Code Drop Two (Update One)
This is the second code drop for the white-box api reference implementation and tests. This corrects the errors in the license white-box reference implementation and implements the remaining test cases. It should be noted that there is one test case missing, the test case for handling ChromeOS's unique policy settings. In order to make the tests easier to create and read, a license builder class was created and golden content and keys were wrapped in their own classes. How key errors are communicated was changed in the API. WB_RESULT_NO_SUCH_KEY and WB_RESULT_WRONG_KEY_TYPE were merged into WB_RESULT_KEY_UNAVAILABLE.
This commit is contained in:
@@ -5,148 +5,221 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "api/golden_data.h"
|
||||
#include "api/license_builder.h"
|
||||
#include "api/license_whitebox_test_base.h"
|
||||
#include "api/test_data.h"
|
||||
#include "crypto_utils/rsa_key.h"
|
||||
#include "testing/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
namespace widevine {
|
||||
|
||||
class LicenseWhiteboxGetSecretStringTest : public ::testing::Test {
|
||||
class LicenseWhiteboxGetSecretStringTest : public LicenseWhiteboxTestBase {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
LicenseWhiteboxTestBase::SetUp();
|
||||
|
||||
// The secret string size is implementation specific, so this number just
|
||||
// needs to be reasonably large to accommodate different implementations.
|
||||
secret_string_size_ = 256;
|
||||
secret_string_.resize(secret_string_size_);
|
||||
|
||||
const std::vector<uint8_t> init_data = GetLicenseInitData();
|
||||
|
||||
ASSERT_EQ(WB_License_Create(init_data.data(), init_data.size(), &whitebox_),
|
||||
WB_RESULT_OK);
|
||||
ASSERT_TRUE(whitebox_);
|
||||
golden_data_.MakeKeyIdDifferent(&non_content_key_id_);
|
||||
golden_data_.MakeKeyIdDifferent(&missing_key_id_);
|
||||
}
|
||||
|
||||
void TearDown() override { WB_License_Delete(whitebox_); }
|
||||
|
||||
void LoadLicense() {
|
||||
// TODO: We will need to load a license for most tests as they will require
|
||||
// a key id look-up and we get keys from licenses.
|
||||
LicenseBuilder builder;
|
||||
|
||||
builder.AddContentKey(golden_data_.CBCCryptoKey().level,
|
||||
golden_data_.CBCCryptoKey().id,
|
||||
golden_data_.CBCCryptoKey().content->key);
|
||||
|
||||
builder.AddContentKey(golden_data_.CBCDecodeKey().level,
|
||||
golden_data_.CBCDecodeKey().id,
|
||||
golden_data_.CBCDecodeKey().content->key);
|
||||
|
||||
builder.AddContentKey(golden_data_.CBCHardwareKey().level,
|
||||
golden_data_.CBCHardwareKey().id,
|
||||
golden_data_.CBCHardwareKey().content->key);
|
||||
|
||||
builder.AddOperatorSessionKey(non_content_key_id_);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO: These needs to be replaced with the actual keys in the loaded
|
||||
// license.
|
||||
const std::vector<uint8_t> crypto_key_id_ = {1, 2, 3};
|
||||
const std::vector<uint8_t> hardware_key_id_ = {2, 3, 4};
|
||||
const std::vector<uint8_t> bad_key_id_ = {3, 4, 5};
|
||||
const std::vector<uint8_t> non_content_key_id_ = {4, 5, 6};
|
||||
// We need two special keys for this test, one that will be used for a
|
||||
// non-content key and one that will never be in the license.
|
||||
std::vector<uint8_t> non_content_key_id_ = {0, 0, 0};
|
||||
std::vector<uint8_t> missing_key_id_ = {1, 0, 0};
|
||||
|
||||
size_t secret_string_size_;
|
||||
std::vector<uint8_t> secret_string_;
|
||||
|
||||
WB_License_Whitebox* whitebox_;
|
||||
};
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, Success) {
|
||||
// TODO: This test needs to be skipped right now because we can't load a
|
||||
// license and we need a license to have key ids.
|
||||
GTEST_SKIP();
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCBCWithCryptoKey) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
crypto_key_id_.data(), crypto_key_id_.size(),
|
||||
golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_OK);
|
||||
secret_string_.resize(secret_string_size_);
|
||||
ASSERT_GT(secret_string_.size(), 0);
|
||||
ASSERT_GT(secret_string_size_, 0);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCTRWithCryptoKey) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CTR,
|
||||
golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_OK);
|
||||
ASSERT_GT(secret_string_size_, 0);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCBCWithDecodeKey) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
golden_data_.CBCDecodeKey().id.data(),
|
||||
golden_data_.CBCDecodeKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_OK);
|
||||
ASSERT_GT(secret_string_size_, 0);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, SuccessForCTRWithDecodeKey) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CTR,
|
||||
golden_data_.CBCDecodeKey().id.data(),
|
||||
golden_data_.CBCDecodeKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_OK);
|
||||
ASSERT_GT(secret_string_size_, 0);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidParameterForNullWhitebox) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(nullptr, WB_CIPHER_MODE_CBC,
|
||||
crypto_key_id_.data(), crypto_key_id_.size(),
|
||||
golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest,
|
||||
InvalidParameterForInvalidCipherMode) {
|
||||
LoadLicense();
|
||||
|
||||
// In order to trick the compiler into letting us pass an invalid enum value
|
||||
// to WB__License_Decrypt(), we need to cast it. If we don't do this, the
|
||||
// compiler tries to save us.
|
||||
const WB_CipherMode invalid_mode = static_cast<WB_CipherMode>(0xFF);
|
||||
|
||||
ASSERT_EQ(WB_License_GetSecretString(
|
||||
whitebox_, invalid_mode, golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(), secret_string_.data(),
|
||||
&secret_string_size_),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidParameterForNullKeyId) {
|
||||
LoadLicense();
|
||||
ASSERT_EQ(WB_License_GetSecretString(
|
||||
whitebox_, WB_CIPHER_MODE_CBC, nullptr, crypto_key_id_.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC, nullptr,
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidParameterForZeroKeyIdSize) {
|
||||
LoadLicense();
|
||||
ASSERT_EQ(WB_License_GetSecretString(
|
||||
whitebox_, WB_CIPHER_MODE_CBC, crypto_key_id_.data(), 0,
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
golden_data_.CBCCryptoKey().id.data(), 0,
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest,
|
||||
InvalidParameterForNullSecretString) {
|
||||
LoadLicense();
|
||||
ASSERT_EQ(WB_License_GetSecretString(
|
||||
whitebox_, WB_CIPHER_MODE_CBC, crypto_key_id_.data(),
|
||||
crypto_key_id_.size(), nullptr, &secret_string_size_),
|
||||
|
||||
ASSERT_EQ(WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
nullptr, &secret_string_size_),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest,
|
||||
InvalidParameterForNullSecretStringSize) {
|
||||
LoadLicense();
|
||||
ASSERT_EQ(WB_License_GetSecretString(
|
||||
whitebox_, WB_CIPHER_MODE_CBC, crypto_key_id_.data(),
|
||||
crypto_key_id_.size(), secret_string_.data(), nullptr),
|
||||
|
||||
ASSERT_EQ(WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
secret_string_.data(), nullptr),
|
||||
WB_RESULT_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, NoSuchKey) {
|
||||
// TODO: This test needs to be skipped right now because we can't load a
|
||||
// license and we need a license to have key ids.
|
||||
GTEST_SKIP();
|
||||
|
||||
// For this test, "missing key id" specifically means a key id that was never
|
||||
// in the license to start with. This is different than "non content key"
|
||||
// and "dropped content key", as those keys were in the license but ignored.
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, KeyUnavailableForMissingKeyId) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
bad_key_id_.data(), bad_key_id_.size(),
|
||||
missing_key_id_.data(), missing_key_id_.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_NO_SUCH_KEY);
|
||||
WB_RESULT_KEY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, WrongKeyType) {
|
||||
// TODO: This test needs to be skipped right now because we can't load a
|
||||
// license and we need a license to have key ids.
|
||||
GTEST_SKIP();
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, KeyUnavailableForNonContentKey) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(WB_License_GetSecretString(
|
||||
whitebox_, WB_CIPHER_MODE_CBC, non_content_key_id_.data(),
|
||||
non_content_key_id_.size(), secret_string_.data(),
|
||||
&secret_string_size_),
|
||||
WB_RESULT_NO_SUCH_KEY);
|
||||
WB_RESULT_KEY_UNAVAILABLE);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, InsufficientSecurityLevel) {
|
||||
// TODO: This test needs to be skipped right now because we can't load a
|
||||
// license and we need a license to have key ids.
|
||||
GTEST_SKIP();
|
||||
|
||||
// Under normal circumstances, a hardware key should be dropped. The exception
|
||||
// to this rule is on ChromeOS with a special license.
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest,
|
||||
InsufficientSecurityLevelForHardwareContentKey) {
|
||||
LoadLicense();
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(
|
||||
whitebox_, WB_CIPHER_MODE_CBC, hardware_key_id_.data(),
|
||||
hardware_key_id_.size(), secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_NO_SUCH_KEY);
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
golden_data_.CBCHardwareKey().id.data(),
|
||||
golden_data_.CBCHardwareKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_INSUFFICIENT_SECURITY_LEVEL);
|
||||
}
|
||||
|
||||
TEST_F(LicenseWhiteboxGetSecretStringTest, BufferTooSmall) {
|
||||
// TODO: This test needs to be skipped right now because we can't load a
|
||||
// license and we need a license to have key ids.
|
||||
GTEST_SKIP();
|
||||
|
||||
LoadLicense();
|
||||
|
||||
// Since the secret string is implementation specific, we don't want to make
|
||||
@@ -156,7 +229,8 @@ TEST_F(LicenseWhiteboxGetSecretStringTest, BufferTooSmall) {
|
||||
secret_string_size_ = 1;
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
crypto_key_id_.data(), crypto_key_id_.size(),
|
||||
golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_BUFFER_TOO_SMALL);
|
||||
|
||||
@@ -172,9 +246,10 @@ TEST_F(LicenseWhiteboxGetSecretStringTest, InvalidState) {
|
||||
|
||||
ASSERT_EQ(
|
||||
WB_License_GetSecretString(whitebox_, WB_CIPHER_MODE_CBC,
|
||||
crypto_key_id_.data(), crypto_key_id_.size(),
|
||||
golden_data_.CBCCryptoKey().id.data(),
|
||||
golden_data_.CBCCryptoKey().id.size(),
|
||||
secret_string_.data(), &secret_string_size_),
|
||||
WB_RESULT_INVALID_STATE);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace widevine
|
||||
|
||||
Reference in New Issue
Block a user