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