xref: /aosp_15_r20/external/tink/cc/internal/ec_util_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 #include "tink/internal/ec_util.h"
17 
18 #include <stdint.h>
19 
20 #include <memory>
21 #include <string>
22 #include <vector>
23 
24 #include "gmock/gmock.h"
25 #include "gtest/gtest.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/escaping.h"
28 #include "absl/strings/str_cat.h"
29 #include "absl/strings/str_split.h"
30 #include "absl/strings/string_view.h"
31 #include "absl/types/span.h"
32 #include "openssl/bn.h"
33 #include "openssl/ec.h"
34 #include "openssl/ecdsa.h"
35 #include "openssl/evp.h"
36 #include "include/rapidjson/document.h"
37 #include "tink/internal/bn_util.h"
38 #include "tink/internal/fips_utils.h"
39 #include "tink/internal/ssl_unique_ptr.h"
40 #include "tink/internal/ssl_util.h"
41 #include "tink/subtle/common_enums.h"
42 #include "tink/subtle/subtle_util.h"
43 #include "tink/subtle/wycheproof_util.h"
44 #include "tink/util/secret_data.h"
45 #include "tink/util/status.h"
46 #include "tink/util/statusor.h"
47 #include "tink/util/test_matchers.h"
48 
49 namespace crypto {
50 namespace tink {
51 namespace internal {
52 namespace {
53 
54 using ::crypto::tink::subtle::EcPointFormat;
55 using ::crypto::tink::subtle::EllipticCurveType;
56 using ::crypto::tink::subtle::WycheproofUtil;
57 using ::crypto::tink::test::IsOk;
58 using ::crypto::tink::test::IsOkAndHolds;
59 using ::crypto::tink::test::StatusIs;
60 using ::testing::AllOf;
61 using ::testing::ElementsAreArray;
62 using ::testing::Eq;
63 using ::testing::Field;
64 using ::testing::HasSubstr;
65 using ::testing::IsEmpty;
66 using ::testing::IsNull;
67 using ::testing::Matcher;
68 using ::testing::Not;
69 using ::testing::SizeIs;
70 using ::testing::TestParamInfo;
71 using ::testing::TestWithParam;
72 using ::testing::ValuesIn;
73 
74 // Use wycheproof test vectors to verify Ed25519 key generation from a seed (the
75 // private key) results in the public/private key.
TEST(EcUtilTest,NewEd25519KeyWithWycheproofTestVectors)76 TEST(EcUtilTest, NewEd25519KeyWithWycheproofTestVectors) {
77   std::unique_ptr<rapidjson::Document> test_vectors =
78       WycheproofUtil::ReadTestVectors("eddsa_test.json");
79   ASSERT_THAT(test_vectors, Not(IsNull()));
80 
81   // For this test we are only interested in Ed25519 keys.
82   for (const auto& test_group : (*test_vectors)["testGroups"].GetArray()) {
83     std::string private_key = WycheproofUtil::GetBytes(test_group["key"]["sk"]);
84     std::string public_key = WycheproofUtil::GetBytes(test_group["key"]["pk"]);
85 
86     util::StatusOr<std::unique_ptr<Ed25519Key>> key =
87         NewEd25519Key(util::SecretDataFromStringView(private_key));
88     ASSERT_THAT(key, IsOk());
89     EXPECT_EQ((*key)->public_key, public_key);
90     EXPECT_EQ((*key)->private_key, private_key);
91   }
92 }
93 
TEST(EcUtilTest,NewEd25519KeyInvalidSeed)94 TEST(EcUtilTest, NewEd25519KeyInvalidSeed) {
95   std::string valid_seed = absl::HexStringToBytes(
96       "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f");
97   // Seed that is too small.
98   for (int i = 0; i < 32; i++) {
99     EXPECT_THAT(
100         NewEd25519Key(util::SecretDataFromStringView(valid_seed.substr(0, i)))
101             .status(),
102         Not(IsOk()))
103         << " with seed of length " << i;
104   }
105   // Seed that is too large.
106   std::string large_seed = absl::StrCat(valid_seed, "a");
107   EXPECT_THAT(
108       NewEd25519Key(util::SecretDataFromStringView(large_seed)).status(),
109       Not(IsOk()))
110       << " with seed of length " << large_seed.size();
111 }
112 
TEST(EcUtilTest,NewEcKeyReturnsWellFormedX25519Key)113 TEST(EcUtilTest, NewEcKeyReturnsWellFormedX25519Key) {
114   util::StatusOr<EcKey> ec_key =
115       NewEcKey(subtle::EllipticCurveType::CURVE25519);
116   ASSERT_THAT(ec_key, IsOk());
117   EXPECT_THAT(
118       *ec_key,
119       AllOf(Field(&EcKey::curve, Eq(subtle::EllipticCurveType::CURVE25519)),
120             Field(&EcKey::pub_x, SizeIs(X25519KeyPubKeySize())),
121             Field(&EcKey::pub_y, IsEmpty()),
122             Field(&EcKey::priv, SizeIs(X25519KeyPrivKeySize()))));
123 }
124 
125 using EcUtilNewEcKeyWithSeed = TestWithParam<subtle::EllipticCurveType>;
126 
127 // Matcher for the equality of two EcKeys.
EqualsEcKey(const EcKey & expected)128 Matcher<EcKey> EqualsEcKey(const EcKey& expected) {
129   return AllOf(Field(&EcKey::priv, Eq(expected.priv)),
130                Field(&EcKey::pub_x, Eq(expected.pub_x)),
131                Field(&EcKey::pub_y, Eq(expected.pub_y)),
132                Field(&EcKey::curve, Eq(expected.curve)));
133 }
134 
TEST_P(EcUtilNewEcKeyWithSeed,KeysFromDifferentSeedAreDifferent)135 TEST_P(EcUtilNewEcKeyWithSeed, KeysFromDifferentSeedAreDifferent) {
136   if (IsFipsModeEnabled()) {
137     GTEST_SKIP() << "Not supported in FIPS-only mode";
138   }
139   if (!IsBoringSsl()) {
140     GTEST_SKIP() << "NewEcKey with seed is not supported with OpenSSL";
141   }
142 
143   util::SecretData seed1 = util::SecretDataFromStringView(
144       absl::HexStringToBytes("000102030405060708090a0b0c0d0e0f"));
145   util::SecretData seed2 = util::SecretDataFromStringView(
146       absl::HexStringToBytes("0f0e0d0c0b0a09080706050403020100"));
147   subtle::EllipticCurveType curve = GetParam();
148 
149   util::StatusOr<EcKey> keypair1 = NewEcKey(curve, seed1);
150   ASSERT_THAT(keypair1, IsOk());
151   util::StatusOr<EcKey> keypair2 = NewEcKey(curve, seed2);
152   ASSERT_THAT(keypair2, IsOk());
153   EXPECT_THAT(*keypair1, Not(EqualsEcKey(*keypair2)));
154 }
155 
TEST_P(EcUtilNewEcKeyWithSeed,SameSeedGivesSameKey)156 TEST_P(EcUtilNewEcKeyWithSeed, SameSeedGivesSameKey) {
157   if (IsFipsModeEnabled()) {
158     GTEST_SKIP() << "Not supported in FIPS-only mode";
159   }
160   if (!IsBoringSsl()) {
161     GTEST_SKIP() << "NewEcKey with seed is not supported with OpenSSL";
162   }
163 
164   util::SecretData seed1 = util::SecretDataFromStringView(
165       absl::HexStringToBytes("000102030405060708090a0b0c0d0e0f"));
166   subtle::EllipticCurveType curve = GetParam();
167 
168   util::StatusOr<EcKey> keypair1 = NewEcKey(curve, seed1);
169   ASSERT_THAT(keypair1, IsOk());
170   util::StatusOr<EcKey> keypair2 = NewEcKey(curve, seed1);
171   ASSERT_THAT(keypair2, IsOk());
172   EXPECT_THAT(*keypair1, EqualsEcKey(*keypair2));
173 }
174 
175 INSTANTIATE_TEST_SUITE_P(EcUtilNewEcKeyWithSeeds, EcUtilNewEcKeyWithSeed,
176                          ValuesIn({subtle::NIST_P256, subtle::NIST_P384,
177                                    subtle::NIST_P521}));
178 
TEST(EcUtilTest,GenerationWithSeedFailsWithWrongCurve)179 TEST(EcUtilTest, GenerationWithSeedFailsWithWrongCurve) {
180   if (IsFipsModeEnabled()) {
181     GTEST_SKIP() << "Not supported in FIPS-only mode";
182   }
183   if (!IsBoringSsl()) {
184     GTEST_SKIP() << "NewEcKey with seed is not supported with OpenSSL";
185   }
186   util::SecretData seed = util::SecretDataFromStringView(
187       absl::HexStringToBytes("000102030405060708090a0b0c0d0e0f"));
188   util::StatusOr<EcKey> keypair =
189       NewEcKey(subtle::EllipticCurveType::CURVE25519, seed);
190   EXPECT_THAT(keypair.status(), StatusIs(absl::StatusCode::kInternal));
191 }
192 
TEST(EcUtilTest,NewEcKeyFromSeedUnimplementedIfOpenSsl)193 TEST(EcUtilTest, NewEcKeyFromSeedUnimplementedIfOpenSsl) {
194   if (IsFipsModeEnabled()) {
195     GTEST_SKIP() << "Not supported in FIPS-only mode";
196   }
197   if (IsBoringSsl()) {
198     GTEST_SKIP()
199         << "OpenSSL-only test; skipping because BoringSSL is being used";
200   }
201   util::SecretData seed = util::SecretDataFromStringView(
202       absl::HexStringToBytes("000102030405060708090a0b0c0d0e0f"));
203   util::StatusOr<EcKey> keypair =
204       NewEcKey(subtle::EllipticCurveType::CURVE25519, seed);
205   EXPECT_THAT(keypair.status(), StatusIs(absl::StatusCode::kUnimplemented));
206 }
207 
TEST(EcUtilTest,NewX25519KeyGeneratesNewKeyEveryTime)208 TEST(EcUtilTest, NewX25519KeyGeneratesNewKeyEveryTime) {
209   util::StatusOr<std::unique_ptr<X25519Key>> keypair1 = NewX25519Key();
210   ASSERT_THAT(keypair1, IsOk());
211   util::StatusOr<std::unique_ptr<X25519Key>> keypair2 = NewX25519Key();
212   ASSERT_THAT(keypair2, IsOk());
213 
214   auto priv_key1 =
215       absl::MakeSpan((*keypair1)->private_key, X25519KeyPrivKeySize());
216   auto priv_key2 =
217       absl::MakeSpan((*keypair2)->private_key, X25519KeyPrivKeySize());
218   auto pub_key1 =
219       absl::MakeSpan((*keypair1)->public_value, X25519KeyPubKeySize());
220   auto pub_key2 =
221       absl::MakeSpan((*keypair2)->public_value, X25519KeyPubKeySize());
222   EXPECT_THAT(priv_key1, Not(ElementsAreArray(priv_key2)));
223   EXPECT_THAT(pub_key1, Not(ElementsAreArray(pub_key2)));
224 }
225 
TEST(EcUtilTest,X25519KeyToEcKeyAndBack)226 TEST(EcUtilTest, X25519KeyToEcKeyAndBack) {
227   util::StatusOr<std::unique_ptr<X25519Key>> x25519_key = NewX25519Key();
228   ASSERT_THAT(x25519_key, IsOk());
229   EcKey ec_key = EcKeyFromX25519Key(x25519_key->get());
230   ASSERT_EQ(ec_key.curve, EllipticCurveType::CURVE25519);
231 
232   util::StatusOr<std::unique_ptr<X25519Key>> roundtrip_key =
233       X25519KeyFromEcKey(ec_key);
234   ASSERT_THAT(roundtrip_key, IsOk());
235   EXPECT_THAT(
236       absl::MakeSpan((*x25519_key)->private_key, X25519KeyPrivKeySize()),
237       ElementsAreArray(absl::MakeSpan((*roundtrip_key)->private_key,
238                                       X25519KeyPrivKeySize())));
239   EXPECT_THAT(
240       absl::MakeSpan((*x25519_key)->public_value, X25519KeyPubKeySize()),
241       ElementsAreArray(absl::MakeSpan((*roundtrip_key)->public_value,
242                                       X25519KeyPubKeySize())));
243 }
244 
TEST(EcUtilTest,X25519KeyFromRandomPrivateKey)245 TEST(EcUtilTest, X25519KeyFromRandomPrivateKey) {
246   util::StatusOr<std::unique_ptr<X25519Key>> x25519_key = NewX25519Key();
247   ASSERT_THAT(x25519_key, IsOk());
248 
249   absl::Span<uint8_t> pkey_span =
250       absl::MakeSpan((*x25519_key)->private_key, X25519KeyPrivKeySize());
251   util::StatusOr<std::unique_ptr<X25519Key>> roundtrip_key =
252       X25519KeyFromPrivateKey({pkey_span.begin(), pkey_span.end()});
253   ASSERT_THAT(roundtrip_key, IsOk());
254   EXPECT_THAT(
255       absl::MakeSpan((*x25519_key)->private_key, X25519KeyPrivKeySize()),
256       ElementsAreArray(absl::MakeSpan((*roundtrip_key)->private_key,
257                                       X25519KeyPrivKeySize())));
258   EXPECT_THAT(
259       absl::MakeSpan((*x25519_key)->public_value, X25519KeyPubKeySize()),
260       ElementsAreArray(absl::MakeSpan((*roundtrip_key)->public_value,
261                                       X25519KeyPubKeySize())));
262 }
263 
264 struct X25519FunctionTestVector {
265   std::string private_key;
266   std::string expected_public_key;
267 };
268 
269 // Returns some X25519 test vectors taken from
270 // https://datatracker.ietf.org/doc/html/rfc7748.
GetX25519FunctionTestVectors()271 std::vector<X25519FunctionTestVector> GetX25519FunctionTestVectors() {
272   return {
273       // https://datatracker.ietf.org/doc/html/rfc7748#section-5.2
274       {
275           /*private_key=*/
276           absl::HexStringToBytes("090000000000000000000000000000000000000000000"
277                                  "0000000000000000000"),
278           /*expected_public_key=*/
279           absl::HexStringToBytes("422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854"
280                                  "b783c60e80311ae3079"),
281       },
282       // https://datatracker.ietf.org/doc/html/rfc7748#section-6.1; Alice
283       {
284           /*private_key=*/
285           absl::HexStringToBytes("77076d0a7318a57d3c16c17251b26645df4c2f87ebc09"
286                                  "92ab177fba51db92c2a"),
287           /*expected_public_key=*/
288           absl::HexStringToBytes("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381"
289                                  "af4eba4a98eaa9b4e6a"),
290       },
291       // https://datatracker.ietf.org/doc/html/rfc7748#section-6.1; Bob
292       {
293           /*private_key=*/
294           absl::HexStringToBytes("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b"
295                                  "6fd1c2f8b27ff88e0eb"),
296           /*expected_public_key=*/
297           absl::HexStringToBytes("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b786"
298                                  "74dadfc7e146f882b4f"),
299       },
300       // Locally made up test vector
301       {
302           /*private_key=*/
303           "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
304           /*expected_public_key=*/
305           absl::HexStringToBytes("4049502db92ca2342c3f92dac5d6de7c85db5df5407a5"
306                                  "b4996ce39f2efb7e827"),
307       },
308   };
309 }
310 
311 using X25519FunctionTest = TestWithParam<X25519FunctionTestVector>;
312 
TEST_P(X25519FunctionTest,ComputeX25519PublicKey)313 TEST_P(X25519FunctionTest, ComputeX25519PublicKey) {
314   X25519FunctionTestVector test_vector = GetParam();
315 
316   util::StatusOr<std::unique_ptr<X25519Key>> key = X25519KeyFromPrivateKey(
317       util::SecretDataFromStringView(test_vector.private_key));
318   ASSERT_THAT(key, IsOk());
319   EXPECT_THAT(absl::MakeSpan((*key)->public_value, X25519KeyPubKeySize()),
320               ElementsAreArray(test_vector.expected_public_key));
321 }
322 
323 INSTANTIATE_TEST_SUITE_P(X25519SharedSecretTests, X25519FunctionTest,
324                          ValuesIn(GetX25519FunctionTestVectors()));
325 
326 struct X25519SharedSecretTestVector {
327   std::string private_key;
328   std::string public_key;
329   std::string expected_shared_secret;
330 };
331 
332 // Returns some X25519 test vectors taken from
333 // https://datatracker.ietf.org/doc/html/rfc7748#section-5.2.
GetX25519SharedSecretTestVectors()334 std::vector<X25519SharedSecretTestVector> GetX25519SharedSecretTestVectors() {
335   return {
336       {
337           /*private_key=*/
338           absl::HexStringToBytes("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5"
339                                  "a18506a2244ba449ac4"),
340           /*public_key=*/
341           absl::HexStringToBytes("e6db6867583030db3594c1a424b15f7c726624ec26b33"
342                                  "53b10a903a6d0ab1c4c"),
343           /*expected_shared_secret=*/
344           absl::HexStringToBytes("c3da55379de9c6908e94ea4df28d084f32eccf03491c7"
345                                  "1f754b4075577a28552"),
346       },
347       {
348           /*private_key=*/
349           absl::HexStringToBytes("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea0"
350                                  "1d42ca4169e7918ba0d"),
351           /*public_key=*/
352           absl::HexStringToBytes("e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03"
353                                  "c3efc4cd549c715a493"),
354           /*expected_shared_secret=*/
355           absl::HexStringToBytes("95cbde9476e8907d7aade45cb4b873f88b595a68799fa"
356                                  "152e6f8f7647aac7957"),
357       },
358   };
359 }
360 
361 using X25519SharedSecretTest = TestWithParam<X25519SharedSecretTestVector>;
362 
TEST_P(X25519SharedSecretTest,ComputeX25519SharedSecret)363 TEST_P(X25519SharedSecretTest, ComputeX25519SharedSecret) {
364   X25519SharedSecretTestVector test_vector = GetParam();
365 
366   // Generate the EVP_PKEYs.
367   internal::SslUniquePtr<EVP_PKEY> ssl_priv_key(EVP_PKEY_new_raw_private_key(
368       /*type=*/EVP_PKEY_X25519, /*unused=*/nullptr,
369       /*in=*/reinterpret_cast<const uint8_t*>(test_vector.private_key.data()),
370       /*len=*/Ed25519KeyPrivKeySize()));
371   ASSERT_THAT(ssl_priv_key, Not(IsNull()));
372   internal::SslUniquePtr<EVP_PKEY> ssl_pub_key(EVP_PKEY_new_raw_public_key(
373       /*type=*/EVP_PKEY_X25519, /*unused=*/nullptr,
374       /*in=*/reinterpret_cast<const uint8_t*>(test_vector.public_key.data()),
375       /*len=*/Ed25519KeyPrivKeySize()));
376   ASSERT_THAT(ssl_pub_key, Not(IsNull()));
377 
378   EXPECT_THAT(ComputeX25519SharedSecret(ssl_priv_key.get(), ssl_pub_key.get()),
379               IsOkAndHolds(util::SecretDataFromStringView(
380                   test_vector.expected_shared_secret)));
381 }
382 
383 INSTANTIATE_TEST_SUITE_P(X25519SharedSecretTests, X25519SharedSecretTest,
384                          ValuesIn(GetX25519SharedSecretTestVectors()));
385 
TEST(EcUtilTest,ComputeX25519SharedSecretInvalidKeyType)386 TEST(EcUtilTest, ComputeX25519SharedSecretInvalidKeyType) {
387   // Key pair of an invalid type EVP_PKEY_ED25519.
388   SslUniquePtr<EVP_PKEY_CTX> pctx(EVP_PKEY_CTX_new_id(EVP_PKEY_ED25519,
389                                                       /*e=*/nullptr));
390   ASSERT_THAT(pctx, Not(IsNull()));
391   ASSERT_EQ(EVP_PKEY_keygen_init(pctx.get()), 1);
392   EVP_PKEY* invalid_type_key_ptr = nullptr;
393   ASSERT_EQ(EVP_PKEY_keygen(pctx.get(), &invalid_type_key_ptr), 1);
394   SslUniquePtr<EVP_PKEY> invalid_type_key(invalid_type_key_ptr);
395 
396   // Private and public key with valid type.
397   internal::SslUniquePtr<EVP_PKEY> ssl_priv_key(EVP_PKEY_new_raw_private_key(
398       /*type=*/EVP_PKEY_X25519, /*unused=*/nullptr,
399       /*in=*/
400       reinterpret_cast<const uint8_t*>(
401           absl::HexStringToBytes("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5"
402                                  "a18506a2244ba449ac4")
403               .data()),
404       /*len=*/Ed25519KeyPrivKeySize()));
405   ASSERT_THAT(ssl_priv_key, Not(IsNull()));
406   internal::SslUniquePtr<EVP_PKEY> ssl_pub_key(EVP_PKEY_new_raw_public_key(
407       /*type=*/EVP_PKEY_X25519, /*unused=*/nullptr,
408       /*in=*/
409       reinterpret_cast<const uint8_t*>(
410           absl::HexStringToBytes("e6db6867583030db3594c1a424b15f7c726624ec26b33"
411                                  "53b10a903a6d0ab1c4c")
412               .data()),
413       /*len=*/Ed25519KeyPubKeySize()));
414   ASSERT_THAT(ssl_pub_key, Not(IsNull()));
415 
416   EXPECT_THAT(
417       ComputeX25519SharedSecret(ssl_priv_key.get(), invalid_type_key.get())
418           .status(),
419       Not(IsOk()));
420   EXPECT_THAT(
421       ComputeX25519SharedSecret(invalid_type_key.get(), ssl_pub_key.get())
422           .status(),
423       Not(IsOk()));
424 }
425 
426 struct EncodingTestVector {
427   EcPointFormat format;
428   std::string x_hex;
429   std::string y_hex;
430   std::string encoded_hex;
431   EllipticCurveType curve;
432 };
433 
GetEncodingTestVectors()434 std::vector<EncodingTestVector> GetEncodingTestVectors() {
435   return {
436       {EcPointFormat::UNCOMPRESSED,
437        "00093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918ec6"
438        "619b9931955d5a89d4d74adf1046bb362192f2ef6bd3e3d2d04dd1f87054a",
439        "00aa3fb2448335f694e3cda4ae0cc71b1b2f2a206fa802d7262f19983c44674fe15327a"
440        "caac1fa40424c395a6556cb8167312527fae5865ecffc14bbdc17da78cdcf",
441        "0400093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918e"
442        "c6619b9931955d5a89d4d74adf1046bb362192f2ef6bd3e3d2d04dd1f87054a00aa3fb2"
443        "448335f694e3cda4ae0cc71b1b2f2a206fa802d7262f19983c44674fe15327acaac1fa4"
444        "0424c395a6556cb8167312527fae5865ecffc14bbdc17da78cdcf",
445        EllipticCurveType::NIST_P521},
446       {EcPointFormat::DO_NOT_USE_CRUNCHY_UNCOMPRESSED,
447        "00093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918ec6"
448        "619b9931955d5a89d4d74adf1046bb362192f2ef6bd3e3d2d04dd1f87054a",
449        "00aa3fb2448335f694e3cda4ae0cc71b1b2f2a206fa802d7262f19983c44674fe15327a"
450        "caac1fa40424c395a6556cb8167312527fae5865ecffc14bbdc17da78cdcf",
451        "00093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918ec6"
452        "619b9931955d5a89d4d74adf1046bb362192f2ef6bd3e3d2d04dd1f87054a00aa3fb244"
453        "8335f694e3cda4ae0cc71b1b2f2a206fa802d7262f19983c44674fe15327acaac1fa404"
454        "24c395a6556cb8167312527fae5865ecffc14bbdc17da78cdcf",
455        EllipticCurveType::NIST_P521},
456       {EcPointFormat::COMPRESSED,
457        "00093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918ec6"
458        "619b9931955d5a89d4d74adf1046bb362192f2ef6bd3e3d2d04dd1f87054a",
459        "00aa3fb2448335f694e3cda4ae0cc71b1b2f2a206fa802d7262f19983c44674fe15327a"
460        "caac1fa40424c395a6556cb8167312527fae5865ecffc14bbdc17da78cdcf",
461        "0300093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918e"
462        "c6619b9931955d5a89d4d74adf1046bb362192f2ef6bd3e3d2d04dd1f87054a",
463        EllipticCurveType::NIST_P521}};
464 }
465 
466 using EcUtilEncodeDecodePointTest = TestWithParam<EncodingTestVector>;
467 
TEST_P(EcUtilEncodeDecodePointTest,EcPointEncode)468 TEST_P(EcUtilEncodeDecodePointTest, EcPointEncode) {
469   const EncodingTestVector& test = GetParam();
470   util::StatusOr<SslUniquePtr<EC_POINT>> point =
471       GetEcPoint(test.curve, absl::HexStringToBytes(test.x_hex),
472                  absl::HexStringToBytes(test.y_hex));
473   ASSERT_THAT(point, IsOk());
474 
475   util::StatusOr<std::string> encoded_point =
476       EcPointEncode(test.curve, test.format, point->get());
477   ASSERT_THAT(encoded_point, IsOk());
478   EXPECT_EQ(test.encoded_hex, absl::BytesToHexString(*encoded_point));
479 }
480 
TEST_P(EcUtilEncodeDecodePointTest,EcPointDecode)481 TEST_P(EcUtilEncodeDecodePointTest, EcPointDecode) {
482   const EncodingTestVector& test = GetParam();
483   // Get the test point and its encoded version.
484   util::StatusOr<SslUniquePtr<EC_POINT>> point =
485       GetEcPoint(test.curve, absl::HexStringToBytes(test.x_hex),
486                  absl::HexStringToBytes(test.y_hex));
487   ASSERT_THAT(point, IsOk());
488   std::string encoded_str = absl::HexStringToBytes(test.encoded_hex);
489 
490   util::StatusOr<SslUniquePtr<EC_GROUP>> ec_group =
491       EcGroupFromCurveType(test.curve);
492   util::StatusOr<SslUniquePtr<EC_POINT>> ec_point =
493       EcPointDecode(test.curve, test.format, encoded_str);
494   ASSERT_THAT(ec_point, IsOk());
495   EXPECT_EQ(EC_POINT_cmp(ec_group->get(), point->get(), ec_point->get(),
496                          /*ctx=*/nullptr),
497             0);
498 
499   // Modifying the 1st byte decoding fails.
500   encoded_str[0] = '0';
501   util::StatusOr<SslUniquePtr<EC_POINT>> ec_point2 =
502       EcPointDecode(test.curve, test.format, encoded_str);
503   EXPECT_THAT(ec_point2, Not(IsOk()));
504   if (test.format == EcPointFormat::UNCOMPRESSED ||
505       test.format == EcPointFormat::COMPRESSED) {
506     EXPECT_THAT(std::string(ec_point2.status().message()),
507                 HasSubstr("point should start with"));
508   }
509 }
510 
511 INSTANTIATE_TEST_SUITE_P(
512     EcUtilEncodeDecodePointTests, EcUtilEncodeDecodePointTest,
513     ValuesIn(GetEncodingTestVectors()),
__anon457384850202(const TestParamInfo<EcUtilEncodeDecodePointTest::ParamType>& info) 514     [](const TestParamInfo<EcUtilEncodeDecodePointTest::ParamType>& info) {
515       switch (info.param.format) {
516         case EcPointFormat::UNCOMPRESSED:
517           return "Uncompressed";
518         case EcPointFormat::DO_NOT_USE_CRUNCHY_UNCOMPRESSED:
519           return "DoNotUseCrunchyUncompressed";
520         case EcPointFormat::COMPRESSED:
521           return "Compressed";
522         default:
523           return "Unknown";
524       }
525     });
526 
TEST(EcUtilTest,EcFieldSizeInBytes)527 TEST(EcUtilTest, EcFieldSizeInBytes) {
528   EXPECT_THAT(EcFieldSizeInBytes(EllipticCurveType::NIST_P256),
529               IsOkAndHolds(256 / 8));
530   EXPECT_THAT(EcFieldSizeInBytes(EllipticCurveType::NIST_P384),
531               IsOkAndHolds(384 / 8));
532   EXPECT_THAT(EcFieldSizeInBytes(EllipticCurveType::NIST_P521),
533               IsOkAndHolds((521 + 7) / 8));
534   EXPECT_THAT(EcFieldSizeInBytes(EllipticCurveType::CURVE25519),
535               IsOkAndHolds(256 / 8));
536   EXPECT_THAT(EcFieldSizeInBytes(EllipticCurveType::UNKNOWN_CURVE).status(),
537               Not(IsOk()));
538 }
539 
TEST(EcUtilTest,EcPointEncodingSizeInBytes)540 TEST(EcUtilTest, EcPointEncodingSizeInBytes) {
541   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::NIST_P256,
542                                          EcPointFormat::UNCOMPRESSED),
543               IsOkAndHolds(2 * (256 / 8) + 1));
544   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::NIST_P256,
545                                          EcPointFormat::COMPRESSED),
546               IsOkAndHolds(256 / 8 + 1));
547   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::NIST_P384,
548                                          EcPointFormat::UNCOMPRESSED),
549               IsOkAndHolds(2 * (384 / 8) + 1));
550   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::NIST_P384,
551                                          EcPointFormat::COMPRESSED),
552               IsOkAndHolds(384 / 8 + 1));
553   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::NIST_P521,
554                                          EcPointFormat::UNCOMPRESSED),
555               IsOkAndHolds(2 * ((521 + 7) / 8) + 1));
556   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::NIST_P521,
557                                          EcPointFormat::COMPRESSED),
558               IsOkAndHolds((521 + 7) / 8 + 1));
559   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::CURVE25519,
560                                          EcPointFormat::COMPRESSED),
561               IsOkAndHolds(256 / 8));
562 
563   EXPECT_THAT(EcPointEncodingSizeInBytes(EllipticCurveType::NIST_P256,
564                                          EcPointFormat::UNKNOWN_FORMAT)
565                   .status(),
566               Not(IsOk()));
567 }
568 
TEST(EcUtilTest,CurveTypeFromEcGroupSuccess)569 TEST(EcUtilTest, CurveTypeFromEcGroupSuccess) {
570   EC_GROUP* p256_group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
571   EC_GROUP* p384_group = EC_GROUP_new_by_curve_name(NID_secp384r1);
572   EC_GROUP* p521_group = EC_GROUP_new_by_curve_name(NID_secp521r1);
573 
574   util::StatusOr<EllipticCurveType> p256_curve =
575       CurveTypeFromEcGroup(p256_group);
576   util::StatusOr<EllipticCurveType> p384_curve =
577       CurveTypeFromEcGroup(p384_group);
578   util::StatusOr<EllipticCurveType> p521_curve =
579       CurveTypeFromEcGroup(p521_group);
580 
581   ASSERT_THAT(p256_curve, IsOkAndHolds(EllipticCurveType::NIST_P256));
582   ASSERT_THAT(p384_curve, IsOkAndHolds(EllipticCurveType::NIST_P384));
583   ASSERT_THAT(p521_curve, IsOkAndHolds(EllipticCurveType::NIST_P521));
584 }
585 
TEST(EcUtilTest,CurveTypeFromEcGroupUnimplemented)586 TEST(EcUtilTest, CurveTypeFromEcGroupUnimplemented) {
587   EXPECT_THAT(
588       CurveTypeFromEcGroup(EC_GROUP_new_by_curve_name(NID_secp224r1)).status(),
589       StatusIs(absl::StatusCode::kUnimplemented));
590 }
591 
TEST(EcUtilTest,EcGroupFromCurveTypeSuccess)592 TEST(EcUtilTest, EcGroupFromCurveTypeSuccess) {
593   util::StatusOr<SslUniquePtr<EC_GROUP>> p256_curve =
594       EcGroupFromCurveType(EllipticCurveType::NIST_P256);
595   util::StatusOr<SslUniquePtr<EC_GROUP>> p384_curve =
596       EcGroupFromCurveType(EllipticCurveType::NIST_P384);
597   util::StatusOr<SslUniquePtr<EC_GROUP>> p521_curve =
598       EcGroupFromCurveType(EllipticCurveType::NIST_P521);
599   ASSERT_THAT(p256_curve, IsOk());
600   ASSERT_THAT(p384_curve, IsOk());
601   ASSERT_THAT(p521_curve, IsOk());
602 
603   SslUniquePtr<EC_GROUP> ssl_p256_group(
604       EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
605   SslUniquePtr<EC_GROUP> ssl_p384_group(
606       EC_GROUP_new_by_curve_name(NID_secp384r1));
607   SslUniquePtr<EC_GROUP> ssl_p521_group(
608       EC_GROUP_new_by_curve_name(NID_secp521r1));
609 
610   EXPECT_EQ(
611       EC_GROUP_cmp(p256_curve->get(), ssl_p256_group.get(), /*ctx=*/nullptr),
612       0);
613   EXPECT_EQ(
614       EC_GROUP_cmp(p384_curve->get(), ssl_p384_group.get(), /*ctx=*/nullptr),
615       0);
616   EXPECT_EQ(
617       EC_GROUP_cmp(p521_curve->get(), ssl_p521_group.get(), /*ctx=*/nullptr),
618       0);
619 }
620 
TEST(EcUtilTest,EcGroupFromCurveTypeUnimplemented)621 TEST(EcUtilTest, EcGroupFromCurveTypeUnimplemented) {
622   EXPECT_THAT(EcGroupFromCurveType(EllipticCurveType::UNKNOWN_CURVE).status(),
623               StatusIs(absl::StatusCode::kUnimplemented));
624 }
625 
TEST(EcUtilTest,GetEcPointReturnsAValidPoint)626 TEST(EcUtilTest, GetEcPointReturnsAValidPoint) {
627   SslUniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(NID_secp521r1));
628   const unsigned int kCurveSizeInBytes =
629       (EC_GROUP_get_degree(group.get()) + 7) / 8;
630 
631   constexpr absl::string_view kXCoordinateHex =
632       "00093057fb862f2ad2e82e581baeb3324e7b32946f2ba845a9beeed87d6995f54918ec6"
633       "619b9931955d5a89d4d74adf1046bb362192f2ef6bd3e3d2d04dd1f87054a";
634   constexpr absl::string_view kYCoordinateHex =
635       "00aa3fb2448335f694e3cda4ae0cc71b1b2f2a206fa802d7262f19983c44674fe15327a"
636       "caac1fa40424c395a6556cb8167312527fae5865ecffc14bbdc17da78cdcf";
637   util::StatusOr<SslUniquePtr<EC_POINT>> point = GetEcPoint(
638       EllipticCurveType::NIST_P521, absl::HexStringToBytes(kXCoordinateHex),
639       absl::HexStringToBytes(kYCoordinateHex));
640   ASSERT_THAT(point, IsOk());
641 
642   // We check that we can decode this point and the result is the same as the
643   // original coordinates.
644   std::string xy;
645   subtle::ResizeStringUninitialized(&xy, 2 * kCurveSizeInBytes);
646   SslUniquePtr<BIGNUM> x(BN_new());
647   SslUniquePtr<BIGNUM> y(BN_new());
648   ASSERT_EQ(EC_POINT_get_affine_coordinates(group.get(), point->get(), x.get(),
649                                             y.get(), /*ctx=*/nullptr),
650             1);
651   ASSERT_THAT(
652       BignumToBinaryPadded(absl::MakeSpan(&xy[0], kCurveSizeInBytes), x.get()),
653       IsOk());
654   ASSERT_THAT(
655       BignumToBinaryPadded(
656           absl::MakeSpan(&xy[kCurveSizeInBytes], kCurveSizeInBytes), y.get()),
657       IsOk());
658   EXPECT_EQ(xy, absl::StrCat(absl::HexStringToBytes(kXCoordinateHex),
659                              absl::HexStringToBytes(kYCoordinateHex)));
660 }
661 
TEST(EcUtilTest,EcSignatureIeeeToDer)662 TEST(EcUtilTest, EcSignatureIeeeToDer) {
663   std::unique_ptr<rapidjson::Document> test_vectors =
664       WycheproofUtil::ReadTestVectors("ecdsa_webcrypto_test.json");
665   ASSERT_THAT(test_vectors, Not(IsNull()));
666   for (const auto& test_group : (*test_vectors)["testGroups"].GetArray()) {
667     EllipticCurveType curve =
668         WycheproofUtil::GetEllipticCurveType(test_group["key"]["curve"]);
669     if (curve == EllipticCurveType::UNKNOWN_CURVE) {
670       continue;
671     }
672     util::StatusOr<SslUniquePtr<EC_GROUP>> ec_group =
673         EcGroupFromCurveType(curve);
674     ASSERT_THAT(ec_group, IsOk());
675     // Read all the valid signatures.
676     for (const auto& test : test_group["tests"].GetArray()) {
677       std::string result = test["result"].GetString();
678       if (result != "valid") {
679         continue;
680       }
681       std::string sig = WycheproofUtil::GetBytes(test["sig"]);
682       util::StatusOr<std::string> der_encoded =
683           EcSignatureIeeeToDer(ec_group->get(), sig);
684       ASSERT_THAT(der_encoded, IsOk());
685 
686       // Make sure we can reconstruct the IEEE format: [ s || r ].
687       const uint8_t* der_sig_data_ptr =
688           reinterpret_cast<const uint8_t*>(der_encoded->data());
689       SslUniquePtr<ECDSA_SIG> ecdsa_sig(d2i_ECDSA_SIG(
690           /*out=*/nullptr, &der_sig_data_ptr, der_encoded->size()));
691       ASSERT_THAT(ecdsa_sig, Not(IsNull()));
692       // Owned by OpenSSL/BoringSSL.
693       const BIGNUM* r;
694       const BIGNUM* s;
695       ECDSA_SIG_get0(ecdsa_sig.get(), &r, &s);
696       ASSERT_THAT(r, Not(IsNull()));
697       ASSERT_THAT(s, Not(IsNull()));
698 
699       util::StatusOr<int32_t> field_size = EcFieldSizeInBytes(curve);
700       ASSERT_THAT(field_size, IsOk());
701       util::StatusOr<std::string> r_str = BignumToString(r, *field_size);
702       ASSERT_THAT(r_str, IsOk());
703       util::StatusOr<std::string> s_str = BignumToString(s, *field_size);
704       ASSERT_THAT(s_str, IsOk());
705       EXPECT_EQ(absl::StrCat(*r_str, *s_str), sig);
706     }
707   }
708 }
709 
710 // ECDH test vector.
711 struct EcdhWycheproofTestVector {
712   std::string testcase_name;
713   EllipticCurveType curve;
714   std::string id;
715   std::string comment;
716   std::string pub_bytes;
717   std::string priv_bytes;
718   std::string expected_shared_bytes;
719   std::string result;
720   EcPointFormat format;
721 };
722 
723 // Utility function to look for a `value` inside an array of flags `flags`.
HasFlag(const rapidjson::Value & flags,absl::string_view value)724 bool HasFlag(const rapidjson::Value& flags, absl::string_view value) {
725   if (!flags.IsArray()) {
726     return false;
727   }
728   for (const rapidjson::Value& flag : flags.GetArray()) {
729     if (std::string(flag.GetString()) == value) {
730       return true;
731     }
732   }
733   return false;
734 }
735 
736 // Reads Wycheproof's ECDH test vectors from the given file `file_name`.
ReadEcdhWycheproofTestVectors(absl::string_view file_name)737 std::vector<EcdhWycheproofTestVector> ReadEcdhWycheproofTestVectors(
738     absl::string_view file_name) {
739   std::unique_ptr<rapidjson::Document> root =
740       WycheproofUtil::ReadTestVectors(std::string(file_name));
741   std::vector<EcdhWycheproofTestVector> test_vectors;
742   for (const rapidjson::Value& test_group : (*root)["testGroups"].GetArray()) {
743     // Tink only supports secp256r1, secp384r1 or secp521r1.
744     EllipticCurveType curve =
745         WycheproofUtil::GetEllipticCurveType(test_group["curve"]);
746     if (curve == EllipticCurveType::UNKNOWN_CURVE) {
747       continue;
748     }
749 
750     for (const rapidjson::Value& test : test_group["tests"].GetArray()) {
751       // Wycheproof's ECDH public key uses ASN encoding while Tink uses X9.62
752       // format point encoding. For the purpose of testing, we note the
753       // followings:
754       //  + The prefix of ASN encoding contains curve name, so we can skip test
755       //  vector with "UnnamedCurve".
756       //  + The suffix of ASN encoding is X9.62 format point encoding.
757       // TODO(quannguyen): Use X9.62 test vectors once it's available.
758       if (HasFlag(test["flags"], /*value=*/"UnnamedCurve")) {
759         continue;
760       }
761       // Get the format from "flags".
762       EcPointFormat format = EcPointFormat::UNCOMPRESSED;
763       if (HasFlag(test["flags"], /*value=*/"CompressedPoint")) {
764         format = EcPointFormat::COMPRESSED;
765       }
766       // Testcase name is of the form: <file_name_without_extension>_tcid<tcid>.
767       std::vector<std::string> file_name_tokens =
768           absl::StrSplit(file_name, '.');
769       test_vectors.push_back({
770           absl::StrCat(file_name_tokens[0], "_tcid", test["tcId"].GetInt()),
771           curve,
772           absl::StrCat(test["tcId"].GetInt()),
773           test["comment"].GetString(),
774           WycheproofUtil::GetBytes(test["public"]),
775           WycheproofUtil::GetBytes(test["private"]),
776           WycheproofUtil::GetBytes(test["shared"]),
777           test["result"].GetString(),
778           format,
779       });
780     }
781   }
782   return test_vectors;
783 }
784 
785 using EcUtilComputeEcdhSharedSecretTest =
786     TestWithParam<EcdhWycheproofTestVector>;
787 
TEST_P(EcUtilComputeEcdhSharedSecretTest,ComputeEcdhSharedSecretWycheproof)788 TEST_P(EcUtilComputeEcdhSharedSecretTest, ComputeEcdhSharedSecretWycheproof) {
789   EcdhWycheproofTestVector params = GetParam();
790 
791   util::StatusOr<int32_t> point_size =
792       internal::EcPointEncodingSizeInBytes(params.curve, params.format);
793   ASSERT_THAT(point_size, IsOk());
794   if (*point_size > params.pub_bytes.size()) {
795     GTEST_SKIP();
796   }
797 
798   std::string pub_bytes = params.pub_bytes.substr(
799       params.pub_bytes.size() - *point_size, *point_size);
800 
801   util::StatusOr<SslUniquePtr<EC_POINT>> pub_key =
802       EcPointDecode(params.curve, params.format, pub_bytes);
803   if (!pub_key.ok()) {
804     // Make sure we didn't fail decoding a valid point, then we can terminate
805     // testing;
806     ASSERT_NE(params.result, "valid");
807     return;
808   }
809 
810   util::StatusOr<SslUniquePtr<BIGNUM>> priv_key =
811       StringToBignum(params.priv_bytes);
812   ASSERT_THAT(priv_key, IsOk());
813 
814   util::StatusOr<util::SecretData> shared_secret =
815       ComputeEcdhSharedSecret(params.curve, priv_key->get(), pub_key->get());
816 
817   if (params.result == "invalid") {
818     EXPECT_THAT(shared_secret, Not(IsOk()));
819   } else {
820     EXPECT_THAT(shared_secret, IsOkAndHolds(util::SecretDataFromStringView(
821                                    params.expected_shared_bytes)));
822   }
823 }
824 
GetEcUtilComputeEcdhSharedSecretParams()825 std::vector<EcdhWycheproofTestVector> GetEcUtilComputeEcdhSharedSecretParams() {
826   std::vector<EcdhWycheproofTestVector> test_vectors =
827       ReadEcdhWycheproofTestVectors(
828           /*file_name=*/"ecdh_secp256r1_test.json");
829   std::vector<EcdhWycheproofTestVector> others = ReadEcdhWycheproofTestVectors(
830       /*file_name=*/"ecdh_secp384r1_test.json");
831   test_vectors.insert(test_vectors.end(), others.begin(), others.end());
832   others = ReadEcdhWycheproofTestVectors(
833       /*file_name=*/"ecdh_secp521r1_test.json");
834   test_vectors.insert(test_vectors.end(), others.begin(), others.end());
835   others = ReadEcdhWycheproofTestVectors(
836       /*file_name=*/"ecdh_test.json");
837   test_vectors.insert(test_vectors.end(), others.begin(), others.end());
838   return test_vectors;
839 }
840 
841 INSTANTIATE_TEST_SUITE_P(
842     EcUtilComputeEcdhSharedSecretTests, EcUtilComputeEcdhSharedSecretTest,
843     ValuesIn(GetEcUtilComputeEcdhSharedSecretParams()),
844     [](const TestParamInfo<EcUtilComputeEcdhSharedSecretTest::ParamType>&
__anon457384850302(const TestParamInfo<EcUtilComputeEcdhSharedSecretTest::ParamType>& info) 845            info) { return info.param.testcase_name; });
846 
847 }  // namespace
848 }  // namespace internal
849 }  // namespace tink
850 }  // namespace crypto
851