In this code drop we introduce the ODK dependency. The reference implementation has been updated to make use of the ODK and the related tests have been included. In addition, we have included an example of how a shared libraries can be created. This will allow make it easier to test and verify different implementations of the API. Most other changes introduce by this code drop were made to clean-up the reference implementation and limit dependencies.
233 lines
9.6 KiB
C++
233 lines
9.6 KiB
C++
// Copyright 2020 Google LLC. All Rights Reserved.
|
|
|
|
#include "api/license_whitebox.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#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<uint8_t>& 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.core_message.data(), license.core_message.size(),
|
|
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<uint8_t> Sign(const std::vector<uint8_t>& 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<uint8_t>(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<uint8_t> 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<uint8_t> 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.core_message.data(), license.core_message.size(),
|
|
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
|