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