1 // Copyright 2018 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/subtle/rsa_ssa_pkcs1_verify_boringssl.h"
18
19 #include <iostream>
20 #include <memory>
21 #include <string>
22 #include <utility>
23
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/escaping.h"
27 #include "absl/strings/str_cat.h"
28 #include "openssl/bn.h"
29 #include "include/rapidjson/document.h"
30 #include "tink/internal/err_util.h"
31 #include "tink/internal/fips_utils.h"
32 #include "tink/internal/rsa_util.h"
33 #include "tink/internal/ssl_unique_ptr.h"
34 #include "tink/public_key_sign.h"
35 #include "tink/public_key_verify.h"
36 #include "tink/subtle/common_enums.h"
37 #include "tink/subtle/wycheproof_util.h"
38 #include "tink/util/status.h"
39 #include "tink/util/statusor.h"
40 #include "tink/util/test_matchers.h"
41
42 namespace crypto {
43 namespace tink {
44 namespace subtle {
45 namespace {
46
47 using ::crypto::tink::test::IsOk;
48 using ::crypto::tink::test::StatusIs;
49
50 class RsaSsaPkcs1VerifyBoringSslTest : public ::testing::Test {};
51
52 // Test vector from
53 // https://csrc.nist.gov/Projects/Cryptographic-Algorithm-Validation-Program/Digital-Signatures
54 struct NistTestVector {
55 std::string n;
56 std::string e;
57 std::string message;
58 std::string signature;
59 HashType sig_hash;
60 };
61
62 static const NistTestVector nist_test_vector{
63 absl::HexStringToBytes(
64 "c47abacc2a84d56f3614d92fd62ed36ddde459664b9301dcd1d61781cfcc026bcb2399"
65 "bee7e75681a80b7bf500e2d08ceae1c42ec0b707927f2b2fe92ae852087d25f1d260cc"
66 "74905ee5f9b254ed05494a9fe06732c3680992dd6f0dc634568d11542a705f83ae96d2"
67 "a49763d5fbb24398edf3702bc94bc168190166492b8671de874bb9cecb058c6c8344aa"
68 "8c93754d6effcd44a41ed7de0a9dcd9144437f212b18881d042d331a4618a9e630ef9b"
69 "b66305e4fdf8f0391b3b2313fe549f0189ff968b92f33c266a4bc2cffc897d1937eeb9"
70 "e406f5d0eaa7a14782e76af3fce98f54ed237b4a04a4159a5f6250a296a902880204e6"
71 "1d891c4da29f2d65f34cbb"),
72 absl::HexStringToBytes("49d2a1"),
73 absl::HexStringToBytes(
74 "95123c8d1b236540b86976a11cea31f8bd4e6c54c235147d20ce722b03a6ad756fbd91"
75 "8c27df8ea9ce3104444c0bbe877305bc02e35535a02a58dcda306e632ad30b3dc3ce0b"
76 "a97fdf46ec192965dd9cd7f4a71b02b8cba3d442646eeec4af590824ca98d74fbca934"
77 "d0b6867aa1991f3040b707e806de6e66b5934f05509bea"),
78 absl::HexStringToBytes(
79 "51265d96f11ab338762891cb29bf3f1d2b3305107063f5f3245af376dfcc7027d39365"
80 "de70a31db05e9e10eb6148cb7f6425f0c93c4fb0e2291adbd22c77656afc196858a11e"
81 "1c670d9eeb592613e69eb4f3aa501730743ac4464486c7ae68fd509e896f63884e9424"
82 "f69c1c5397959f1e52a368667a598a1fc90125273d9341295d2f8e1cc4969bf228c860"
83 "e07a3546be2eeda1cde48ee94d062801fe666e4a7ae8cb9cd79262c017b081af874ff0"
84 "0453ca43e34efdb43fffb0bb42a4e2d32a5e5cc9e8546a221fe930250e5f5333e0efe5"
85 "8ffebf19369a3b8ae5a67f6a048bc9ef915bda25160729b508667ada84a0c27e7e26cf"
86 "2abca413e5e4693f4a9405"),
87 HashType::SHA256};
88
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,BasicVerify)89 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, BasicVerify) {
90 if (internal::IsFipsModeEnabled()) {
91 GTEST_SKIP() << "Test not run in FIPS-only mode";
92 }
93
94 internal::RsaPublicKey pub_key{nist_test_vector.n, nist_test_vector.e};
95 internal::RsaSsaPkcs1Params params{nist_test_vector.sig_hash};
96
97 auto verifier_result = RsaSsaPkcs1VerifyBoringSsl::New(pub_key, params);
98 ASSERT_TRUE(verifier_result.ok()) << verifier_result.status();
99 auto verifier = std::move(verifier_result.value());
100 auto status =
101 verifier->Verify(nist_test_vector.signature, nist_test_vector.message);
102 EXPECT_TRUE(status.ok()) << status << internal::GetSslErrors();
103 }
104
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,NewErrors)105 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, NewErrors) {
106 if (internal::IsFipsModeEnabled()) {
107 GTEST_SKIP() << "Test not run in FIPS-only mode";
108 }
109
110 internal::RsaPublicKey nist_pub_key{nist_test_vector.n, nist_test_vector.e};
111 internal::RsaSsaPkcs1Params nist_params{nist_test_vector.sig_hash};
112 internal::RsaPublicKey small_pub_key{std::string("\x23"), std::string("\x3")};
113 internal::RsaSsaPkcs1Params sha1_hash_params{HashType::SHA1};
114
115 { // Small modulus.
116 auto result = RsaSsaPkcs1VerifyBoringSsl::New(small_pub_key, nist_params);
117 EXPECT_FALSE(result.ok());
118 EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
119 EXPECT_PRED_FORMAT2(testing::IsSubstring,
120 "only modulus size >= 2048-bit is supported",
121 std::string(result.status().message()));
122 }
123
124 { // Use SHA1 for digital signature.
125 auto result =
126 RsaSsaPkcs1VerifyBoringSsl::New(nist_pub_key, sha1_hash_params);
127 EXPECT_FALSE(result.ok());
128 EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
129 EXPECT_PRED_FORMAT2(testing::IsSubstring,
130 "SHA1 is not safe for digital signature",
131 std::string(result.status().message()));
132 }
133 }
134
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,Modification)135 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, Modification) {
136 if (internal::IsFipsModeEnabled()) {
137 GTEST_SKIP() << "Test not run in FIPS-only mode";
138 }
139
140 internal::RsaPublicKey pub_key{nist_test_vector.n, nist_test_vector.e};
141 internal::RsaSsaPkcs1Params params{nist_test_vector.sig_hash};
142
143 auto verifier_result = RsaSsaPkcs1VerifyBoringSsl::New(pub_key, params);
144 ASSERT_TRUE(verifier_result.ok()) << verifier_result.status();
145 auto verifier = std::move(verifier_result.value());
146 // Modify the message.
147 for (std::size_t i = 0; i < nist_test_vector.message.length(); i++) {
148 std::string modified_message = nist_test_vector.message;
149 modified_message[i / 8] ^= 1 << (i % 8);
150 auto status =
151 verifier->Verify(nist_test_vector.signature, modified_message);
152 EXPECT_FALSE(status.ok()) << status << internal::GetSslErrors();
153 }
154 // Modify the signature.
155 for (std::size_t i = 0; i < nist_test_vector.signature.length(); i++) {
156 std::string modified_signature = nist_test_vector.signature;
157 modified_signature[i / 8] ^= 1 << (i % 8);
158 auto status =
159 verifier->Verify(modified_signature, nist_test_vector.message);
160 EXPECT_FALSE(status.ok()) << status << internal::GetSslErrors();
161 }
162 // Truncate the signature.
163 for (std::size_t i = 0; i < nist_test_vector.signature.length(); i++) {
164 std::string truncated_signature(nist_test_vector.signature, 0, i);
165 auto status =
166 verifier->Verify(truncated_signature, nist_test_vector.message);
167 EXPECT_FALSE(status.ok()) << status << internal::GetSslErrors();
168 }
169 }
170
GetVerifier(const rapidjson::Value & test_group)171 static util::StatusOr<std::unique_ptr<RsaSsaPkcs1VerifyBoringSsl>> GetVerifier(
172 const rapidjson::Value& test_group) {
173 internal::RsaPublicKey key;
174 key.n = WycheproofUtil::GetInteger(test_group["n"]);
175 key.e = WycheproofUtil::GetInteger(test_group["e"]);
176
177 HashType md = WycheproofUtil::GetHashType(test_group["sha"]);
178 internal::RsaSsaPkcs1Params params;
179 params.hash_type = md;
180
181 auto result = RsaSsaPkcs1VerifyBoringSsl::New(key, params);
182 if (!result.ok()) {
183 std::cout << "Failed: " << result.status() << "\n";
184 }
185 return result;
186 }
187
188 // Tests signature verification using the test vectors in the specified file.
189 // allow_skipping determines whether it is OK to skip a test because
190 // a verfier cannot be constructed. This option can be used for
191 // if a file contains test vectors that are not necessarily supported
192 // by tink.
TestSignatures(const std::string & filename,bool allow_skipping)193 bool TestSignatures(const std::string& filename, bool allow_skipping) {
194 std::unique_ptr<rapidjson::Document> root =
195 WycheproofUtil::ReadTestVectors(filename);
196 std::cout << (*root)["algorithm"].GetString();
197 std::cout << "generator version " << (*root)["generatorVersion"].GetString();
198 std::cout << "expected version 0.4.12";
199 int passed_tests = 0;
200 int failed_tests = 0;
201 int group_count = 0;
202 for (const rapidjson::Value& test_group : (*root)["testGroups"].GetArray()) {
203 group_count++;
204 auto verifier_result = GetVerifier(test_group);
205 if (!verifier_result.ok()) {
206 std::string type = test_group["type"].GetString();
207 if (allow_skipping) {
208 std::cout << "Could not construct verifier for " << type << " group "
209 << group_count << ": " << verifier_result.status();
210 } else {
211 ADD_FAILURE() << "Could not construct verifier for " << type
212 << " group " << group_count << ": "
213 << verifier_result.status();
214 failed_tests += test_group["tests"].GetArray().Size();
215 }
216 continue;
217 }
218 auto verifier = std::move(verifier_result.value());
219 for (const rapidjson::Value& test : test_group["tests"].GetArray()) {
220 std::string expected = test["result"].GetString();
221 std::string msg = WycheproofUtil::GetBytes(test["msg"]);
222 std::string sig = WycheproofUtil::GetBytes(test["sig"]);
223 std::string id =
224 absl::StrCat(test["tcId"].GetInt(), " ", test["comment"].GetString());
225 auto status = verifier->Verify(sig, msg);
226 if (expected == "valid") {
227 if (status.ok()) {
228 ++passed_tests;
229 } else {
230 ++failed_tests;
231 ADD_FAILURE() << "Valid signature not verified:" << id
232 << " status:" << status;
233 }
234 } else if (expected == "invalid") {
235 if (!status.ok()) {
236 ++passed_tests;
237 } else {
238 ++failed_tests;
239 ADD_FAILURE() << "Invalid signature verified:" << id;
240 }
241 } else if (expected == "acceptable") {
242 // The validity of the signature is undefined. Hence the test passes
243 // but we log the result since we might still want to know if the
244 // library is strict or forgiving.
245 ++passed_tests;
246 std::cout << "Acceptable signature:" << id << ":" << status;
247 } else {
248 ++failed_tests;
249 ADD_FAILURE() << "Invalid field result:" << expected;
250 }
251 }
252 }
253 int num_tests = (*root)["numberOfTests"].GetInt();
254 std::cout << "total number of tests: " << num_tests;
255 std::cout << "number of tests passed:" << passed_tests;
256 std::cout << "number of tests failed:" << failed_tests;
257 return failed_tests == 0;
258 }
259
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,WycheproofRsaPkcs12048SHA256)260 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, WycheproofRsaPkcs12048SHA256) {
261 if (internal::IsFipsModeEnabled()) {
262 GTEST_SKIP() << "Test not run in FIPS-only mode";
263 }
264 ASSERT_TRUE(TestSignatures("rsa_signature_2048_sha256_test.json",
265 /*allow_skipping=*/true));
266 }
267
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,WycheproofRsaPkcs13072SHA256)268 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, WycheproofRsaPkcs13072SHA256) {
269 if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
270 GTEST_SKIP()
271 << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
272 }
273 ASSERT_TRUE(TestSignatures("rsa_signature_3072_sha256_test.json",
274 /*allow_skipping=*/true));
275 }
276
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,WycheproofRsaPkcs13072SHA512)277 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, WycheproofRsaPkcs13072SHA512) {
278 if (internal::IsFipsModeEnabled() && !internal::IsFipsEnabledInSsl()) {
279 GTEST_SKIP()
280 << "Test is skipped if kOnlyUseFips but BoringCrypto is unavailable.";
281 }
282 ASSERT_TRUE(TestSignatures("rsa_signature_3072_sha512_test.json",
283 /*allow_skipping=*/true));
284 }
285
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,WycheproofRsaPkcs14096SHA512)286 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, WycheproofRsaPkcs14096SHA512) {
287 if (internal::IsFipsModeEnabled()) {
288 GTEST_SKIP() << "Test not run in FIPS-only mode";
289 }
290 ASSERT_TRUE(TestSignatures("rsa_signature_4096_sha512_test.json",
291 /*allow_skipping=*/true));
292 }
293
294 // FIPS-only mode test
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,TestFipsFailWithoutBoringCrypto)295 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, TestFipsFailWithoutBoringCrypto) {
296 if (!internal::IsFipsModeEnabled() || internal::IsFipsEnabledInSsl()) {
297 GTEST_SKIP()
298 << "Test assumes kOnlyUseFips but BoringCrypto is unavailable.";
299 }
300
301 internal::RsaPublicKey pub_key{nist_test_vector.n, nist_test_vector.e};
302 internal::RsaSsaPkcs1Params params{/*sig_hash=*/HashType::SHA256};
303 EXPECT_THAT(RsaSsaPkcs1VerifyBoringSsl::New(pub_key, params).status(),
304 StatusIs(absl::StatusCode::kInternal));
305 }
306
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,TestAllowedFipsModuli)307 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, TestAllowedFipsModuli) {
308 if (!internal::IsFipsModeEnabled() || !internal::IsFipsEnabledInSsl()) {
309 GTEST_SKIP() << "Test assumes kOnlyUseFips and BoringCrypto.";
310 }
311
312 internal::SslUniquePtr<BIGNUM> rsa_f4(BN_new());
313 internal::RsaPrivateKey private_key;
314 internal::RsaPublicKey public_key;
315 BN_set_word(rsa_f4.get(), RSA_F4);
316
317 EXPECT_THAT(
318 internal::NewRsaKeyPair(3072, rsa_f4.get(), &private_key, &public_key),
319 IsOk());
320
321 internal::RsaSsaPkcs1Params params{/*sig_hash=*/HashType::SHA256};
322 EXPECT_THAT(RsaSsaPkcs1VerifyBoringSsl::New(public_key, params).status(),
323 IsOk());
324 }
325
TEST_F(RsaSsaPkcs1VerifyBoringSslTest,TestRestrictedFipsModuli)326 TEST_F(RsaSsaPkcs1VerifyBoringSslTest, TestRestrictedFipsModuli) {
327 if (!internal::IsFipsModeEnabled() || !internal::IsFipsEnabledInSsl()) {
328 GTEST_SKIP() << "Test assumes kOnlyUseFips and BoringCrypto.";
329 }
330
331 internal::SslUniquePtr<BIGNUM> rsa_f4(BN_new());
332 internal::RsaPrivateKey private_key;
333 internal::RsaPublicKey public_key;
334 internal::RsaSsaPkcs1Params params{/*sig_hash=*/HashType::SHA256};
335 BN_set_word(rsa_f4.get(), RSA_F4);
336
337 EXPECT_THAT(
338 internal::NewRsaKeyPair(2560, rsa_f4.get(), &private_key, &public_key),
339 IsOk());
340
341 EXPECT_THAT(RsaSsaPkcs1VerifyBoringSsl::New(public_key, params).status(),
342 StatusIs(absl::StatusCode::kInternal));
343
344 EXPECT_THAT(
345 internal::NewRsaKeyPair(4096, rsa_f4.get(), &private_key, &public_key),
346 IsOk());
347
348 EXPECT_THAT(RsaSsaPkcs1VerifyBoringSsl::New(public_key, params).status(),
349 StatusIs(absl::StatusCode::kInternal));
350 }
351
352 } // namespace
353 } // namespace subtle
354 } // namespace tink
355 } // namespace crypto
356