xref: /aosp_15_r20/external/tink/cc/signature/internal/ecdsa_raw_sign_boringssl_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2017 Google Inc.
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 
17 #include "tink/signature/internal/ecdsa_raw_sign_boringssl.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 
23 #include "gtest/gtest.h"
24 #include "absl/status/status.h"
25 #include "tink/internal/ec_util.h"
26 #include "tink/internal/fips_utils.h"
27 #include "tink/public_key_sign.h"
28 #include "tink/public_key_verify.h"
29 #include "tink/subtle/common_enums.h"
30 #include "tink/subtle/ecdsa_verify_boringssl.h"
31 #include "tink/subtle/subtle_util_boringssl.h"
32 #include "tink/util/status.h"
33 #include "tink/util/statusor.h"
34 #include "tink/util/test_matchers.h"
35 
36 namespace crypto {
37 namespace tink {
38 namespace internal {
39 namespace {
40 
41 using ::crypto::tink::test::IsOk;
42 using ::crypto::tink::test::IsOkAndHolds;
43 using ::crypto::tink::test::StatusIs;
44 using ::testing::Eq;
45 using ::testing::Not;
46 using ::testing::SizeIs;
47 
ComputeDigest(subtle::HashType hash_type,absl::string_view data)48 util::StatusOr<std::string> ComputeDigest(subtle::HashType hash_type,
49                                           absl::string_view data) {
50   util::StatusOr<const EVP_MD*> hash = internal::EvpHashFromHashType(hash_type);
51   if (!hash.ok()) return hash.status();
52 
53   unsigned int digest_size;
54   uint8_t digest[EVP_MAX_MD_SIZE];
55   if (1 != EVP_Digest(data.data(), data.size(), digest, &digest_size, *hash,
56                       nullptr)) {
57     return util::Status(absl::StatusCode::kInternal,
58                         "Could not compute digest.");
59   }
60 
61   return std::string(reinterpret_cast<const char*>(digest), digest_size);
62 }
63 
TEST(EcdsaRawSignBoringSslTest,VerifySignature)64 TEST(EcdsaRawSignBoringSslTest, VerifySignature) {
65   if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
66     GTEST_SKIP()
67         << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
68   }
69   subtle::EcdsaSignatureEncoding encodings[2] = {
70       subtle::EcdsaSignatureEncoding::DER,
71       subtle::EcdsaSignatureEncoding::IEEE_P1363};
72   for (subtle::EcdsaSignatureEncoding encoding : encodings) {
73     util::StatusOr<EcKey> ec_key = subtle::SubtleUtilBoringSSL::GetNewEcKey(
74         subtle::EllipticCurveType::NIST_P256);
75     ASSERT_THAT(ec_key, IsOk());
76 
77     util::StatusOr<std::unique_ptr<EcdsaRawSignBoringSsl>> signer =
78         EcdsaRawSignBoringSsl::New(*ec_key, encoding);
79     ASSERT_THAT(signer, IsOk());
80 
81     util::StatusOr<std::unique_ptr<subtle::EcdsaVerifyBoringSsl>> verifier =
82         subtle::EcdsaVerifyBoringSsl::New(*ec_key, subtle::HashType::SHA256,
83                                           encoding);
84     ASSERT_THAT(verifier, IsOk());
85 
86     std::string message = "some data to be signed";
87     util::StatusOr<std::string> message_digest =
88         ComputeDigest(subtle::HashType::SHA256, message);
89     ASSERT_THAT(message_digest, IsOk());
90     util::StatusOr<std::string> signature = (*signer)->Sign(*message_digest);
91     ASSERT_THAT(signature, IsOkAndHolds(Not(Eq(message))));
92     EXPECT_THAT((*verifier)->Verify(*signature, message), IsOk());
93   }
94 }
95 
TEST(EcdsaRawSignBoringSslTest,VerifySignatureWithEmptyMessage)96 TEST(EcdsaRawSignBoringSslTest, VerifySignatureWithEmptyMessage) {
97   if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
98     GTEST_SKIP()
99         << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
100   }
101   subtle::EcdsaSignatureEncoding encodings[2] = {
102       subtle::EcdsaSignatureEncoding::DER,
103       subtle::EcdsaSignatureEncoding::IEEE_P1363};
104   for (subtle::EcdsaSignatureEncoding encoding : encodings) {
105     util::StatusOr<EcKey> ec_key = subtle::SubtleUtilBoringSSL::GetNewEcKey(
106         subtle::EllipticCurveType::NIST_P256);
107     ASSERT_THAT(ec_key, IsOk());
108 
109     util::StatusOr<std::unique_ptr<EcdsaRawSignBoringSsl>> signer =
110         EcdsaRawSignBoringSsl::New(*ec_key, encoding);
111     ASSERT_THAT(signer, IsOk());
112 
113     util::StatusOr<std::unique_ptr<subtle::EcdsaVerifyBoringSsl>> verifier =
114         subtle::EcdsaVerifyBoringSsl::New(*ec_key, subtle::HashType::SHA256,
115                                           encoding);
116     ASSERT_THAT(verifier, IsOk());
117 
118     // Message is a null string_view.
119     const absl::string_view empty_message;
120     util::StatusOr<std::string> empty_message_digest =
121         ComputeDigest(subtle::HashType::SHA256, empty_message);
122     ASSERT_THAT(empty_message_digest, IsOk());
123     util::StatusOr<std::string> empty_msg_signature =
124         (*signer)->Sign(*empty_message_digest);
125     ASSERT_THAT(empty_msg_signature, IsOkAndHolds(Not(Eq(empty_message))));
126     EXPECT_THAT((*verifier)->Verify(*empty_msg_signature, empty_message),
127                 IsOk());
128   }
129 }
130 
TEST(EcdsaRawSignBoringSslTest,VerifyFailsWithInvalidMessageOrSignature)131 TEST(EcdsaRawSignBoringSslTest, VerifyFailsWithInvalidMessageOrSignature) {
132   if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
133     GTEST_SKIP()
134         << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
135   }
136   subtle::EcdsaSignatureEncoding encodings[2] = {
137       subtle::EcdsaSignatureEncoding::DER,
138       subtle::EcdsaSignatureEncoding::IEEE_P1363};
139   for (subtle::EcdsaSignatureEncoding encoding : encodings) {
140     util::StatusOr<EcKey> ec_key = subtle::SubtleUtilBoringSSL::GetNewEcKey(
141         subtle::EllipticCurveType::NIST_P256);
142     ASSERT_THAT(ec_key, IsOk());
143 
144     util::StatusOr<std::unique_ptr<EcdsaRawSignBoringSsl>> signer =
145         EcdsaRawSignBoringSsl::New(*ec_key, encoding);
146     ASSERT_THAT(signer, IsOk());
147 
148     util::StatusOr<std::unique_ptr<subtle::EcdsaVerifyBoringSsl>> verifier =
149         subtle::EcdsaVerifyBoringSsl::New(*ec_key, subtle::HashType::SHA256,
150                                           encoding);
151     ASSERT_THAT(verifier, IsOk());
152 
153     std::string message = "some data to be signed";
154     util::StatusOr<std::string> message_digest =
155         ComputeDigest(subtle::HashType::SHA256, message);
156     ASSERT_THAT(message_digest, IsOk());
157     util::StatusOr<std::string> signature = (*signer)->Sign(*message_digest);
158     ASSERT_THAT(signature, IsOkAndHolds(Not(Eq(message))));
159     EXPECT_THAT((*verifier)->Verify(*signature, message), IsOk());
160 
161     EXPECT_THAT((*verifier)->Verify("some bad signature", message),
162                 Not(IsOk()));
163     EXPECT_THAT((*verifier)->Verify(*signature, "some bad message"),
164                 Not(IsOk()));
165   }
166 }
167 
TEST(EcdsaRawSignBoringSslTest,VerifyFailsWhenEncodingDoesNotMatch)168 TEST(EcdsaRawSignBoringSslTest, VerifyFailsWhenEncodingDoesNotMatch) {
169   if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
170     GTEST_SKIP()
171         << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
172   }
173   subtle::EcdsaSignatureEncoding encodings[2] = {
174       subtle::EcdsaSignatureEncoding::DER,
175       subtle::EcdsaSignatureEncoding::IEEE_P1363};
176   for (subtle::EcdsaSignatureEncoding encoding : encodings) {
177     util::StatusOr<EcKey> ec_key = subtle::SubtleUtilBoringSSL::GetNewEcKey(
178         subtle::EllipticCurveType::NIST_P256);
179     ASSERT_THAT(ec_key, IsOk());
180 
181     util::StatusOr<std::unique_ptr<EcdsaRawSignBoringSsl>> signer =
182         EcdsaRawSignBoringSsl::New(*ec_key, encoding);
183     ASSERT_THAT(signer, IsOk());
184 
185     util::StatusOr<std::unique_ptr<subtle::EcdsaVerifyBoringSsl>> verifier =
186         subtle::EcdsaVerifyBoringSsl::New(
187             *ec_key, subtle::HashType::SHA256,
188             encoding == subtle::EcdsaSignatureEncoding::DER
189                 ? subtle::EcdsaSignatureEncoding::IEEE_P1363
190                 : subtle::EcdsaSignatureEncoding::DER);
191     ASSERT_THAT(verifier, IsOk());
192 
193     std::string message = "some data to be signed";
194     util::StatusOr<std::string> message_digest =
195         ComputeDigest(subtle::HashType::SHA256, message);
196     ASSERT_THAT(message_digest, IsOk());
197     util::StatusOr<std::string> signature = (*signer)->Sign(*message_digest);
198     ASSERT_THAT(signature, IsOkAndHolds(Not(Eq(message))));
199     EXPECT_THAT((*verifier)->Verify(*signature, message), Not(IsOk()));
200   }
201 }
202 
TEST(EcdsaRawSignBoringSslTest,SignatureSizesAreCorrectWhenUsingIeeeP136Encoding)203 TEST(EcdsaRawSignBoringSslTest,
204      SignatureSizesAreCorrectWhenUsingIeeeP136Encoding) {
205   if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
206     GTEST_SKIP()
207         << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
208   }
209   subtle::EllipticCurveType curves[3] = {subtle::EllipticCurveType::NIST_P256,
210                                          subtle::EllipticCurveType::NIST_P384,
211                                          subtle::EllipticCurveType::NIST_P521};
212   for (subtle::EllipticCurveType curve : curves) {
213     util::StatusOr<EcKey> ec_key =
214         subtle::SubtleUtilBoringSSL::GetNewEcKey(curve);
215     ASSERT_THAT(ec_key, IsOk());
216 
217     util::StatusOr<std::unique_ptr<EcdsaRawSignBoringSsl>> signer =
218         EcdsaRawSignBoringSsl::New(*ec_key,
219                                    subtle::EcdsaSignatureEncoding::IEEE_P1363);
220     ASSERT_THAT(signer, IsOk());
221 
222     util::StatusOr<std::unique_ptr<subtle::EcdsaVerifyBoringSsl>> verifier =
223         subtle::EcdsaVerifyBoringSsl::New(
224             *ec_key, subtle::HashType::SHA256,
225             subtle::EcdsaSignatureEncoding::IEEE_P1363);
226     ASSERT_THAT(verifier, IsOk());
227 
228     std::string message = "some data to be signed";
229     util::StatusOr<std::string> message_digest =
230         ComputeDigest(subtle::HashType::SHA256, message);
231     ASSERT_THAT(message_digest, IsOk());
232     util::StatusOr<std::string> signature = (*signer)->Sign(*message_digest);
233     ASSERT_THAT(signature, IsOkAndHolds(Not(Eq(message))));
234     EXPECT_THAT((*verifier)->Verify(*signature, message), IsOk());
235 
236     // Check signature size.
237     util::StatusOr<int32_t> field_size_in_bytes =
238         internal::EcFieldSizeInBytes(curve);
239     ASSERT_THAT(field_size_in_bytes, IsOk());
240     EXPECT_THAT(*signature, SizeIs(2 * (*field_size_in_bytes)));
241   }
242 }
243 
TEST(EcdsaRawSignBoringSslTest,CreateFailsWithBadPublicKey)244 TEST(EcdsaRawSignBoringSslTest, CreateFailsWithBadPublicKey) {
245   if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
246     GTEST_SKIP()
247         << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
248   }
249   util::StatusOr<EcKey> ec_key = subtle::SubtleUtilBoringSSL::GetNewEcKey(
250       subtle::EllipticCurveType::NIST_P256);
251   ASSERT_THAT(ec_key, IsOk());
252 
253   ec_key->pub_x += "corrupted public key x coordinate";
254   EXPECT_THAT(
255       EcdsaRawSignBoringSsl::New(*ec_key, subtle::EcdsaSignatureEncoding::DER),
256       Not(IsOk()));
257 }
258 
259 // TODO(bleichen): add Wycheproof tests.
260 
261 // FIPS-only mode test
TEST(EcdsaRawSignBoringSslTest,FipsFailWithoutBoringCrypto)262 TEST(EcdsaRawSignBoringSslTest, FipsFailWithoutBoringCrypto) {
263   if (!internal::IsFipsModeEnabled() || internal::IsFipsEnabledInSsl()) {
264     GTEST_SKIP()
265         << "Test assumes kOnlyUseFips but BoringCrypto is unavailable.";
266   }
267 
268   util::StatusOr<EcKey> p256_key = subtle::SubtleUtilBoringSSL::GetNewEcKey(
269       subtle::EllipticCurveType::NIST_P256);
270   ASSERT_THAT(p256_key, IsOk());
271   EXPECT_THAT(
272       EcdsaRawSignBoringSsl::New(*p256_key, subtle::EcdsaSignatureEncoding::DER)
273           .status(),
274       StatusIs(absl::StatusCode::kInternal));
275 
276   util::StatusOr<EcKey> p384_key = subtle::SubtleUtilBoringSSL::GetNewEcKey(
277       subtle::EllipticCurveType::NIST_P384);
278   ASSERT_THAT(p384_key, IsOk());
279   EXPECT_THAT(
280       EcdsaRawSignBoringSsl::New(*p384_key, subtle::EcdsaSignatureEncoding::DER)
281           .status(),
282       StatusIs(absl::StatusCode::kInternal));
283 
284   util::StatusOr<EcKey> p521_key = *subtle::SubtleUtilBoringSSL::GetNewEcKey(
285       subtle::EllipticCurveType::NIST_P521);
286   ASSERT_THAT(p521_key, IsOk());
287   EXPECT_THAT(
288       EcdsaRawSignBoringSsl::New(*p521_key, subtle::EcdsaSignatureEncoding::DER)
289           .status(),
290       StatusIs(absl::StatusCode::kInternal));
291 }
292 
293 }  // namespace
294 }  // namespace internal
295 }  // namespace tink
296 }  // namespace crypto
297