Files
provisioning_sdk_source/common/security_profile_list_test.cc
2020-09-21 15:54:27 -07:00

365 lines
16 KiB
C++

////////////////////////////////////////////////////////////////////////////////
// Copyright 2020 Google LLC.
//
// This software is licensed under the terms defined in the Widevine Master
// License Agreement. For a copy of this agreement, please contact
// widevine-licensing@google.com.
////////////////////////////////////////////////////////////////////////////////
#include "common/security_profile_list.h"
#include "glog/logging.h"
#include "google/protobuf/util/message_differencer.h"
#include "testing/gmock.h"
#include "testing/gunit.h"
#include "absl/memory/memory.h"
#include "common/client_id_util.h"
#include "protos/public/device_common.pb.h"
#include "protos/public/device_security_profile_data.pb.h"
#include "protos/public/security_profile.pb.h"
namespace widevine {
namespace security_profile {
const char kMakeName[] = "company_name";
const char kMakeValue[] = "Google";
const char kModelName[] = "model_name";
const char kModelValue[] = "model1";
const char kDeviceNameValue[] = "TestDeviceName";
const char kProductNameValue[] = "TestProductName";
const char kBuildInfoValue[] = "TestBuildInfo";
const char kOemCryptoSecurityPatchLevelValue[] =
"TestOemCryptoSecurityPatchLevel";
const char kDefaultContentOwnerName[] = "Widevine";
const uint32_t kSystemId = 1234;
const uint32_t kSystemIdOverridden = 1567;
const uint32_t kResourceTierLow = 1;
const uint32_t kResourceTierMed = 2;
const uint32_t kResourceTierHigh = 3;
const uint64_t kStartTimeInSeconds = 5000;
const uint64_t kEndTimeInSeconds = 10000;
class SecurityProfileListTest : public ::testing::Test {
public:
SecurityProfileListTest() {}
~SecurityProfileListTest() override {}
void SetUp() override {
const uint32_t oemcrypto_12 = 12;
SecurityProfile profile;
std::string profile_namespace = "widevine";
profile_list_ = absl::make_unique<SecurityProfileList>(profile_namespace);
AddClientInfo(&client_id_, kMakeName, kMakeValue);
AddClientInfo(&client_id_, kModelName, kModelValue);
AddClientInfo(&client_id_, kModDrmDeviceName, kDeviceNameValue);
AddClientInfo(&client_id_, kModDrmProductName, kProductNameValue);
AddClientInfo(&client_id_, kModDrmBuildInfo, kBuildInfoValue);
AddClientInfo(&client_id_, kModDrmOemCryptoSecurityPatchLevel,
kOemCryptoSecurityPatchLevelValue);
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(
oemcrypto_12);
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V2_2);
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
kResourceTierHigh);
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_1);
device_info_.set_system_id(kSystemId);
}
std::unique_ptr<SecurityProfileList> profile_list_;
ClientIdentification client_id_;
ProvisionedDeviceInfo device_info_;
};
TEST_F(SecurityProfileListTest, InsertProfile) {
// Insert test profile1 into the list.
SecurityProfileList profile_list("widevine-test");
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_TRUE(profile_list.InsertProfile(profile1));
// Verify the list still has one profile.
EXPECT_EQ(1, profile_list.NumProfiles());
// Should not allow insert if existing profile has the same name.
SecurityProfile profile2;
profile2.set_name(profile1.name());
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
EXPECT_FALSE(profile_list.InsertProfile(profile2));
// Verify the list still has one profile.
EXPECT_EQ(1, profile_list.NumProfiles());
// Should allow insert since this profile has a different name.
profile2.set_name("profile2");
EXPECT_TRUE(profile_list.InsertProfile(profile2));
EXPECT_EQ(2, profile_list.NumProfiles());
}
TEST_F(SecurityProfileListTest, GetDrmInfo) {
SecurityProfile::DrmInfo drm_info;
DeviceModel* device_model = device_info_.add_model_info();
device_model->set_manufacturer(GetClientInfo(client_id_, kModDrmMake));
device_model->set_model_name(GetClientInfo(client_id_, kModDrmModel));
device_model->set_status(DeviceModel::MODEL_STATUS_VERIFIED);
const uint32_t model_launch_year = 2015;
device_model->set_model_year(model_launch_year);
ASSERT_TRUE(profile_list_->GetDrmInfo(client_id_, device_info_, &drm_info));
EXPECT_EQ(client_id_.client_capabilities().max_hdcp_version(),
drm_info.output().hdcp_version());
EXPECT_EQ(client_id_.client_capabilities().analog_output_capabilities(),
drm_info.output().analog_output_capabilities());
EXPECT_EQ(client_id_.client_capabilities().oem_crypto_api_version(),
drm_info.security().oemcrypto_api_version());
EXPECT_EQ(client_id_.client_capabilities().resource_rating_tier(),
drm_info.security().resource_rating_tier());
EXPECT_EQ(device_info_.security_level(),
drm_info.security().security_level());
EXPECT_EQ(device_info_.system_id(), drm_info.system_id());
EXPECT_EQ(kMakeValue, drm_info.request_model_info().manufacturer());
EXPECT_EQ(kModelValue, drm_info.request_model_info().model_name());
EXPECT_EQ(DeviceModel::MODEL_STATUS_VERIFIED,
drm_info.request_model_info().status());
EXPECT_EQ(model_launch_year, drm_info.request_model_info().model_year());
EXPECT_EQ(kDeviceNameValue, drm_info.client_info().device_name());
EXPECT_EQ(kProductNameValue,
drm_info.client_info().product_info().product_name());
EXPECT_EQ(kBuildInfoValue,
drm_info.client_info().product_info().build_info());
EXPECT_EQ(
kOemCryptoSecurityPatchLevelValue,
drm_info.client_info().product_info().oem_crypto_security_patch_level());
}
TEST_F(SecurityProfileListTest, QualifiedProfiles) {
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
profile1.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V1);
profile_list_->InsertProfile(profile1);
EXPECT_EQ(1, profile_list_->NumProfiles());
SecurityProfile profile2;
profile2.set_name("profile2");
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_1);
profile2.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V2);
profile_list_->InsertProfile(profile2);
EXPECT_EQ(2, profile_list_->NumProfiles());
// Both profiles should qualify based on client_info and device_info from the
// Setup function.
std::vector<std::string> qualified_profiles;
EXPECT_EQ(2, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile2.name()));
// Reduce the DRM capabilities of the device so profile2 will not qualify.
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
ClientCapabilities::HDCP_V1);
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
}
TEST_F(SecurityProfileListTest, DeviceExceptionImpactOnQualifiedProfiles) {
std::vector<std::string> qualified_profiles;
// Add device_exceptions to a profile and check the qualified profile.
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
profile1.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V1);
// Add one system_id in device blocked list.
DeviceException* device_exception = profile1.add_device_exceptions();
device_exception->set_system_id(kSystemId);
device_exception->set_action(DeviceException::DEVICE_EXCEPTION_BLOCK);
device_exception = profile1.add_device_exceptions();
// Add another system_id in device allowable list.
device_exception->set_system_id(kSystemIdOverridden);
device_exception->set_action(DeviceException::DEVICE_EXCEPTION_ALLOW);
profile_list_->InsertProfile(profile1);
EXPECT_EQ(profile_list_->NumProfiles(), 1);
// System_id of the current device is listed in the device exceptions with
// DEVICE_EXCEPTION_BLOCK label. So this profile can't be used for it.
EXPECT_EQ(profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles),
0);
EXPECT_EQ(std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()),
qualified_profiles.end());
// Reset the system id in the device info so that profile1 will be
// auto-qualified for the current device.
device_info_.set_system_id(kSystemIdOverridden);
ASSERT_EQ(profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles),
1);
EXPECT_NE(std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()),
qualified_profiles.end());
}
TEST_F(SecurityProfileListTest, GetQualifiedForInactiveDSPs) {
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
profile1.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V1);
profile1.set_owner("owner1");
int64_t current_time_seconds = time(nullptr);
// Set the start time one hour back.
profile1.mutable_control_time()->set_start_time_seconds(current_time_seconds -
3600);
// Set the end time one hour later.
profile1.mutable_control_time()->set_end_time_seconds(current_time_seconds +
3600);
profile_list_->InsertProfile(profile1);
ASSERT_EQ(1, profile_list_->NumProfiles());
std::vector<std::string> qualified_profiles;
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
SecurityProfile profile2;
profile2.set_name("profile2");
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_1);
profile2.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V2);
// Set the start time one hour later.
profile2.mutable_control_time()->set_start_time_seconds(current_time_seconds +
3600);
// Set the end time two hours later.
profile2.mutable_control_time()->set_end_time_seconds(current_time_seconds +
7200);
profile_list_->InsertProfile(profile2);
ASSERT_EQ(2, profile_list_->NumProfiles());
qualified_profiles.clear();
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
// Profile2 will be filtered out as it is an inactive profile.
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
SecurityProfile profile3;
profile3.set_name("profile3");
profile3.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_1);
profile3.mutable_min_output_requirements()->set_hdcp_version(
ClientCapabilities::HDCP_V2);
// Set the start time two hours back.
profile3.mutable_control_time()->set_start_time_seconds(current_time_seconds -
7200);
// Set the end time one hour back.
profile3.mutable_control_time()->set_end_time_seconds(current_time_seconds -
3600);
profile_list_->InsertProfile(profile3);
ASSERT_EQ(3, profile_list_->NumProfiles());
qualified_profiles.clear();
ASSERT_EQ(1, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
// Profile3 will be filtered out as it is an expired profile.
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
SecurityProfile profile4;
profile4.set_name("profile4");
profile4.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_2);
// Set the start time two hours back.
profile4.mutable_control_time()->set_start_time_seconds(current_time_seconds -
7200);
// Set the end time to 0 (never expired).
profile4.mutable_control_time()->set_end_time_seconds(0);
profile_list_->InsertProfile(profile4);
ASSERT_EQ(4, profile_list_->NumProfiles());
qualified_profiles.clear();
ASSERT_EQ(2, profile_list_->GetQualifiedProfiles(client_id_, device_info_,
&qualified_profiles));
// Profile4 will be listed in the qualified profiles.
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile1.name()));
EXPECT_NE(qualified_profiles.end(),
std::find(qualified_profiles.begin(), qualified_profiles.end(),
profile4.name()));
}
TEST_F(SecurityProfileListTest, FindProfile) {
SecurityProfileList profile_list("widevine-test");
SecurityProfile profile1;
profile1.set_name("profile1");
profile1.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
DeviceException* device_exception = profile1.add_device_exceptions();
device_exception->set_system_id(kSystemId);
device_exception->set_action(DeviceException::DEVICE_EXCEPTION_BLOCK);
device_exception = profile1.add_device_exceptions();
device_exception->set_system_id(kSystemIdOverridden);
device_exception->set_action(DeviceException::DEVICE_EXCEPTION_ALLOW);
EXPECT_EQ(kDefaultContentOwnerName, profile1.owner());
SecurityProfile profile2;
profile2.set_name("profile2");
profile2.mutable_min_security_requirements()->set_security_level(
ProvisionedDeviceInfo::LEVEL_3);
// Override the default owner name.
profile2.set_owner("owner2");
profile2.mutable_control_time()->set_start_time_seconds(kStartTimeInSeconds);
profile2.mutable_control_time()->set_end_time_seconds(kEndTimeInSeconds);
// Insert profiles 1 & 2.
EXPECT_TRUE(profile_list.InsertProfile(profile1));
EXPECT_TRUE(profile_list.InsertProfile(profile2));
EXPECT_EQ(2, profile_list.NumProfiles());
// Find the profile by its name.
SecurityProfile profile;
EXPECT_TRUE(profile_list.GetProfileByName(profile1.name(), &profile));
EXPECT_EQ(profile1.name(), profile.name());
EXPECT_EQ(profile1.level(), profile.level());
EXPECT_EQ(profile1.owner(), profile.owner());
// By default, security profile doesn't contain the control_dates field.
EXPECT_FALSE(profile1.has_control_time());
EXPECT_EQ(2, profile.device_exceptions().size());
EXPECT_EQ(kSystemId, profile.device_exceptions(0).system_id());
EXPECT_EQ(DeviceException::DEVICE_EXCEPTION_BLOCK,
profile.device_exceptions(0).action());
EXPECT_EQ(kSystemIdOverridden, profile.device_exceptions(1).system_id());
EXPECT_EQ(DeviceException::DEVICE_EXCEPTION_ALLOW,
profile.device_exceptions(1).action());
EXPECT_TRUE(profile_list.GetProfileByName(profile2.name(), &profile));
EXPECT_EQ(profile2.name(), profile.name());
EXPECT_EQ(profile2.level(), profile.level());
EXPECT_EQ(profile2.owner(), profile.owner());
EXPECT_TRUE(profile2.device_exceptions().empty());
EXPECT_EQ(profile2.control_time().start_time_seconds(), kStartTimeInSeconds);
EXPECT_EQ(profile2.control_time().end_time_seconds(), kEndTimeInSeconds);
EXPECT_FALSE(
profile_list.GetProfileByName("you-should-not-find-me", &profile));
}
} // namespace security_profile
} // namespace widevine