This adds: - Requires WB_RESULT_NOT_IMPLEMENTED for masked in CE - WB_License_RemoveEntitledContentKey - WB_License_Generic* methods
649 lines
27 KiB
C++
649 lines
27 KiB
C++
// Copyright 2020 Google LLC. All Rights Reserved.
|
|
|
|
#include "api/license_whitebox.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "api/golden_data.h"
|
|
#include "api/license_whitebox_test_base.h"
|
|
#include "api/test_license_builder.h"
|
|
#include "crypto_utils/rsa_key.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace widevine {
|
|
namespace {
|
|
|
|
using Padding = TestLicenseBuilder::Padding;
|
|
|
|
const size_t kValidProviderKeyId1 = 1;
|
|
const size_t kValidProviderKeyId2 = 2;
|
|
const size_t kInvalidProviderKeyId = 0xfff;
|
|
// There is also kNoProviderKeyId specified in test_license_builder.
|
|
|
|
} // namespace
|
|
|
|
class LicenseWhiteboxDecryptTest
|
|
: public LicenseWhiteboxTestBase,
|
|
public ::testing::WithParamInterface<std::tuple<Padding, size_t>> {
|
|
protected:
|
|
void SetUp() override {
|
|
LicenseWhiteboxTestBase::SetUp();
|
|
|
|
// Because we are using the same buffer for both CTR and CBC, need to make
|
|
// sure that it is large enough for either one.
|
|
plaintext_size_ = std::max(golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CTRContent().ciphertext.size());
|
|
plaintext_.resize(plaintext_size_);
|
|
|
|
non_content_key_id_ = golden_data_.GetFreeId();
|
|
missing_key_id_ = golden_data_.GetFreeId();
|
|
|
|
padding_ = std::get<0>(GetParam());
|
|
provider_key_id_ = std::get<1>(GetParam());
|
|
}
|
|
|
|
// Creates and loads a license. The license is created using |settings|
|
|
// updated to include the test parameters. The license is loaded using
|
|
// |provider_key_id|.
|
|
bool LoadLicense(const TestLicenseBuilder::Settings& settings,
|
|
size_t provider_key_id) {
|
|
TestLicenseBuilder builder;
|
|
builder.SetSettings(settings);
|
|
|
|
// Update settings with the test specified parameters.
|
|
builder.GetSettings().padding = padding_;
|
|
builder.GetSettings().provider_key_id = provider_key_id_;
|
|
|
|
builder.AddContentKey(golden_data_.CBCContent().software_crypto_key);
|
|
builder.AddContentKey(golden_data_.CBCContent().software_decode_key);
|
|
builder.AddContentKey(golden_data_.CBCContent().hardware_key);
|
|
|
|
builder.AddContentKey(golden_data_.CTRContent().software_crypto_key);
|
|
|
|
builder.AddOperatorSessionKey(non_content_key_id_);
|
|
|
|
auto server = TestServer::CreateDualKey();
|
|
|
|
License license;
|
|
builder.Build(*server, &license);
|
|
|
|
const auto result = WB_License_ProcessLicenseResponse(
|
|
whitebox_, WB_LICENSE_KEY_MODE_DUAL_KEY, 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(), provider_key_id, license.request.data(),
|
|
license.request.size());
|
|
#ifndef HAS_PROVIDER_KEYS
|
|
if (provider_key_id != 0 && result == WB_RESULT_NOT_IMPLEMENTED)
|
|
return false;
|
|
#endif
|
|
EXPECT_EQ(result, WB_RESULT_OK);
|
|
return true;
|
|
}
|
|
|
|
// 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.
|
|
KeyId non_content_key_id_;
|
|
KeyId missing_key_id_;
|
|
|
|
// This is the buffer used to store the output of each decrypt call.
|
|
size_t plaintext_size_;
|
|
std::vector<uint8_t> plaintext_;
|
|
|
|
Padding padding_;
|
|
size_t provider_key_id_;
|
|
};
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataInCbcMode) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InPlaceDecryptionCbc) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
memcpy(plaintext_.data(), golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size());
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
plaintext_.data(), plaintext_.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataInCtrMode) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CTR,
|
|
golden_data_.CTRContent().software_crypto_key.id.data(),
|
|
golden_data_.CTRContent().software_crypto_key.id.size(),
|
|
golden_data_.CTRContent().ciphertext.data(),
|
|
golden_data_.CTRContent().ciphertext.size(),
|
|
golden_data_.CTRContent().iv.data(),
|
|
golden_data_.CTRContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InPlaceDecryptionCtr) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
memcpy(plaintext_.data(), golden_data_.CTRContent().ciphertext.data(),
|
|
golden_data_.CTRContent().ciphertext.size());
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CTR,
|
|
golden_data_.CTRContent().software_crypto_key.id.data(),
|
|
golden_data_.CTRContent().software_crypto_key.id.size(),
|
|
plaintext_.data(), plaintext_.size(),
|
|
golden_data_.CTRContent().iv.data(),
|
|
golden_data_.CTRContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
|
|
}
|
|
|
|
// We try to decrypt CBC encrypted data in CTR mode. All operations should be
|
|
// successful, but the resulting plaintext should not match.
|
|
TEST_P(LicenseWhiteboxDecryptTest, CryptoKeyWithCbcDataInCtrMode) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CTR,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_NE(plaintext_, golden_data_.CBCContent().plaintext);
|
|
}
|
|
|
|
// We try to decrypt CTR encrypted data in CBC mode. All operations should be
|
|
// successful, but the resulting plaintext should not match.
|
|
TEST_P(LicenseWhiteboxDecryptTest, CryptoKeyWithCtrDataInCbcMode) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CTRContent().software_crypto_key.id.data(),
|
|
golden_data_.CTRContent().software_crypto_key.id.size(),
|
|
golden_data_.CTRContent().ciphertext.data(),
|
|
golden_data_.CTRContent().ciphertext.size(),
|
|
golden_data_.CTRContent().iv.data(),
|
|
golden_data_.CTRContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_NE(plaintext_, golden_data_.CTRContent().plaintext);
|
|
}
|
|
|
|
// Try decrypting two different sets of content to make sure that two
|
|
// different keys can be used at the same time.
|
|
TEST_P(LicenseWhiteboxDecryptTest, SuccessWithMultipleKeys) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_EQ(plaintext_, golden_data_.CBCContent().plaintext);
|
|
|
|
// Reset our output buffer.
|
|
plaintext_.clear();
|
|
plaintext_size_ = golden_data_.CTRContent().plaintext.size();
|
|
plaintext_.resize(plaintext_size_);
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CTR,
|
|
golden_data_.CTRContent().software_crypto_key.id.data(),
|
|
golden_data_.CTRContent().software_crypto_key.id.size(),
|
|
golden_data_.CTRContent().ciphertext.data(),
|
|
golden_data_.CTRContent().ciphertext.size(),
|
|
golden_data_.CTRContent().iv.data(),
|
|
golden_data_.CTRContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_EQ(plaintext_, golden_data_.CTRContent().plaintext);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForNullWhitebox) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
nullptr, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidCipherMode) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
// 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_Decrypt(
|
|
whitebox_, invalid_mode,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForNullKeyId) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC, nullptr,
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForZeroKeyIdSize) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(), 0,
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForNullInputData) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
nullptr, golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
// AES CBC requires that the input be block aligned (multiple of 16). CTR does
|
|
// not care.
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidCBCInputDataSize) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(), 14,
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
// The white-box (using any cipher mode) should reject input with size zero.
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForZeroInputDataSize) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(), 0,
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForNullIV) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(), nullptr,
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
// IV size should be 16. Any number other than 16 should fail.
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForInvalidIVSize) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(), 9, plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForNullOutput) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), nullptr, &plaintext_size_),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidParameterForNullOutputSize) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(
|
|
WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(), nullptr),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
// 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_P(LicenseWhiteboxDecryptTest, KeyUnavailableForMissingKeyId) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
|
|
missing_key_id_.data(), missing_key_id_.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(),
|
|
plaintext_.data(), &plaintext_size_),
|
|
WB_RESULT_KEY_UNAVAILABLE);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, KeyUnavailableForNonContentKey) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(
|
|
WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
|
|
non_content_key_id_.data(), non_content_key_id_.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_KEY_UNAVAILABLE);
|
|
}
|
|
|
|
// Under normal circumstances, a hardware key should be dropped. The exception
|
|
// to this rule is on ChromeOS with a special license.
|
|
TEST_P(LicenseWhiteboxDecryptTest,
|
|
InsufficientSecurityLevelForHardwareContentKey) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().hardware_key.id.data(),
|
|
golden_data_.CBCContent().hardware_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(),
|
|
plaintext_.data(), &plaintext_size_),
|
|
WB_RESULT_INSUFFICIENT_PERMISSIONS);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InsufficientSecurityLevelForDecodeKey) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
// Use the software decode key as they are limited to
|
|
// WB_License_Decrypt().
|
|
#ifdef ALWAYS_DECRYPT_TO_CLEAR
|
|
const auto expected = WB_RESULT_OK;
|
|
#else
|
|
const auto expected = WB_RESULT_INSUFFICIENT_PERMISSIONS;
|
|
#endif
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_decode_key.id.data(),
|
|
golden_data_.CBCContent().software_decode_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
expected);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, BufferTooSmall) {
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
// Our ciphertext will be large enough that we should not need to worry about
|
|
// using a constant here.
|
|
plaintext_size_ = 8;
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_BUFFER_TOO_SMALL);
|
|
|
|
// We don't use padding so the reported plaintext size should be the same as
|
|
// the cipher text size.
|
|
ASSERT_EQ(plaintext_size_, golden_data_.CBCContent().ciphertext.size());
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, InvalidState) {
|
|
// 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_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_INVALID_STATE);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxDecryptTest, KeyUnavailableForInvalidKey) {
|
|
// There are multiple ways for us to invalidate a content key. We have tests
|
|
// that test invalid keys (see the query content key status tests). But here,
|
|
// we just need an invalid key, so we use one way of invalidating the key.
|
|
TestLicenseBuilder::Settings settings;
|
|
settings.include_content_key_iv = false;
|
|
if (!LoadLicense(settings, provider_key_id_))
|
|
GTEST_SKIP();
|
|
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_KEY_UNAVAILABLE);
|
|
}
|
|
|
|
// For this test, we create a license using the test specified Provider Key
|
|
// Id, then load the license using a different Provider Key Id.
|
|
TEST_P(LicenseWhiteboxDecryptTest, MismatchProviderKeyId) {
|
|
// These tests use 2 valid provider key IDs, so try loading the license
|
|
// with a different key. Not all possible combinations are tested.
|
|
size_t other_provider_key_id = kInvalidProviderKeyId;
|
|
switch (provider_key_id_) {
|
|
case kNoProviderKeyId:
|
|
other_provider_key_id = kValidProviderKeyId1;
|
|
break;
|
|
case kValidProviderKeyId1:
|
|
other_provider_key_id = kValidProviderKeyId2;
|
|
break;
|
|
case kValidProviderKeyId2:
|
|
other_provider_key_id = kNoProviderKeyId;
|
|
break;
|
|
case kInvalidProviderKeyId:
|
|
// This is the same as kNoProviderKeyId, so use one of the valid ids.
|
|
other_provider_key_id = kValidProviderKeyId2;
|
|
break;
|
|
}
|
|
|
|
TestLicenseBuilder::Settings settings;
|
|
if (!LoadLicense(settings, other_provider_key_id))
|
|
GTEST_SKIP();
|
|
|
|
// Decryption should succeed, but the plaintext should be incorrect.
|
|
ASSERT_EQ(WB_License_Decrypt(
|
|
whitebox_, WB_CIPHER_MODE_CBC,
|
|
golden_data_.CBCContent().software_crypto_key.id.data(),
|
|
golden_data_.CBCContent().software_crypto_key.id.size(),
|
|
golden_data_.CBCContent().ciphertext.data(),
|
|
golden_data_.CBCContent().ciphertext.size(),
|
|
golden_data_.CBCContent().iv.data(),
|
|
golden_data_.CBCContent().iv.size(), plaintext_.data(),
|
|
&plaintext_size_),
|
|
WB_RESULT_OK);
|
|
plaintext_.resize(plaintext_size_);
|
|
ASSERT_NE(plaintext_, golden_data_.CBCContent().plaintext);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
NoPadding,
|
|
LicenseWhiteboxDecryptTest,
|
|
::testing::Combine(::testing::Values(Padding::kNone),
|
|
::testing::Values(kNoProviderKeyId,
|
|
kValidProviderKeyId1,
|
|
kValidProviderKeyId2,
|
|
kInvalidProviderKeyId)));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
PKSC8,
|
|
LicenseWhiteboxDecryptTest,
|
|
::testing::Combine(::testing::Values(Padding::kPKSC8),
|
|
::testing::Values(kNoProviderKeyId,
|
|
kValidProviderKeyId1,
|
|
kValidProviderKeyId2,
|
|
kInvalidProviderKeyId)));
|
|
} // namespace widevine
|