| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/cert/internal/verify_signed_data.h" |
| |
| #include <memory> |
| #include <set> |
| |
| #include "net/cert/internal/signature_algorithm.h" |
| #include "net/cert/internal/signature_policy.h" |
| #include "net/cert/internal/test_helpers.h" |
| #include "net/der/input.h" |
| #include "net/der/parse_values.h" |
| #include "net/der/parser.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #include <openssl/obj.h> |
| |
| namespace net { |
| |
| namespace { |
| |
| enum VerifyResult { |
| SUCCESS, |
| FAILURE, |
| }; |
| |
| // Reads test data from |file_name| and runs VerifySignedData() over its |
| // inputs, using |policy|. |
| // |
| // If expected_result was SUCCESS then the test will only succeed if |
| // VerifySignedData() returns true. |
| // |
| // If expected_result was FAILURE then the test will only succeed if |
| // VerifySignedData() returns false. |
| void RunTestCaseUsingPolicy(VerifyResult expected_result, |
| const char* file_name, |
| const SignaturePolicy* policy) { |
| std::string path = |
| std::string("net/data/verify_signed_data_unittest/") + file_name; |
| |
| std::string public_key; |
| std::string algorithm; |
| std::string signed_data; |
| std::string signature_value; |
| |
| const PemBlockMapping mappings[] = { |
| {"PUBLIC KEY", &public_key}, |
| {"ALGORITHM", &algorithm}, |
| {"DATA", &signed_data}, |
| {"SIGNATURE", &signature_value}, |
| }; |
| |
| ASSERT_TRUE(ReadTestDataFromPemFile(path, mappings)); |
| |
| std::unique_ptr<SignatureAlgorithm> signature_algorithm = |
| SignatureAlgorithm::CreateFromDer(der::Input(&algorithm)); |
| ASSERT_TRUE(signature_algorithm); |
| |
| der::BitString signature_value_bit_string; |
| der::Parser signature_value_parser((der::Input(&signature_value))); |
| ASSERT_TRUE(signature_value_parser.ReadBitString(&signature_value_bit_string)) |
| << "The signature value is not a valid BIT STRING"; |
| |
| bool expected_result_bool = expected_result == SUCCESS; |
| |
| EXPECT_EQ(expected_result_bool, |
| VerifySignedData(*signature_algorithm, der::Input(&signed_data), |
| signature_value_bit_string, |
| der::Input(&public_key), policy)); |
| } |
| |
| // RunTestCase() is the same as RunTestCaseUsingPolicy(), only it uses a |
| // default policy. This policy will accept a basic profile of signature |
| // algorithms (including ANY sized RSA key >= 1024). |
| void RunTestCase(VerifyResult expected_result, const char* file_name) { |
| SimpleSignaturePolicy policy(1024); |
| return RunTestCaseUsingPolicy(expected_result, file_name, &policy); |
| } |
| |
| // Read the descriptions in the test files themselves for details on what is |
| // being tested. |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha1) { |
| RunTestCase(SUCCESS, "rsa-pkcs1-sha1.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha256) { |
| RunTestCase(SUCCESS, "rsa-pkcs1-sha256.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, Rsa2048Pkcs1Sha512) { |
| RunTestCase(SUCCESS, "rsa2048-pkcs1-sha512.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha256KeyEncodedBer) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha256-key-encoded-ber.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaSecp384r1Sha256) { |
| RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512) { |
| RunTestCase(SUCCESS, "ecdsa-prime256v1-sha512.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha1) { |
| RunTestCase(SUCCESS, "rsa-pss-sha1-salt20.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha256Mgf1Sha512Salt33) { |
| RunTestCase(SUCCESS, "rsa-pss-sha256-mgf1-sha512-salt33.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha256) { |
| RunTestCase(SUCCESS, "rsa-pss-sha256-salt10.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha1WrongSalt) { |
| RunTestCase(FAILURE, "rsa-pss-sha1-wrong-salt.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaSecp384r1Sha256CorruptedData) { |
| RunTestCase(FAILURE, "ecdsa-secp384r1-sha256-corrupted-data.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha1WrongAlgorithm) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha1-wrong-algorithm.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512WrongSignatureFormat) { |
| RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-wrong-signature-format.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaUsingRsaKey) { |
| RunTestCase(FAILURE, "ecdsa-using-rsa-key.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaUsingEcKey) { |
| RunTestCase(FAILURE, "rsa-using-ec-key.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha1BadKeyDerNull) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha1-bad-key-der-null.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha1BadKeyDerLength) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha1-bad-key-der-length.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha256UsingEcdsaAlgorithm) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha256-using-ecdsa-algorithm.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512UsingRsaAlgorithm) { |
| RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-rsa-algorithm.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512UsingEcdhKey) { |
| RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-ecdh-key.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512UsingEcmqvKey) { |
| RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-using-ecmqv-key.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha1KeyParamsAbsent) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha1-key-params-absent.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha1Salt20UsingPssKeyNoParams) { |
| // TODO(eroman): This should pass! (rsaPss not currently supported in key |
| // algorithm). See https://crbug.com/522232 |
| RunTestCase(FAILURE, "rsa-pss-sha1-salt20-using-pss-key-no-params.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha1UsingPssKeyNoParams) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha1-using-pss-key-no-params.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha256Salt10UsingPssKeyWithParams) { |
| // TODO(eroman): This should pass! (rsaPss not currently supported in key |
| // algorithm). See https://crbug.com/522232 |
| RunTestCase(FAILURE, "rsa-pss-sha256-salt10-using-pss-key-with-params.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha256Salt10UsingPssKeyWithWrongParams) { |
| RunTestCase(FAILURE, |
| "rsa-pss-sha256-salt10-using-pss-key-with-wrong-params.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPssSha256Salt12UsingPssKeyWithNullParams) { |
| RunTestCase(FAILURE, |
| "rsa-pss-sha1-salt20-using-pss-key-with-null-params.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512SpkiParamsNull) { |
| RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-spki-params-null.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha256UsingIdEaRsa) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha256-using-id-ea-rsa.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, RsaPkcs1Sha256SpkiNonNullParams) { |
| RunTestCase(FAILURE, "rsa-pkcs1-sha256-spki-non-null-params.pem"); |
| } |
| |
| TEST(VerifySignedDataTest, EcdsaPrime256v1Sha512UnusedBitsSignature) { |
| RunTestCase(FAILURE, "ecdsa-prime256v1-sha512-unused-bits-signature.pem"); |
| } |
| |
| // This policy rejects specifically secp384r1 curves. |
| class RejectSecp384r1Policy : public SignaturePolicy { |
| public: |
| bool IsAcceptableCurveForEcdsa(int curve_nid) const override { |
| if (curve_nid == NID_secp384r1) |
| return false; |
| return true; |
| } |
| }; |
| |
| TEST(VerifySignedDataTest, PolicyIsAcceptableCurveForEcdsa) { |
| // Using the regular policy both secp384r1 and secp256r1 should be accepted. |
| RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); |
| RunTestCase(SUCCESS, "ecdsa-prime256v1-sha512.pem"); |
| |
| // However when using a policy that specifically rejects secp384r1, only |
| // prime256v1 should be accepted. |
| RejectSecp384r1Policy policy; |
| RunTestCaseUsingPolicy(FAILURE, "ecdsa-secp384r1-sha256.pem", &policy); |
| RunTestCaseUsingPolicy(SUCCESS, "ecdsa-prime256v1-sha512.pem", &policy); |
| } |
| |
| TEST(VerifySignedDataTest, PolicyIsAcceptableModulusLengthForRsa) { |
| // Using the regular policy both 1024-bit and 2048-bit RSA keys should be |
| // accepted. |
| SimpleSignaturePolicy policy_1024(1024); |
| RunTestCaseUsingPolicy(SUCCESS, "rsa-pkcs1-sha256.pem", &policy_1024); |
| RunTestCaseUsingPolicy(SUCCESS, "rsa2048-pkcs1-sha512.pem", &policy_1024); |
| |
| // However when using a policy that rejects any keys less than 2048-bits, only |
| // one of the tests will pass. |
| SimpleSignaturePolicy policy_2048(2048); |
| RunTestCaseUsingPolicy(FAILURE, "rsa-pkcs1-sha256.pem", &policy_2048); |
| RunTestCaseUsingPolicy(SUCCESS, "rsa2048-pkcs1-sha512.pem", &policy_2048); |
| } |
| |
| // This policy rejects the use of SHA-512. |
| class RejectSha512 : public SignaturePolicy { |
| public: |
| RejectSha512() : SignaturePolicy() {} |
| |
| bool IsAcceptableSignatureAlgorithm( |
| const SignatureAlgorithm& algorithm) const override { |
| if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss && |
| algorithm.ParamsForRsaPss()->mgf1_hash() == DigestAlgorithm::Sha512) { |
| return false; |
| } |
| |
| return algorithm.digest() != DigestAlgorithm::Sha512; |
| } |
| |
| bool IsAcceptableModulusLengthForRsa( |
| size_t modulus_length_bits) const override { |
| return true; |
| } |
| }; |
| |
| TEST(VerifySignedDataTest, PolicyIsAcceptableDigestAlgorithm) { |
| // Using the regular policy use of either SHA256 or SHA512 should work |
| // (whether as the main digest, or the MGF1 for RSASSA-PSS) |
| RunTestCase(SUCCESS, "rsa2048-pkcs1-sha512.pem"); |
| RunTestCase(SUCCESS, "ecdsa-prime256v1-sha512.pem"); |
| RunTestCase(SUCCESS, "ecdsa-secp384r1-sha256.pem"); |
| RunTestCase(SUCCESS, "rsa-pkcs1-sha256.pem"); |
| RunTestCase(SUCCESS, "rsa-pss-sha256-salt10.pem"); |
| // This one uses both SHA256 and SHA512 |
| RunTestCase(SUCCESS, "rsa-pss-sha256-mgf1-sha512-salt33.pem"); |
| |
| // The tests using SHA512 should fail when using a policy that rejects SHA512. |
| // Everything else should pass. |
| RejectSha512 policy; |
| RunTestCaseUsingPolicy(FAILURE, "rsa2048-pkcs1-sha512.pem", &policy); |
| RunTestCaseUsingPolicy(FAILURE, "ecdsa-prime256v1-sha512.pem", &policy); |
| RunTestCaseUsingPolicy(SUCCESS, "ecdsa-secp384r1-sha256.pem", &policy); |
| RunTestCaseUsingPolicy(SUCCESS, "rsa-pkcs1-sha256.pem", &policy); |
| RunTestCaseUsingPolicy(SUCCESS, "rsa-pss-sha256-salt10.pem", &policy); |
| RunTestCaseUsingPolicy(FAILURE, "rsa-pss-sha256-mgf1-sha512-salt33.pem", |
| &policy); |
| } |
| |
| } // namespace |
| |
| } // namespace net |