Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/internal/verify_signed_data.h" | 5 #include "net/cert/internal/verify_signed_data.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/base_paths.h" | 9 #include "base/base_paths.h" |
| 10 #include "base/files/file_util.h" | 10 #include "base/files/file_util.h" |
| 11 #include "base/path_service.h" | 11 #include "base/path_service.h" |
| 12 #include "net/cert/internal/signature_algorithm.h" | 12 #include "net/cert/internal/signature_algorithm.h" |
| 13 #include "net/cert/internal/signature_policy.h" | |
| 13 #include "net/cert/pem_tokenizer.h" | 14 #include "net/cert/pem_tokenizer.h" |
| 14 #include "net/der/input.h" | 15 #include "net/der/input.h" |
| 15 #include "net/der/parse_values.h" | 16 #include "net/der/parse_values.h" |
| 16 #include "net/der/parser.h" | 17 #include "net/der/parser.h" |
| 17 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
| 18 | 19 |
| 20 #if defined(USE_OPENSSL) | |
| 21 #include <openssl/obj_mac.h> | |
|
davidben
2015/08/06 21:32:04
(This one also should be obj.h.)
eroman
2015/08/06 22:22:30
Done. Sorry about not remembering that!
| |
| 22 #endif | |
| 23 | |
| 19 namespace net { | 24 namespace net { |
| 20 | 25 |
| 21 namespace { | 26 namespace { |
| 22 | 27 |
| 23 // Creates a der::Input from an std::string. The lifetimes are a bit subtle | 28 // Creates a der::Input from an std::string. The lifetimes are a bit subtle |
| 24 // when using this function: | 29 // when using this function: |
| 25 // | 30 // |
| 26 // The returned der::Input() is only valid so long as the input string is alive | 31 // The returned der::Input() is only valid so long as the input string is alive |
| 27 // and is not mutated. | 32 // and is not mutated. |
| 28 // | 33 // |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 return src_root.Append( | 102 return src_root.Append( |
| 98 FILE_PATH_LITERAL("net/data/verify_signed_data_unittest")) | 103 FILE_PATH_LITERAL("net/data/verify_signed_data_unittest")) |
| 99 .AppendASCII(file_name); | 104 .AppendASCII(file_name); |
| 100 } | 105 } |
| 101 | 106 |
| 102 enum VerifyResult { | 107 enum VerifyResult { |
| 103 SUCCESS, | 108 SUCCESS, |
| 104 FAILURE, | 109 FAILURE, |
| 105 }; | 110 }; |
| 106 | 111 |
| 107 // Reads test data from |file_name| and runs VerifySignedData() over its inputs. | 112 // Reads test data from |file_name| and runs VerifySignedData() over its |
| 113 // inputs, using |policy|. | |
| 108 // | 114 // |
| 109 // If expected_result was SUCCESS then the test will only succeed if | 115 // If expected_result was SUCCESS then the test will only succeed if |
| 110 // VerifySignedData() returns true. | 116 // VerifySignedData() returns true. |
| 111 // | 117 // |
| 112 // If expected_result was FAILURE then the test will only succeed if | 118 // If expected_result was FAILURE then the test will only succeed if |
| 113 // VerifySignedData() returns false. | 119 // VerifySignedData() returns false. |
| 114 void RunTestCase(VerifyResult expected_result, const char* file_name) { | 120 void RunTestCaseUsingPolicy(VerifyResult expected_result, |
| 121 const char* file_name, | |
| 122 const SignaturePolicy* policy) { | |
| 115 #if !defined(USE_OPENSSL) | 123 #if !defined(USE_OPENSSL) |
| 116 LOG(INFO) << "Skipping test, only implemented for BoringSSL"; | 124 LOG(INFO) << "Skipping test, only implemented for BoringSSL"; |
| 117 return; | 125 return; |
| 118 #endif | 126 #endif |
| 119 | 127 |
| 120 base::FilePath test_file_path = GetTestFilePath(file_name); | 128 base::FilePath test_file_path = GetTestFilePath(file_name); |
| 121 | 129 |
| 122 std::string file_data; | 130 std::string file_data; |
| 123 ASSERT_TRUE(base::ReadFileToString(test_file_path, &file_data)) | 131 ASSERT_TRUE(base::ReadFileToString(test_file_path, &file_data)) |
| 124 << "Couldn't read file: " << test_file_path.value(); | 132 << "Couldn't read file: " << test_file_path.value(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 135 SignatureAlgorithm::CreateFromDer(InputFromString(&algorithm)); | 143 SignatureAlgorithm::CreateFromDer(InputFromString(&algorithm)); |
| 136 ASSERT_TRUE(signature_algorithm); | 144 ASSERT_TRUE(signature_algorithm); |
| 137 | 145 |
| 138 der::BitString signature_value_bit_string; | 146 der::BitString signature_value_bit_string; |
| 139 der::Parser signature_value_parser(InputFromString(&signature_value)); | 147 der::Parser signature_value_parser(InputFromString(&signature_value)); |
| 140 ASSERT_TRUE(signature_value_parser.ReadBitString(&signature_value_bit_string)) | 148 ASSERT_TRUE(signature_value_parser.ReadBitString(&signature_value_bit_string)) |
| 141 << "The signature value is not a valid BIT STRING"; | 149 << "The signature value is not a valid BIT STRING"; |
| 142 | 150 |
| 143 bool expected_result_bool = expected_result == SUCCESS; | 151 bool expected_result_bool = expected_result == SUCCESS; |
| 144 | 152 |
| 145 EXPECT_EQ(expected_result_bool, | 153 EXPECT_EQ( |
| 146 VerifySignedData( | 154 expected_result_bool, |
| 147 *signature_algorithm, InputFromString(&signed_data), | 155 VerifySignedData(*signature_algorithm, InputFromString(&signed_data), |
| 148 signature_value_bit_string, InputFromString(&public_key))); | 156 signature_value_bit_string, InputFromString(&public_key), |
| 157 policy)); | |
| 158 } | |
| 159 | |
| 160 // RunTestCase() is the same as RunTestCaseUsingPolicy(), only it uses a | |
| 161 // default policy. This policy will accept a basic profile of signature | |
| 162 // algorithms (including ANY sized RSA key >= 1024). | |
| 163 void RunTestCase(VerifyResult expected_result, const char* file_name) { | |
| 164 SimpleSignaturePolicy policy(1024); | |
| 165 return RunTestCaseUsingPolicy(expected_result, file_name, &policy); | |
| 149 } | 166 } |
| 150 | 167 |
| 151 // Read the descriptions in the test files themselves for details on what is | 168 // Read the descriptions in the test files themselves for details on what is |
| 152 // being tested. | 169 // being tested. |
| 153 | 170 |
| 154 TEST(VerifySignedDataTest, RsaPkcs1Sha1) { | 171 TEST(VerifySignedDataTest, RsaPkcs1Sha1) { |
| 155 RunTestCase(SUCCESS, "rsa-pkcs1-sha1.pem"); | 172 RunTestCase(SUCCESS, "rsa-pkcs1-sha1.pem"); |
| 156 } | 173 } |
| 157 | 174 |
| 158 TEST(VerifySignedDataTest, RsaPkcs1Sha256) { | 175 TEST(VerifySignedDataTest, RsaPkcs1Sha256) { |
| 159 RunTestCase(SUCCESS, "rsa-pkcs1-sha256.pem"); | 176 RunTestCase(SUCCESS, "rsa-pkcs1-sha256.pem"); |
| 160 } | 177 } |
| 161 | 178 |
| 179 TEST(VerifySignedDataTest, Rsa2048Pkcs1Sha512) { | |
| 180 RunTestCase(SUCCESS, "rsa2048-pkcs1-sha512.pem"); | |
| 181 } | |
| 182 | |
| 162 TEST(VerifySignedDataTest, RsaPkcs1Sha256KeyEncodedBer) { | 183 TEST(VerifySignedDataTest, RsaPkcs1Sha256KeyEncodedBer) { |
| 163 // TODO(eroman): This should fail! (SPKI should be DER-encoded). | 184 // TODO(eroman): This should fail! (SPKI should be DER-encoded). |
| 164 RunTestCase(SUCCESS, "rsa-pkcs1-sha256-key-encoded-ber.pem"); | 185 RunTestCase(SUCCESS, "rsa-pkcs1-sha256-key-encoded-ber.pem"); |
| 165 } | 186 } |
| 166 | 187 |
| 167 TEST(VerifySignedDataTest, EcdsaSecp384r1Sha256) { | 188 TEST(VerifySignedDataTest, EcdsaSecp384r1Sha256) { |
| 168 RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); | 189 RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); |
| 169 } | 190 } |
| 170 | 191 |
| 171 TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512) { | 192 TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 TEST(VerifySignedDataTest, RsaPkcs1Sha256SpkiNonNullParams) { | 296 TEST(VerifySignedDataTest, RsaPkcs1Sha256SpkiNonNullParams) { |
| 276 // TODO(eroman): This should fail! (shouldn't recognize bogus params in rsa | 297 // TODO(eroman): This should fail! (shouldn't recognize bogus params in rsa |
| 277 // SPKI). | 298 // SPKI). |
| 278 RunTestCase(SUCCESS, "rsa-pkcs1-sha256-spki-non-null-params.pem"); | 299 RunTestCase(SUCCESS, "rsa-pkcs1-sha256-spki-non-null-params.pem"); |
| 279 } | 300 } |
| 280 | 301 |
| 281 TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512UnusedBitsSignature) { | 302 TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512UnusedBitsSignature) { |
| 282 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-unused-bits-signature.pem"); | 303 RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-unused-bits-signature.pem"); |
| 283 } | 304 } |
| 284 | 305 |
| 306 // This policy rejects specifically secp384r1 curves. | |
| 307 class RejectSecp384r1Policy : public SignaturePolicy { | |
| 308 public: | |
| 309 bool IsAcceptableCurveForEcdsa(int curve_nid) const override { | |
| 310 #if defined(USE_OPENSSL) | |
| 311 if (curve_nid == NID_secp384r1) | |
| 312 return false; | |
| 313 #endif | |
| 314 return true; | |
| 315 } | |
| 316 }; | |
| 317 | |
| 318 TEST(VerifySignedDataTest, PolicyIsAcceptableCurveForEcdsa) { | |
| 319 RejectSecp384r1Policy policy; | |
| 320 | |
| 321 // Using the regular policy both secp384r1 and secp256r1 should be accepted. | |
| 322 RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); | |
| 323 RunTestCase(SUCCESS, "ecdsa-prime256v1-sha512.pem"); | |
| 324 | |
| 325 // However when using a policy that specifically rejects secp384r1, only | |
| 326 // prime256v1 should be accepted. | |
| 327 RunTestCaseUsingPolicy(FAILURE, "ecdsa-secp384r1-sha256.pem", &policy); | |
| 328 RunTestCaseUsingPolicy(SUCCESS, "ecdsa-prime256v1-sha512.pem", &policy); | |
| 329 } | |
| 330 | |
| 331 TEST(VerifySignedDataTest, PolicyIsAcceptableModulusLengthForRsa) { | |
| 332 SimpleSignaturePolicy policy_1024(1024); | |
| 333 SimpleSignaturePolicy policy_2048(2048); | |
| 334 | |
| 335 // Using the regular policy both 1024-bit and 2048-bit RSA keys should be | |
| 336 // accepted. | |
| 337 RunTestCaseUsingPolicy(SUCCESS, "rsa-pkcs1-sha256.pem", &policy_1024); | |
| 338 RunTestCaseUsingPolicy(SUCCESS, "rsa2048-pkcs1-sha512.pem", &policy_1024); | |
| 339 | |
| 340 // However when using a policy that rejects any keys less than 2048-bits, only | |
| 341 // one of the tests will pass. | |
| 342 RunTestCaseUsingPolicy(FAILURE, "rsa-pkcs1-sha256.pem", &policy_2048); | |
| 343 RunTestCaseUsingPolicy(SUCCESS, "rsa2048-pkcs1-sha512.pem", &policy_2048); | |
| 344 } | |
| 345 | |
| 346 // This policy rejects the use of SHA-512. | |
| 347 class RejectSha512 : public SignaturePolicy { | |
| 348 public: | |
| 349 RejectSha512() : SignaturePolicy() {} | |
| 350 | |
| 351 bool IsAcceptableSignatureAlgorithm( | |
| 352 const SignatureAlgorithm& algorithm) const override { | |
| 353 if (algorithm.ParamsForRsaPss() && | |
|
davidben
2015/08/06 21:32:04
Would algorithm.algorithm() == SignatureAlgorithmI
eroman
2015/08/06 22:22:30
Done.
| |
| 354 algorithm.ParamsForRsaPss()->mgf1_hash() == DigestAlgorithm::Sha512) { | |
| 355 return false; | |
| 356 } | |
| 357 | |
| 358 return algorithm.digest() != DigestAlgorithm::Sha512; | |
| 359 } | |
| 360 | |
| 361 bool IsAcceptableModulusLengthForRsa( | |
| 362 size_t modulus_length_bits) const override { | |
| 363 return true; | |
| 364 } | |
| 365 }; | |
| 366 | |
| 367 TEST(VerifySignedDataTest, PolicyIsAcceptableDigestAlgorithm) { | |
| 368 RejectSha512 policy; | |
| 369 | |
| 370 // Using the regular policy use of either SHA256 or SHA512 should work | |
| 371 // (whether as the main digest, or the MGF1 for RSASSA-PSS) | |
| 372 RunTestCase(SUCCESS, "rsa2048-pkcs1-sha512.pem"); | |
| 373 RunTestCase(SUCCESS, "ecdsa-prime256v1-sha512.pem"); | |
| 374 RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); | |
| 375 RunTestCase(SUCCESS, "rsa-pkcs1-sha256.pem"); | |
| 376 RunTestCase(SUCCESS, "rsa-pss-sha256-salt10.pem"); | |
| 377 // This one uses both SHA256 and SHA512 | |
| 378 RunTestCase(SUCCESS, "rsa-pss-sha256-mgf1-sha512-salt33.pem"); | |
| 379 | |
| 380 // However when using a policy that rejects SHA512, only the tests using | |
| 381 // exclusively SHA256 should pass). | |
|
davidben
2015/08/06 21:32:04
Nit: maybe phrase this as 'the tests using SHA512
eroman
2015/08/06 22:22:30
Done.
| |
| 382 RunTestCaseUsingPolicy(FAILURE, "rsa2048-pkcs1-sha512.pem", &policy); | |
| 383 RunTestCaseUsingPolicy(FAILURE, "ecdsa-prime256v1-sha512.pem", &policy); | |
| 384 RunTestCaseUsingPolicy(SUCCESS, "ecdsa-secp384r1-sha256.pem", &policy); | |
| 385 RunTestCaseUsingPolicy(SUCCESS, "rsa-pkcs1-sha256.pem", &policy); | |
| 386 RunTestCaseUsingPolicy(SUCCESS, "rsa-pss-sha256-salt10.pem", &policy); | |
| 387 RunTestCaseUsingPolicy(FAILURE, "rsa-pss-sha256-mgf1-sha512-salt33.pem", | |
| 388 &policy); | |
| 389 } | |
| 390 | |
| 285 } // namespace | 391 } // namespace |
| 286 | 392 |
| 287 } // namespace net | 393 } // namespace net |
| OLD | NEW |