| // Copyright 2021 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "missive/encryption/verification.h" | |
| #include <cstdint> | |
| #include <string> | |
| #include <base/memory/scoped_refptr.h> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "missive/encryption/primitives.h" | |
| #include "missive/encryption/testing_primitives.h" | |
| #include "missive/util/status.h" | |
| #include "missive/util/status_macros.h" | |
| using testing::Eq; | |
| using testing::HasSubstr; | |
| using testing::Ne; | |
| using testing::TestParamInfo; | |
| using testing::TestWithParam; | |
| using testing::ValuesIn; | |
| namespace reporting { | |
| namespace { | |
| class VerificationTest : public ::testing::Test { | |
| protected: | |
| VerificationTest() = default; | |
| void SetUp() override { | |
| // Generate new pair of private key and public value. | |
| test::GenerateSigningKeyPair(private_key_, public_value_); | |
| signature_verification_dev_flag_ = | |
| base::MakeRefCounted<SignatureVerificationDevFlag>( | |
| /*is_enabled=*/false); | |
| } | |
| uint8_t public_value_[kKeySize]; | |
| uint8_t private_key_[kSignKeySize]; | |
| scoped_refptr<SignatureVerificationDevFlag> signature_verification_dev_flag_; | |
| }; | |
| TEST_F(VerificationTest, SignAndVerify) { | |
| static constexpr char message[] = "ABCDEF 012345"; | |
| // Sign the message. | |
| uint8_t signature[kSignatureSize]; | |
| test::SignMessage(private_key_, message, signature); | |
| // Verify the signature. | |
| SignatureVerifier verifier( | |
| std::string(reinterpret_cast<const char*>(public_value_), kKeySize), | |
| signature_verification_dev_flag_); | |
| EXPECT_OK(verifier.Verify( | |
| std::string(message, strlen(message)), | |
| std::string(reinterpret_cast<const char*>(signature), kSignatureSize))); | |
| } | |
| TEST_F(VerificationTest, SignAndFailBadSignature) { | |
| static constexpr char message[] = "ABCDEF 012345"; | |
| // Sign the message. | |
| uint8_t signature[kSignatureSize]; | |
| test::SignMessage(private_key_, message, signature); | |
| // Verify the signature - wrong length. | |
| SignatureVerifier verifier( | |
| std::string(reinterpret_cast<const char*>(public_value_), kKeySize), | |
| signature_verification_dev_flag_); | |
| Status status = | |
| verifier.Verify(std::string(message, strlen(message)), | |
| std::string(reinterpret_cast<const char*>(signature), | |
| kSignatureSize - 1)); | |
| EXPECT_THAT(status.code(), Eq(error::FAILED_PRECONDITION)); | |
| EXPECT_THAT(status.message(), HasSubstr("Wrong signature size")); | |
| // Verify the signature - mismatch. | |
| signature[0] = ~signature[0]; | |
| status = verifier.Verify( | |
| std::string(message, strlen(message)), | |
| std::string(reinterpret_cast<const char*>(signature), kSignatureSize)); | |
| EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT)); | |
| EXPECT_THAT(status.message(), HasSubstr("Verification failed")); | |
| } | |
| TEST_F(VerificationTest, SignAndFailBadPublicKey) { | |
| static constexpr char message[] = "ABCDEF 012345"; | |
| // Sign the message. | |
| uint8_t signature[kSignatureSize]; | |
| test::SignMessage(private_key_, message, signature); | |
| // Verify the public key - wrong length. | |
| SignatureVerifier verifier( | |
| std::string(reinterpret_cast<const char*>(public_value_), kKeySize - 1), | |
| signature_verification_dev_flag_); | |
| Status status = verifier.Verify( | |
| std::string(message, strlen(message)), | |
| std::string(reinterpret_cast<const char*>(signature), kSignatureSize)); | |
| EXPECT_THAT(status.code(), Eq(error::FAILED_PRECONDITION)); | |
| EXPECT_THAT(status.message(), HasSubstr("Wrong public key size")); | |
| // Verify the public key - mismatch. | |
| public_value_[0] = ~public_value_[0]; | |
| SignatureVerifier verifier2( | |
| std::string(reinterpret_cast<const char*>(public_value_), kKeySize), | |
| signature_verification_dev_flag_); | |
| status = verifier2.Verify( | |
| std::string(message, strlen(message)), | |
| std::string(reinterpret_cast<const char*>(signature), kSignatureSize)); | |
| EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT)); | |
| EXPECT_THAT(status.message(), HasSubstr("Verification failed")); | |
| } | |
| TEST_F(VerificationTest, ValidateFixedKey) { | |
| // |dev_data_to_sign| is signed on DEV server, producing | |
| // |dev_server_signature|. | |
| static constexpr uint8_t dev_data_to_sign[] = { | |
| 0x4D, 0x22, 0x5C, 0x4C, 0x74, 0x23, 0x82, 0x80, 0x58, 0xA2, 0x31, 0xA2, | |
| 0xC6, 0xE2, 0x6D, 0xDA, 0x48, 0x82, 0x7A, 0x9C, 0xF7, 0xD0, 0x4A, 0xF2, | |
| 0xFD, 0x19, 0x03, 0x7F, 0xC5, 0x6F, 0xBB, 0x49, 0xAF, 0x91, 0x7B, 0x74}; | |
| static constexpr uint8_t dev_server_signature[kSignatureSize] = { | |
| 0x0C, 0xA4, 0xAF, 0xE3, 0x27, 0x06, 0xD1, 0x4F, 0x0E, 0x05, 0x44, | |
| 0x74, 0x0D, 0x4F, 0xA0, 0x4C, 0x26, 0xB1, 0x0C, 0x44, 0x92, 0x0F, | |
| 0x96, 0xAF, 0x5A, 0x7E, 0x45, 0xED, 0x61, 0xB7, 0x87, 0xA8, 0xA3, | |
| 0x98, 0x52, 0x97, 0x8D, 0x56, 0xA3, 0xED, 0xF7, 0x9B, 0x54, 0x17, | |
| 0x61, 0x32, 0x6C, 0x06, 0x29, 0xBF, 0x30, 0x4E, 0x88, 0x72, 0xAB, | |
| 0xE3, 0x60, 0xDA, 0xF0, 0x37, 0xEB, 0x56, 0x28, 0x0B}; | |
| // |prod_data_to_sign| is signed on PROD server, producing | |
| // |prod_server_signature|. | |
| static constexpr uint8_t prod_data_to_sign[] = { | |
| 0xB3, 0xF9, 0xA3, 0xCC, 0xEB, 0x42, 0x88, 0x6b, 0x3f, 0x7b, 0x93, 0xC3, | |
| 0xD3, 0x61, 0x9C, 0x45, 0xB4, 0xD7, 0x4B, 0x7B, 0x4F, 0xA7, 0x1A, 0x29, | |
| 0xE1, 0x95, 0x14, 0xA4, 0x8C, 0x21, 0x36, 0x9F, 0x34, 0xA7, 0x4A, 0x57}; | |
| static constexpr uint8_t prod_server_signature[kSignatureSize] = { | |
| 0x17, 0xA4, 0x18, 0xA3, 0x78, 0x7A, 0x75, 0x24, 0xD9, 0x81, 0x3D, | |
| 0x9F, 0x17, 0x28, 0x40, 0xD8, 0xE7, 0x67, 0x88, 0x17, 0x44, 0x7C, | |
| 0xC2, 0x1A, 0xE2, 0x73, 0xAC, 0xB1, 0x0B, 0xCE, 0x60, 0xBB, 0x30, | |
| 0x58, 0xCE, 0xF6, 0x8E, 0x33, 0xB6, 0xC6, 0x18, 0x3C, 0xA7, 0xD4, | |
| 0x38, 0x91, 0x90, 0x2C, 0xBC, 0xB9, 0x76, 0x3C, 0xFF, 0x6F, 0x84, | |
| 0xEC, 0x2D, 0x1E, 0x73, 0x43, 0x1B, 0x75, 0x5E, 0x0E}; | |
| std::string dev_data_string = | |
| std::string(reinterpret_cast<const char*>(dev_data_to_sign), | |
| sizeof(dev_data_to_sign)); | |
| std::string prod_data_string = | |
| std::string(reinterpret_cast<const char*>(prod_data_to_sign), | |
| sizeof(prod_data_to_sign)); | |
| std::string dev_signature_string = std::string( | |
| reinterpret_cast<const char*>(dev_server_signature), kSignatureSize); | |
| std::string prod_signature_string = std::string( | |
| reinterpret_cast<const char*>(prod_server_signature), kSignatureSize); | |
| SignatureVerifier verifier(SignatureVerifier::VerificationKey(), | |
| signature_verification_dev_flag_); | |
| Status status = verifier.Verify(dev_data_string, dev_signature_string); | |
| // Dev disabled, dev signed data should fail verification. | |
| EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT)); | |
| EXPECT_THAT(status.message(), HasSubstr("Verification failed")); | |
| status = verifier.Verify(prod_data_string, prod_signature_string); | |
| // Dev disabled, prod signed data should pass verification. | |
| EXPECT_OK(status) << status; | |
| // Flip flag. | |
| signature_verification_dev_flag_->SetValue(/*is_enabled=*/true); | |
| status = verifier.Verify(dev_data_string, dev_signature_string); | |
| // Dev enabled, dev signed data should pass verification. | |
| EXPECT_OK(status) << status; | |
| status = verifier.Verify(prod_data_string, prod_signature_string); | |
| // Dev enabled, prod signed data should fail verification. | |
| EXPECT_THAT(status.code(), Eq(error::INVALID_ARGUMENT)); | |
| EXPECT_THAT(status.message(), HasSubstr("Verification failed")); | |
| } | |
| } // namespace | |
| } // namespace reporting |