In order to support both single-key and dual-key RSA implementations where single-key will use key 0 for both sign and encryption and where dual-key will use key 0 for sign and key 1 for encryption. Additional changes in this code drop: - Added VMP / RA override enabled tests - Added VMP / RA override disabled tests This brings the partner repo in sync with the internal repo at commit 71760b6da1ec546c65b56e2f86b39b73b53f6734.
275 lines
9.4 KiB
C++
275 lines
9.4 KiB
C++
// Copyright 2021 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 "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace widevine {
|
|
|
|
using OdkVersion = TestLicenseBuilder::OdkVersion;
|
|
using KeyControlBlock = TestLicenseBuilder::KeyControlBlock;
|
|
|
|
enum class LicenseParsing {
|
|
kUseProtobuf,
|
|
kUseOdk,
|
|
};
|
|
|
|
class LicenseWhiteboxQuerySigningKeyStatus
|
|
: public LicenseWhiteboxTestBase,
|
|
public testing::WithParamInterface<LicenseParsing> {
|
|
protected:
|
|
void SetUp() override {
|
|
LicenseWhiteboxTestBase::SetUp();
|
|
signing_key_ = TestLicenseBuilder::DefaultSigningKey();
|
|
|
|
license_parsing_ = GetParam();
|
|
}
|
|
|
|
void SetSettings(const TestLicenseBuilder::Settings& settings) {
|
|
builder_.SetSettings(settings);
|
|
}
|
|
|
|
void AddSigningKey() { builder_.AddSigningKey(signing_key_); }
|
|
|
|
WB_Result LoadLicense() {
|
|
// To use ODK, we need to use 16.5 (which should have a clear KCB). If we
|
|
// want to force Protobuf parsing, we just ned to have no ODK message and/or
|
|
// an encrypted KCB.
|
|
switch (license_parsing_) {
|
|
case LicenseParsing::kUseProtobuf:
|
|
builder_.GetSettings().odk_version = OdkVersion::kNone;
|
|
builder_.GetSettings().key_control_block = KeyControlBlock::kEncrypted;
|
|
break;
|
|
|
|
case LicenseParsing::kUseOdk:
|
|
builder_.GetSettings().odk_version = OdkVersion::k16_5;
|
|
builder_.GetSettings().key_control_block = KeyControlBlock::kClear;
|
|
break;
|
|
|
|
default:
|
|
// We can't use an assert here (wrong return type) so instead we'll
|
|
// return an error code.
|
|
return WB_RESULT_INVALID_PARAMETER;
|
|
}
|
|
|
|
// ODK requires there to be at least one content key or else it will fail
|
|
// to create the core message.
|
|
const auto& content_key = &golden_data_.CBCCryptoKey();
|
|
builder_.AddContentKey(content_key->level, content_key->id,
|
|
content_key->content->key);
|
|
|
|
auto server = TestServer::CreateDualKey();
|
|
|
|
License license;
|
|
builder_.Build(*server, &license);
|
|
|
|
return 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(), license.request.data(),
|
|
license.request.size());
|
|
}
|
|
|
|
private:
|
|
TestLicenseBuilder builder_;
|
|
TestLicenseBuilder::SigningKey signing_key_;
|
|
|
|
LicenseParsing license_parsing_;
|
|
};
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, ValidKey) {
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_SIGNING_KEY_VALID);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, NoKey) {
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_KEY_UNAVAILABLE);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, IgnoresContentKeyParams) {
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
// The key id value really does not matter. What matters is that it will be
|
|
// present and therefore the white-box should just ignore it since we are
|
|
// doing a signing key query.
|
|
const uint8_t key_id[] = {0x00, 0x01, 0x02, 0x03};
|
|
const size_t key_id_size = sizeof(key_id);
|
|
|
|
WB_KeyStatus key_state;
|
|
|
|
// Try every permutation of content key params (many invalid for content keys)
|
|
// to make sure that the signing key query ignores them.
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
key_id, key_id_size, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_SIGNING_KEY_VALID);
|
|
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
key_id, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_SIGNING_KEY_VALID);
|
|
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_SIGNING_KEY_VALID);
|
|
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, key_id_size, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_SIGNING_KEY_VALID);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, InvalidParameterForNullWhitebox) {
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(nullptr, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, InvalidParameterForNullKeyStatus) {
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, nullptr),
|
|
WB_RESULT_INVALID_PARAMETER);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, InvalidStateForNoLicense) {
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_INVALID_STATE);
|
|
}
|
|
|
|
// If there is no key type, ODK will assume that it is a signing key. So the
|
|
// protobuf parser should also do this. This is because protobuf will default
|
|
// to the first enum value when the value is missing.
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, ValidKeyForNoKeyType) {
|
|
TestLicenseBuilder::Settings settings;
|
|
settings.include_signing_key_type = false;
|
|
SetSettings(settings);
|
|
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_SIGNING_KEY_VALID);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, InvalidKeyForNoIv) {
|
|
TestLicenseBuilder::Settings settings;
|
|
settings.include_signing_key_iv = false;
|
|
SetSettings(settings);
|
|
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_INVALID);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, InvalidKeyForShortIv) {
|
|
TestLicenseBuilder::Settings settings;
|
|
settings.signing_key_iv_size = 7;
|
|
SetSettings(settings);
|
|
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_INVALID);
|
|
}
|
|
|
|
// The ODK will not write the key to the core message if there is no key data.
|
|
// This is odd, since it does not check any other fields.
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, KeyNotFoundForNoKeyData) {
|
|
TestLicenseBuilder::Settings settings;
|
|
settings.include_signing_key_key = false;
|
|
SetSettings(settings);
|
|
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_KEY_UNAVAILABLE);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, InvalidKeyForShortKeyData) {
|
|
TestLicenseBuilder::Settings settings;
|
|
settings.signing_key_key_size_override = true;
|
|
settings.signing_key_key_size = 7;
|
|
SetSettings(settings);
|
|
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_INVALID);
|
|
}
|
|
|
|
TEST_P(LicenseWhiteboxQuerySigningKeyStatus, InvalidKeyForLongKeyData) {
|
|
TestLicenseBuilder::Settings settings;
|
|
settings.signing_key_key_size_override = true;
|
|
settings.signing_key_key_size = 100;
|
|
SetSettings(settings);
|
|
|
|
AddSigningKey();
|
|
ASSERT_EQ(LoadLicense(), WB_RESULT_OK);
|
|
|
|
WB_KeyStatus key_state;
|
|
ASSERT_EQ(WB_License_QueryKeyStatus(whitebox_, WB_KEY_QUERY_TYPE_SIGNING_KEY,
|
|
nullptr, 0, &key_state),
|
|
WB_RESULT_OK);
|
|
ASSERT_EQ(key_state, WB_KEY_STATUS_INVALID);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(ProtbufParsing,
|
|
LicenseWhiteboxQuerySigningKeyStatus,
|
|
::testing::Values(LicenseParsing::kUseProtobuf));
|
|
|
|
INSTANTIATE_TEST_SUITE_P(OdkParsing,
|
|
LicenseWhiteboxQuerySigningKeyStatus,
|
|
::testing::Values(LicenseParsing::kUseOdk));
|
|
|
|
} // namespace widevine
|