// Copyright 2020 Google LLC. All Rights Reserved. #include "api/license_whitebox.h" #include #include #include #include "api/license_whitebox_test_base.h" #include "api/test_data.h" #include "api/test_license_builder.h" #include "crypto_utils/crypto_util.h" #include "crypto_utils/rsa_key.h" #include "testing/gtest/include/gtest/gtest.h" namespace widevine { class LicenseWhiteboxVerifyRenewalResponseTest : public LicenseWhiteboxTestBase { protected: void SetUp() override { LicenseWhiteboxTestBase::SetUp(); garbage_renewal_signature_ = Sign(garbage_renewal_message_); } void LoadLicense(const std::vector& padding) { const auto signing_key = TestLicenseBuilder::DefaultSigningKey(); // We need a license so that we can always have a valid signature for our // message(s), but don't load the license as some test will need no // license loaded. TestLicenseBuilder builder; builder.AddSigningKey(signing_key, padding); builder.AddStubbedContentKey(); License license; builder.Build(*public_key_, &license); ASSERT_EQ(WB_License_ProcessLicenseResponse( whitebox_, license.message.data(), license.message.size(), license.signature.data(), license.signature.size(), license.session_key.data(), license.session_key.size(), license.request.data(), license.request.size()), WB_RESULT_OK); } std::vector Sign(const std::vector& message) { const auto key = TestLicenseBuilder::DefaultSigningKey(); // The server signing key is the first half of the signing key. std::string server_key = std::string( key.begin(), key.begin() + crypto_util::kSigningKeySizeBytes); const auto signature = crypto_util::CreateSignatureHmacSha256( server_key, std::string(message.begin(), message.end())); return std::vector(signature.begin(), signature.end()); } // Allow this to be mutable so that a test can corrupt it. This data is random // and has no meaning. std::vector garbage_renewal_message_ = { 0xf1, 0x5c, 0xf1, 0x92, 0x73, 0x0c, 0xf9, 0x5d, 0x2b, 0x1e, 0x3f, 0x51, 0xb2, 0x75, 0xa1, 0xb3, 0xd3, 0xa8, 0x16, 0x83, 0x08, 0xf1, 0xe2, 0x47, 0x7b, 0x80, 0x37, 0xed, 0xf8, 0x8b, 0x1d, 0x79, 0x7f, 0xb0, 0xa1, 0xde, 0xcd, 0xba, 0xd4, 0x8f, 0xb7, 0x3c, 0x1a, 0x3f, 0x3e, 0x3a, 0xb4, 0xea, 0xd8, 0xd7, 0xa4, 0x65, 0xa1, 0x40, 0x87, 0xf6, 0xaa, 0xf4, 0xb1, 0x24, 0x17, 0xed, 0xf4, 0xca, 0x18, 0x51, 0x4a, 0x54, 0x3c, 0x73, 0xca, 0x45, 0x3e, 0xef, 0x39, 0x49, 0x65, 0xdd, 0x62, 0x11, 0x99, 0x13, 0x40, 0x67, 0x7f, 0xfb, 0x07, 0x09, 0x1e, 0xfe, 0x0e, 0xdc, 0xda, 0x0a, 0x85, 0x91, 0x15, 0x40, 0xa8, 0x7a, 0x0e, 0x76, 0xf6, 0xbe, 0x94, 0x2c, 0x70, 0xe9, 0x07, 0xea, 0xf8, 0x7a, 0xc3, 0x48, 0xe1, 0xcf, 0xf4, 0x7b, 0xd6, 0x27, 0xd7, 0x30, 0x6f, 0x18, 0xb3, 0x2d, 0x6a, 0x23, }; // Allow this to be mutable so that we can initialize it in SetUp() but also // so a test can corrupt it. std::vector garbage_renewal_signature_; }; // TODO: Implement a test that uses a real serialized response. Once we have a // real serialized response, we should update all the tests - except the // SuccessForGarbageMessage - to use the real serialized response. TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, SuccessForGarbageMessage) { LoadLicense(TestLicenseBuilder::NoPadding()); ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_OK); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, SuccessWithSigningKeyPKSC8Padding) { LoadLicense(TestLicenseBuilder::PKSC8Padding()); ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_OK); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidParameterForNullWhitebox) { LoadLicense(TestLicenseBuilder::NoPadding()); ASSERT_EQ( WB_License_VerifyRenewalResponse(nullptr, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_INVALID_PARAMETER); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidParameterForNullMessage) { LoadLicense(TestLicenseBuilder::NoPadding()); ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, nullptr, garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_INVALID_PARAMETER); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidParameterForZeroMessageSize) { LoadLicense(TestLicenseBuilder::NoPadding()); ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, garbage_renewal_message_.data(), 0, garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_INVALID_PARAMETER); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidParameterForNullSignature) { LoadLicense(TestLicenseBuilder::NoPadding()); ASSERT_EQ(WB_License_VerifyRenewalResponse( whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), nullptr, garbage_renewal_signature_.size()), WB_RESULT_INVALID_PARAMETER); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidParameterForInvalidSignatureSize) { LoadLicense(TestLicenseBuilder::NoPadding()); ASSERT_EQ(WB_License_VerifyRenewalResponse( whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), 14), WB_RESULT_INVALID_PARAMETER); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidSignatureForModifiedMessage) { LoadLicense(TestLicenseBuilder::NoPadding()); Modify(&garbage_renewal_message_); ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_INVALID_SIGNATURE); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidSignatureForModifiedSignature) { LoadLicense(TestLicenseBuilder::NoPadding()); Modify(&garbage_renewal_signature_); ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_INVALID_SIGNATURE); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidStateForNoLicense) { // Unlike the other tests, we do not call LoadLicense() as the criteria for // WB_RESULT_INVALID_STATE is that no key can be found and keys are provided // via a license. ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_INVALID_STATE); } TEST_F(LicenseWhiteboxVerifyRenewalResponseTest, InvalidStateForNoSigningKey) { // Create a license with no signing key and one content key (every license // must have a content key). widevine::TestLicenseBuilder builder; builder.AddStubbedContentKey(); License license; builder.Build(*public_key_, &license); ASSERT_EQ(WB_License_ProcessLicenseResponse( whitebox_, license.message.data(), license.message.size(), license.signature.data(), license.signature.size(), license.session_key.data(), license.session_key.size(), license.request.data(), license.request.size()), WB_RESULT_OK); ASSERT_EQ(WB_License_VerifyRenewalResponse(whitebox_, garbage_renewal_message_.data(), garbage_renewal_message_.size(), garbage_renewal_signature_.data(), garbage_renewal_signature_.size()), WB_RESULT_INVALID_STATE); } } // namespace widevine