Minor change
This commit is contained in:
@@ -69,6 +69,7 @@ cc_library(
|
||||
":client_id_util",
|
||||
"@abseil_repo//absl/synchronization",
|
||||
"//protos/public:client_identification_cc_proto",
|
||||
"//protos/public:device_common_cc_proto",
|
||||
"//protos/public:provisioned_device_info_cc_proto",
|
||||
"//protos/public:security_profile_cc_proto",
|
||||
],
|
||||
@@ -83,6 +84,8 @@ cc_test(
|
||||
"//base",
|
||||
"//external:protobuf",
|
||||
"//testing:gunit_main",
|
||||
"@abseil_repo//absl/memory",
|
||||
"//protos/public:device_common_cc_proto",
|
||||
"//protos/public:security_profile_cc_proto",
|
||||
],
|
||||
)
|
||||
@@ -196,6 +199,7 @@ cc_library(
|
||||
hdrs = ["device_info_util.h"],
|
||||
deps = [
|
||||
"@abseil_repo//absl/strings",
|
||||
"//protos/public:device_common_cc_proto",
|
||||
"//protos/public:provisioned_device_info_cc_proto",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "common/signing_key_util.h"
|
||||
#include "protos/public/drm_certificate.pb.h"
|
||||
#include "protos/public/errors.pb.h"
|
||||
#include "protos/public/license_protocol.pb.h"
|
||||
#include "protos/public/signed_drm_certificate.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
@@ -80,6 +81,10 @@ class ClientCertAlgorithmRSA : public ClientCertAlgorithm {
|
||||
return wrapped_session_key_;
|
||||
}
|
||||
|
||||
SignedMessage::SessionKeyType session_key_type() const override {
|
||||
return SignedMessage::WRAPPED_AES_KEY;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<RsaPublicKey> rsa_public_key_;
|
||||
std::string session_key_;
|
||||
@@ -159,6 +164,10 @@ class ClientCertAlgorithmECC : public ClientCertAlgorithm {
|
||||
return ephemeral_public_key_;
|
||||
}
|
||||
|
||||
SignedMessage::SessionKeyType session_key_type() const override {
|
||||
return SignedMessage::EPHERMERAL_ECC_PUBLIC_KEY;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ECPublicKey> client_ecc_public_key_;
|
||||
std::string ephemeral_public_key_;
|
||||
|
||||
@@ -40,6 +40,11 @@ class ClientCertAlgorithm {
|
||||
// field of a license response. This key may be either an encrypted aes key,
|
||||
// or the bytes of an ephemeral public key.
|
||||
virtual const std::string& wrapped_session_key() const = 0;
|
||||
|
||||
// Returns information on the type session key used in this format. This value
|
||||
// is intended to be included in the SignedMessage::session_key_type field of
|
||||
// a license response.
|
||||
virtual SignedMessage::SessionKeyType session_key_type() const = 0;
|
||||
};
|
||||
|
||||
class CertificateClientCert : public ClientCert {
|
||||
@@ -62,6 +67,9 @@ class CertificateClientCert : public ClientCert {
|
||||
return algorithm_->wrapped_session_key();
|
||||
}
|
||||
const std::string& key() const override { return algorithm_->session_key(); }
|
||||
SignedMessage::SessionKeyType key_type() const override {
|
||||
return algorithm_->session_key_type();
|
||||
}
|
||||
const std::string& serial_number() const override {
|
||||
return device_cert_.serial_number();
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ class ClientCert {
|
||||
|
||||
virtual const std::string& encrypted_key() const = 0;
|
||||
virtual const std::string& key() const = 0;
|
||||
virtual SignedMessage::SessionKeyType key_type() const = 0;
|
||||
virtual const std::string& serial_number() const = 0;
|
||||
virtual const std::string& service_id() const = 0;
|
||||
virtual const std::string& signing_key() const = 0;
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
|
||||
namespace widevine {
|
||||
|
||||
const char kModDrmMake[] = "company_name";
|
||||
const char kModDrmModel[] = "model_name";
|
||||
|
||||
void AddClientInfo(ClientIdentification* client_id, absl::string_view name,
|
||||
absl::string_view value) {
|
||||
ClientIdentification_NameValue* nv = client_id->add_client_info();
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
namespace widevine {
|
||||
|
||||
extern const char kModDrmMake[];
|
||||
extern const char kModDrmModel[];
|
||||
|
||||
// Append the given name/value pair to client_id->client_info(). Does not
|
||||
// check for duplicates.
|
||||
void AddClientInfo(ClientIdentification* client_id, absl::string_view name,
|
||||
|
||||
@@ -28,13 +28,17 @@ bool GetCoreProvisioningResponse(
|
||||
const std::string& serialized_provisioning_response,
|
||||
const std::string& request_core_message,
|
||||
std::string* response_core_message) {
|
||||
if (request_core_message.empty()) {
|
||||
return false;
|
||||
}
|
||||
oemcrypto_core_message::ODK_ProvisioningRequest odk_provisioning_request;
|
||||
CoreProvisioningRequestFromMessage(request_core_message,
|
||||
&odk_provisioning_request);
|
||||
CreateCoreProvisioningResponseFromProto(serialized_provisioning_response,
|
||||
odk_provisioning_request,
|
||||
if (CoreProvisioningRequestFromMessage(request_core_message,
|
||||
&odk_provisioning_request)) {
|
||||
return CreateCoreProvisioningResponseFromProto(
|
||||
serialized_provisioning_response, odk_provisioning_request,
|
||||
response_core_message);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetCoreRenewalOrReleaseLicenseResponse(
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "common/device_info_util.h"
|
||||
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "protos/public/device_common.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
bool IsMatchedMakeModel(const std::string& expected_make,
|
||||
@@ -29,10 +30,10 @@ bool VerifyMakeModel(const ProvisionedDeviceInfo& device_info,
|
||||
make_from_client, model_from_client)) {
|
||||
return true;
|
||||
}
|
||||
for (ProvisionedDeviceInfo::ModelInfo product_info :
|
||||
device_info.model_info()) {
|
||||
if (IsMatchedMakeModel(product_info.manufacturer(), product_info.model(),
|
||||
make_from_client, model_from_client)) {
|
||||
for (DeviceModel product_info : device_info.model_info()) {
|
||||
if (IsMatchedMakeModel(product_info.manufacturer(),
|
||||
product_info.model_name(), make_from_client,
|
||||
model_from_client)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ class MockClientCert : public ClientCert {
|
||||
ProtocolVersion protocol_version));
|
||||
MOCK_CONST_METHOD0(serial_number, const std::string &());
|
||||
MOCK_CONST_METHOD0(key, const std::string &());
|
||||
MOCK_CONST_METHOD0(key_type, SignedMessage::SessionKeyType());
|
||||
MOCK_CONST_METHOD0(service_id, const std::string &());
|
||||
MOCK_CONST_METHOD0(encrypted_key, const std::string &());
|
||||
MOCK_CONST_METHOD0(signing_key, const std::string &());
|
||||
|
||||
@@ -31,6 +31,9 @@ class KeyboxClientCert : public ClientCert {
|
||||
|
||||
const std::string& encrypted_key() const override { return unimplemented_; }
|
||||
const std::string& key() const override { return device_key_; }
|
||||
SignedMessage::SessionKeyType key_type() const override {
|
||||
return SignedMessage::WRAPPED_AES_KEY;
|
||||
}
|
||||
const std::string& serial_number() const override { return serial_number_; }
|
||||
const std::string& service_id() const override { return unimplemented_; }
|
||||
const std::string& signing_key() const override { return signing_key_; }
|
||||
|
||||
@@ -13,14 +13,15 @@
|
||||
|
||||
#include "common/client_id_util.h"
|
||||
#include "protos/public/client_identification.pb.h"
|
||||
#include "protos/public/device_common.pb.h"
|
||||
#include "protos/public/provisioned_device_info.pb.h"
|
||||
#include "protos/public/security_profile.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
using ClientCapabilities = ClientIdentification::ClientCapabilities;
|
||||
|
||||
const char kModDrmMake[] = "company_name";
|
||||
const char kModDrmModel[] = "model_name";
|
||||
SecurityProfileList::SecurityProfileList(const std::string& profile_namespace)
|
||||
: profile_namespace_(profile_namespace) {}
|
||||
|
||||
int SecurityProfileList::Init() { return AddDefaultProfiles(); }
|
||||
|
||||
@@ -30,28 +31,28 @@ int SecurityProfileList::AddDefaultProfiles() {
|
||||
const bool make_model_not_verified = false;
|
||||
SecurityProfile profile;
|
||||
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_1,
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_1, "WVSP1",
|
||||
ClientCapabilities::HDCP_NONE,
|
||||
ClientCapabilities::ANALOG_OUTPUT_UNKNOWN, oemcrypto_8,
|
||||
make_model_not_verified, ProvisionedDeviceInfo::LEVEL_3,
|
||||
kResourceTierLow, &profile);
|
||||
InsertProfile(profile);
|
||||
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_2,
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_2, "WVSP2",
|
||||
ClientCapabilities::HDCP_NONE,
|
||||
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A,
|
||||
oemcrypto_12, make_model_not_verified,
|
||||
ProvisionedDeviceInfo::LEVEL_2, kResourceTierLow, &profile);
|
||||
InsertProfile(profile);
|
||||
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_3,
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_3, "WVSP3",
|
||||
ClientCapabilities::HDCP_V1,
|
||||
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A,
|
||||
oemcrypto_12, make_model_not_verified,
|
||||
ProvisionedDeviceInfo::LEVEL_1, kResourceTierMed, &profile);
|
||||
InsertProfile(profile);
|
||||
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_4,
|
||||
PopulateProfile(SecurityProfile::SECURITY_PROFILE_LEVEL_4, "WVSP4",
|
||||
ClientCapabilities::HDCP_V2_2,
|
||||
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A,
|
||||
oemcrypto_12, make_model_not_verified,
|
||||
@@ -61,31 +62,15 @@ int SecurityProfileList::AddDefaultProfiles() {
|
||||
return security_profiles_.size();
|
||||
}
|
||||
|
||||
SecurityProfile::Level SecurityProfileList::GetProfileLevel(
|
||||
SecurityProfile::Level SecurityProfileList::GetBestProfileLevel(
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
SecurityProfile::DrmInfo* drm_info) const {
|
||||
// Iterate through each SP starting from the strictest first.
|
||||
absl::ReaderMutexLock lock(&mutex_);
|
||||
// Profile list is assumed to be sorted.
|
||||
for (auto& profile : security_profiles_) {
|
||||
if (profile.min_security_requirements().security_level() <
|
||||
device_info.security_level()) {
|
||||
continue;
|
||||
}
|
||||
if (profile.min_security_requirements().oemcrypto_version() >
|
||||
client_id.client_capabilities().oem_crypto_api_version()) {
|
||||
continue;
|
||||
}
|
||||
if (profile.min_output_requirements().hdcp_version() >
|
||||
client_id.client_capabilities().max_hdcp_version()) {
|
||||
continue;
|
||||
}
|
||||
if (profile.min_output_requirements().analog_output_capabilities() >
|
||||
client_id.client_capabilities().analog_output_capabilities()) {
|
||||
continue;
|
||||
}
|
||||
if (profile.min_security_requirements().resource_rating_tier() >
|
||||
client_id.client_capabilities().resource_rating_tier()) {
|
||||
if (!IsProfileAllowed(profile, client_id, device_info)) {
|
||||
continue;
|
||||
}
|
||||
if (drm_info != nullptr) {
|
||||
@@ -96,6 +81,42 @@ SecurityProfile::Level SecurityProfileList::GetProfileLevel(
|
||||
return SecurityProfile::SECURITY_PROFILE_LEVEL_UNDEFINED;
|
||||
}
|
||||
|
||||
int SecurityProfileList::GetAllowedProfilesFromList(
|
||||
const std::vector<std::string>& profiles_to_check,
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
std::vector<std::string>* profiles_to_allow) const {
|
||||
if (profiles_to_allow == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
absl::ReaderMutexLock lock(&mutex_);
|
||||
for (auto& profile_name : profiles_to_check) {
|
||||
SecurityProfile profile;
|
||||
if (GetProfileByName(profile_name, &profile)) {
|
||||
if (IsProfileAllowed(profile, client_id, device_info)) {
|
||||
profiles_to_allow->push_back(profile.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
return profiles_to_allow->size();
|
||||
}
|
||||
|
||||
int SecurityProfileList::GetAllowedProfiles(
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
std::vector<std::string>* profiles_to_allow) const {
|
||||
if (profiles_to_allow == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
absl::ReaderMutexLock lock(&mutex_);
|
||||
for (auto& profile : security_profiles_) {
|
||||
if (IsProfileAllowed(profile, client_id, device_info)) {
|
||||
profiles_to_allow->push_back(profile.name());
|
||||
}
|
||||
}
|
||||
return profiles_to_allow->size();
|
||||
}
|
||||
|
||||
bool SecurityProfileList::GetDrmInfo(const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
SecurityProfile::DrmInfo* drm_info) const {
|
||||
@@ -115,14 +136,14 @@ bool SecurityProfileList::GetDrmInfo(const ClientIdentification& client_id,
|
||||
drm_info->mutable_security()->set_request_model_info_status(false);
|
||||
drm_info->mutable_request_model_info()->set_manufacturer(
|
||||
GetClientInfo(client_id, kModDrmMake));
|
||||
drm_info->mutable_request_model_info()->set_model(
|
||||
drm_info->mutable_request_model_info()->set_model_name(
|
||||
GetClientInfo(client_id, kModDrmModel));
|
||||
drm_info->set_system_id(device_info.system_id());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SecurityProfileList::PopulateProfile(
|
||||
const SecurityProfile::Level profile_level,
|
||||
const SecurityProfile::Level profile_level, const std::string& profile_name,
|
||||
const ClientCapabilities::HdcpVersion min_hdcp_version,
|
||||
const ClientCapabilities::AnalogOutputCapabilities
|
||||
analog_output_capabilities,
|
||||
@@ -134,6 +155,7 @@ bool SecurityProfileList::PopulateProfile(
|
||||
return false;
|
||||
}
|
||||
profile_to_create->set_level(profile_level);
|
||||
profile_to_create->set_name(profile_name);
|
||||
profile_to_create->mutable_min_output_requirements()->set_hdcp_version(
|
||||
min_hdcp_version);
|
||||
profile_to_create->mutable_min_output_requirements()
|
||||
@@ -149,8 +171,8 @@ bool SecurityProfileList::PopulateProfile(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SecurityProfileList::GetProfile(SecurityProfile::Level level,
|
||||
SecurityProfile* security_profile) {
|
||||
bool SecurityProfileList::GetProfileByLevel(
|
||||
SecurityProfile::Level level, SecurityProfile* security_profile) const {
|
||||
absl::ReaderMutexLock lock(&mutex_);
|
||||
for (auto& profile : security_profiles_) {
|
||||
if (profile.level() == level) {
|
||||
@@ -163,10 +185,27 @@ bool SecurityProfileList::GetProfile(SecurityProfile::Level level,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SecurityProfileList::GetProfileByName(
|
||||
const std::string& name, SecurityProfile* security_profile) const {
|
||||
absl::ReaderMutexLock lock(&mutex_);
|
||||
for (auto& profile : security_profiles_) {
|
||||
if (profile.name() == name) {
|
||||
if (security_profile != nullptr) {
|
||||
*security_profile = profile;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SecurityProfileList::InsertProfile(
|
||||
const SecurityProfile& profile_to_insert) {
|
||||
// Check if profile already exist.
|
||||
if (GetProfile(profile_to_insert.level(), nullptr)) {
|
||||
if (GetProfileByLevel(profile_to_insert.level(), nullptr)) {
|
||||
return false;
|
||||
}
|
||||
if (GetProfileByName(profile_to_insert.name(), nullptr)) {
|
||||
return false;
|
||||
}
|
||||
absl::WriterMutexLock lock(&mutex_);
|
||||
@@ -182,4 +221,30 @@ bool SecurityProfileList::CompareProfileLevel(const SecurityProfile& p1,
|
||||
return (p1.level() > p2.level());
|
||||
}
|
||||
|
||||
bool SecurityProfileList::IsProfileAllowed(
|
||||
const SecurityProfile& profile, const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info) const {
|
||||
if (profile.min_security_requirements().security_level() <
|
||||
device_info.security_level()) {
|
||||
return false;
|
||||
}
|
||||
if (profile.min_security_requirements().oemcrypto_version() >
|
||||
client_id.client_capabilities().oem_crypto_api_version()) {
|
||||
return false;
|
||||
}
|
||||
if (profile.min_output_requirements().hdcp_version() >
|
||||
client_id.client_capabilities().max_hdcp_version()) {
|
||||
return false;
|
||||
}
|
||||
if (profile.min_output_requirements().analog_output_capabilities() >
|
||||
client_id.client_capabilities().analog_output_capabilities()) {
|
||||
return false;
|
||||
}
|
||||
if (profile.min_security_requirements().resource_rating_tier() >
|
||||
client_id.client_capabilities().resource_rating_tier()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
@@ -32,7 +32,7 @@ const uint32_t kResourceTierHigh = 3;
|
||||
|
||||
class SecurityProfileList {
|
||||
public:
|
||||
SecurityProfileList() {}
|
||||
explicit SecurityProfileList(const std::string& profile_namespace);
|
||||
~SecurityProfileList() {}
|
||||
|
||||
// Initialize the security profile list. The list is initially empty, this
|
||||
@@ -44,24 +44,11 @@ class SecurityProfileList {
|
||||
// if successfully inserted, false if unable to insert.
|
||||
bool InsertProfile(const SecurityProfile& profile_to_insert);
|
||||
|
||||
// Return the highest security level based on the device capabilities.
|
||||
// If |drm_info| is not null, |drm_info| is populated with the device data.
|
||||
SecurityProfile::Level GetProfileLevel(
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
SecurityProfile::DrmInfo* drm_info) const;
|
||||
|
||||
// Return the device security capabilities. |drm_info| is populated with
|
||||
// data from |client_id| and |device_info|. |drm_info| must not be null and
|
||||
// is owned by the caller.
|
||||
bool GetDrmInfo(const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
SecurityProfile::DrmInfo* drm_info) const;
|
||||
|
||||
// Populate |profile_to_create| with the specified output protections and
|
||||
// security parameters. All input parameters are used hence should be set.
|
||||
bool PopulateProfile(
|
||||
const SecurityProfile::Level profile_level,
|
||||
const std::string& profile_name,
|
||||
const ClientCapabilities::HdcpVersion min_hdcp_version,
|
||||
const ClientCapabilities::AnalogOutputCapabilities
|
||||
analog_output_capabilities,
|
||||
@@ -70,11 +57,45 @@ class SecurityProfileList {
|
||||
const uint32_t resource_rating_tier,
|
||||
SecurityProfile* profile_to_create) const;
|
||||
|
||||
// Return the highest security level based on the device capabilities.
|
||||
// If |drm_info| is not null, |drm_info| is populated with the device data.
|
||||
SecurityProfile::Level GetBestProfileLevel(
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
SecurityProfile::DrmInfo* drm_info) const;
|
||||
|
||||
// Populates |profiles_to_allow| with a list of profiles that meet the
|
||||
// requirements for the this device. The number of profiles is returned.
|
||||
int GetAllowedProfiles(const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
std::vector<std::string>* profiles_to_allow) const;
|
||||
|
||||
// Populates |profiles_allow| with a list of profiles from the specified
|
||||
// |profiles_to_check| list that meet the requirements for the this device.
|
||||
// The number of profiles is returned.
|
||||
int GetAllowedProfilesFromList(
|
||||
const std::vector<std::string>& profiles_to_check,
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
std::vector<std::string>* profiles_to_allow) const;
|
||||
|
||||
// Return true if a profile exist matching the specified |level|.
|
||||
// |security_profile| is owned by the caller and is populated if a profile
|
||||
// exist.
|
||||
bool GetProfile(SecurityProfile::Level level,
|
||||
SecurityProfile* security_profile);
|
||||
bool GetProfileByLevel(SecurityProfile::Level level,
|
||||
SecurityProfile* security_profile) const;
|
||||
|
||||
// Return true if a profile exist matching the specified |name|.
|
||||
// |security_profile| is owned by the caller and is populated if a profile
|
||||
// exist.
|
||||
bool GetProfileByName(const std::string& name,
|
||||
SecurityProfile* security_profile) const;
|
||||
// Return the device security capabilities. |drm_info| is populated with
|
||||
// data from |client_id| and |device_info|. |drm_info| must not be null and
|
||||
// is owned by the caller.
|
||||
bool GetDrmInfo(const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info,
|
||||
SecurityProfile::DrmInfo* drm_info) const;
|
||||
|
||||
private:
|
||||
// Initialize the list with Widevine default profiles. The size of the
|
||||
@@ -84,12 +105,14 @@ class SecurityProfileList {
|
||||
static bool CompareProfileLevel(const SecurityProfile& p1,
|
||||
const SecurityProfile& p2);
|
||||
|
||||
bool IsProfileAllowed(const SecurityProfile& profile,
|
||||
const ClientIdentification& client_id,
|
||||
const ProvisionedDeviceInfo& device_info) const;
|
||||
|
||||
mutable absl::Mutex mutex_;
|
||||
// Widevine security profiles
|
||||
// Security profiles
|
||||
std::string profile_namespace_;
|
||||
std::vector<SecurityProfile> security_profiles_ ABSL_GUARDED_BY(mutex_);
|
||||
// Custom security profiles
|
||||
std::map<std::string, SecurityProfile> custom_security_profiles_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include "google/protobuf/util/message_differencer.h"
|
||||
#include "testing/gmock.h"
|
||||
#include "testing/gunit.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "protos/public/device_common.pb.h"
|
||||
#include "protos/public/security_profile.pb.h"
|
||||
|
||||
namespace widevine {
|
||||
@@ -47,6 +49,8 @@ class SecurityProfileListTest : public ::testing::Test {
|
||||
->set_resource_rating_tier(kResourceTierHigh);
|
||||
test_profile_1_.mutable_min_security_requirements()
|
||||
->set_request_model_info_status(make_model_not_verified);
|
||||
std::string profile_namespace = "widevine_test";
|
||||
profile_list_ = absl::make_unique<SecurityProfileList>(profile_namespace);
|
||||
|
||||
ClientIdentification_NameValue *nv = client_id_.add_client_info();
|
||||
nv->set_name(kMakeName);
|
||||
@@ -65,7 +69,7 @@ class SecurityProfileListTest : public ::testing::Test {
|
||||
device_info_.set_system_id(kSystemId);
|
||||
}
|
||||
SecurityProfile test_profile_1_;
|
||||
SecurityProfileList profile_list_;
|
||||
std::unique_ptr<SecurityProfileList> profile_list_;
|
||||
ClientIdentification client_id_;
|
||||
ProvisionedDeviceInfo device_info_;
|
||||
};
|
||||
@@ -73,19 +77,24 @@ class SecurityProfileListTest : public ::testing::Test {
|
||||
TEST_F(SecurityProfileListTest, InsertProfile) {
|
||||
// This test will not initialize the SecurityProfileList, hence it's empty.
|
||||
// Insert test profile 1 into the list.
|
||||
EXPECT_TRUE(profile_list_.InsertProfile(test_profile_1_));
|
||||
// Should not allow insertion of an alreadfy existing level.
|
||||
EXPECT_FALSE(profile_list_.InsertProfile(test_profile_1_));
|
||||
EXPECT_TRUE(profile_list_->InsertProfile(test_profile_1_));
|
||||
// Should not allow insertion of an already existing level.
|
||||
EXPECT_FALSE(profile_list_->InsertProfile(test_profile_1_));
|
||||
SecurityProfile profile;
|
||||
ASSERT_EQ(SecurityProfile::SECURITY_PROFILE_LEVEL_1,
|
||||
profile_list_.GetProfile(test_profile_1_.level(), &profile));
|
||||
// Should not allow insertion of an already existing name.
|
||||
// Make sure the level is not the same as already inserted level_1.
|
||||
profile.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_2);
|
||||
profile.set_name(test_profile_1_.name());
|
||||
EXPECT_FALSE(profile_list_->InsertProfile(test_profile_1_));
|
||||
ASSERT_TRUE(profile_list_->GetProfileByLevel(
|
||||
SecurityProfile::SECURITY_PROFILE_LEVEL_1, &profile));
|
||||
EXPECT_TRUE(
|
||||
google::protobuf::util::MessageDifferencer::Equals(test_profile_1_, profile));
|
||||
}
|
||||
|
||||
TEST_F(SecurityProfileListTest, GetDrmInfo) {
|
||||
SecurityProfile::DrmInfo drm_info;
|
||||
ASSERT_TRUE(profile_list_.GetDrmInfo(client_id_, device_info_, &drm_info));
|
||||
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(),
|
||||
@@ -102,12 +111,12 @@ TEST_F(SecurityProfileListTest, GetDrmInfo) {
|
||||
// make_mode status is currently hard-coded to false.
|
||||
EXPECT_EQ(false, drm_info.security().request_model_info_status());
|
||||
EXPECT_EQ(kMakeValue, drm_info.request_model_info().manufacturer());
|
||||
EXPECT_EQ(kModelValue, drm_info.request_model_info().model());
|
||||
EXPECT_EQ(kModelValue, drm_info.request_model_info().model_name());
|
||||
}
|
||||
|
||||
TEST_F(SecurityProfileListTest, ProfileLevels) {
|
||||
SecurityProfile::DrmInfo drm_info;
|
||||
profile_list_.Init();
|
||||
profile_list_->Init();
|
||||
|
||||
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
|
||||
ClientCapabilities::HDCP_NONE);
|
||||
@@ -119,21 +128,24 @@ TEST_F(SecurityProfileListTest, ProfileLevels) {
|
||||
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_3);
|
||||
|
||||
// Lowest profile level requires OEMCrypto version 8.
|
||||
ASSERT_EQ(SecurityProfile::SECURITY_PROFILE_LEVEL_UNDEFINED,
|
||||
profile_list_.GetProfileLevel(client_id_, device_info_, &drm_info));
|
||||
ASSERT_EQ(
|
||||
SecurityProfile::SECURITY_PROFILE_LEVEL_UNDEFINED,
|
||||
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
|
||||
|
||||
// Move up to profile 1
|
||||
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(8);
|
||||
ASSERT_EQ(SecurityProfile::SECURITY_PROFILE_LEVEL_1,
|
||||
profile_list_.GetProfileLevel(client_id_, device_info_, &drm_info));
|
||||
ASSERT_EQ(
|
||||
SecurityProfile::SECURITY_PROFILE_LEVEL_1,
|
||||
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
|
||||
|
||||
// Move up to profile 2
|
||||
client_id_.mutable_client_capabilities()->set_analog_output_capabilities(
|
||||
ClientCapabilities::ANALOG_OUTPUT_SUPPORTS_CGMS_A);
|
||||
client_id_.mutable_client_capabilities()->set_oem_crypto_api_version(12);
|
||||
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_2);
|
||||
ASSERT_EQ(SecurityProfile::SECURITY_PROFILE_LEVEL_2,
|
||||
profile_list_.GetProfileLevel(client_id_, device_info_, &drm_info));
|
||||
ASSERT_EQ(
|
||||
SecurityProfile::SECURITY_PROFILE_LEVEL_2,
|
||||
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
|
||||
|
||||
// Move up to profile 3
|
||||
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
|
||||
@@ -141,16 +153,59 @@ TEST_F(SecurityProfileListTest, ProfileLevels) {
|
||||
device_info_.set_security_level(ProvisionedDeviceInfo::LEVEL_1);
|
||||
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
|
||||
kResourceTierMed);
|
||||
ASSERT_EQ(SecurityProfile::SECURITY_PROFILE_LEVEL_3,
|
||||
profile_list_.GetProfileLevel(client_id_, device_info_, &drm_info));
|
||||
ASSERT_EQ(
|
||||
SecurityProfile::SECURITY_PROFILE_LEVEL_3,
|
||||
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
|
||||
|
||||
// Move up to profile 4
|
||||
client_id_.mutable_client_capabilities()->set_max_hdcp_version(
|
||||
ClientCapabilities::HDCP_V2_2);
|
||||
client_id_.mutable_client_capabilities()->set_resource_rating_tier(
|
||||
kResourceTierHigh);
|
||||
ASSERT_EQ(SecurityProfile::SECURITY_PROFILE_LEVEL_4,
|
||||
profile_list_.GetProfileLevel(client_id_, device_info_, &drm_info));
|
||||
ASSERT_EQ(
|
||||
SecurityProfile::SECURITY_PROFILE_LEVEL_4,
|
||||
profile_list_->GetBestProfileLevel(client_id_, device_info_, &drm_info));
|
||||
}
|
||||
|
||||
TEST_F(SecurityProfileListTest, FindProfile) {
|
||||
// This test will not initialize the SecurityProfileList, hence it's empty.
|
||||
// Insert test profile 1 into the list.
|
||||
SecurityProfile profile1;
|
||||
profile1.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_1);
|
||||
profile1.set_name("profile1");
|
||||
SecurityProfile profile2;
|
||||
profile2.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_2);
|
||||
profile2.set_name("profile2");
|
||||
SecurityProfile profile3;
|
||||
profile3.set_level(SecurityProfile::SECURITY_PROFILE_LEVEL_3);
|
||||
profile3.set_name("profile3");
|
||||
|
||||
// Insert profiles 1 & 2, but not 3..
|
||||
EXPECT_TRUE(profile_list_->InsertProfile(profile1));
|
||||
EXPECT_TRUE(profile_list_->InsertProfile(profile2));
|
||||
|
||||
// Find the profile by its level.
|
||||
SecurityProfile profile;
|
||||
EXPECT_TRUE(profile_list_->GetProfileByLevel(profile1.level(), &profile));
|
||||
EXPECT_EQ(profile1.name(), profile.name());
|
||||
EXPECT_EQ(profile1.level(), profile.level());
|
||||
|
||||
EXPECT_TRUE(profile_list_->GetProfileByLevel(profile2.level(), &profile));
|
||||
EXPECT_EQ(profile2.name(), profile.name());
|
||||
EXPECT_EQ(profile2.level(), profile.level());
|
||||
|
||||
EXPECT_FALSE(profile_list_->GetProfileByName(profile3.name(), nullptr));
|
||||
|
||||
// Find the profile by its name.
|
||||
EXPECT_TRUE(profile_list_->GetProfileByName(profile1.name(), &profile));
|
||||
EXPECT_EQ(profile1.name(), profile.name());
|
||||
EXPECT_EQ(profile1.level(), profile.level());
|
||||
|
||||
EXPECT_TRUE(profile_list_->GetProfileByName(profile2.name(), &profile));
|
||||
EXPECT_EQ(profile2.name(), profile.name());
|
||||
EXPECT_EQ(profile2.level(), profile.level());
|
||||
|
||||
EXPECT_FALSE(profile_list_->GetProfileByName(profile3.name(), nullptr));
|
||||
}
|
||||
|
||||
} // namespace security_profile
|
||||
|
||||
@@ -874,12 +874,19 @@ Status EcmgClientHandler::BuildEcmDatagram(const EcmgParameters& params,
|
||||
DCHECK(stream_info->ecm);
|
||||
|
||||
// Generate serialized ECM.
|
||||
CryptoMode crypto_mode = stream_info->crypto_mode == CryptoMode::kInvalid
|
||||
? ecmg_config_->crypto_mode
|
||||
: stream_info->crypto_mode;
|
||||
std::vector<EntitledKeyInfo> keys;
|
||||
keys.reserve(ecmg_config_->number_of_content_keys);
|
||||
for (size_t i = 0; i < ecmg_config_->number_of_content_keys; i++) {
|
||||
DCHECK(params.cp_cw_combinations[i].cp == params.cp_number + i);
|
||||
keys.emplace_back();
|
||||
keys[i].key_value = params.cp_cw_combinations[i].cw;
|
||||
// Make content key to 16 bytes if crypto mode is Csa2.
|
||||
if (crypto_mode == CryptoMode::kDvbCsa2 && keys[i].key_value.size() == 8) {
|
||||
keys[i].key_value = keys[i].key_value + keys[i].key_value;
|
||||
}
|
||||
keys[i].key_id = crypto_util::DeriveKeyId(keys[i].key_value);
|
||||
keys[i].content_iv = stream_info->content_ivs.empty()
|
||||
? content_ivs_[i]
|
||||
|
||||
@@ -39,7 +39,9 @@ static constexpr size_t kEcmId = 2;
|
||||
static constexpr size_t kNominalCpDuration = 0x64;
|
||||
static constexpr size_t kCpNumber = 0;
|
||||
static constexpr char kContentKeyEven[] = "0123456701234567";
|
||||
static constexpr char kContentKeyEven8Bytes[] = "01234567";
|
||||
static constexpr char kContentKeyOdd[] = "abcdefghabcdefgh";
|
||||
static constexpr char kContentKeyOdd8Bytes[] = "abcdefgh";
|
||||
static constexpr char kEntitlementKeyIdEven[] = "0123456701234567";
|
||||
static constexpr char kEntitlementKeyValueEven[] =
|
||||
"01234567012345670123456701234567";
|
||||
@@ -48,6 +50,7 @@ static constexpr char kEntitlementKeyValueOdd[] =
|
||||
"abcdefghabcdefghabcdefghabcdefgh";
|
||||
static constexpr size_t kAgeRestriction = 3;
|
||||
static constexpr char kCryptoMode[] = "AesScte";
|
||||
static constexpr char kCryptoModeCsa2[] = "DvbCsa2";
|
||||
static constexpr char kTrackTypesSD[] = "SD";
|
||||
static constexpr char kTrackTypesHD[] = "HD";
|
||||
|
||||
@@ -78,14 +81,16 @@ class EcmgClientHandlerTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
void SetupValidChannel() {
|
||||
handler_->HandleRequest(kTestEcmgChannelSetup, response_, &response_len_);
|
||||
handler_->HandleRequest(kTestEcmgChannelSetupWithPrivateParameters,
|
||||
response_, &response_len_);
|
||||
EXPECT_EQ(sizeof(kTestEcmgChannelStatus), response_len_);
|
||||
EXPECT_EQ(0, memcmp(kTestEcmgChannelStatus, response_, response_len_));
|
||||
}
|
||||
|
||||
void SetupValidChannelStream() {
|
||||
SetupValidChannel();
|
||||
handler_->HandleRequest(kTestEcmgStreamSetup, response_, &response_len_);
|
||||
handler_->HandleRequest(kTestEcmgStreamSetupWithPrivateParameters,
|
||||
response_, &response_len_);
|
||||
EXPECT_EQ(sizeof(kTestEcmgStreamStatus), response_len_);
|
||||
EXPECT_EQ(0, memcmp(kTestEcmgStreamStatus, response_, response_len_));
|
||||
}
|
||||
@@ -320,7 +325,33 @@ TEST_F(EcmgClientHandlerTest, SuccessSequenceInjectedEntitlements) {
|
||||
handler_->HandleRequest(request_, response_, &response_len_);
|
||||
EXPECT_EQ(sizeof(kTestEcmgEcmResponse), response_len_);
|
||||
}
|
||||
//
|
||||
|
||||
TEST_F(EcmgClientHandlerTest, SuccessSequenceCsa2) {
|
||||
BuildChannelSetupRequest(kChannelId, kSuperCasId, kAgeRestriction,
|
||||
kCryptoModeCsa2, request_, &request_len_);
|
||||
handler_->HandleRequest(request_, response_, &response_len_);
|
||||
EXPECT_EQ(sizeof(kTestEcmgChannelStatus), response_len_);
|
||||
EXPECT_EQ(0, memcmp(kTestEcmgChannelStatus, response_, response_len_));
|
||||
|
||||
BuildStreamSetupRequest(
|
||||
kChannelId, kStreamId, kEcmId, kNominalCpDuration, kTrackTypesSD,
|
||||
{absl::StrCat(kEntitlementKeyIdEven, kEntitlementKeyValueEven),
|
||||
absl::StrCat(kEntitlementKeyIdOdd, kEntitlementKeyValueOdd)},
|
||||
{kContentKeyEven, kContentKeyEven}, request_, &request_len_);
|
||||
handler_->HandleRequest(request_, response_, &response_len_);
|
||||
EXPECT_EQ(sizeof(kTestEcmgStreamStatus), response_len_);
|
||||
EXPECT_EQ(0, memcmp(kTestEcmgStreamStatus, response_, response_len_));
|
||||
|
||||
const std::vector<EcmgCpCwCombination> cp_cw_combination = {
|
||||
{kCpNumber, kContentKeyEven8Bytes},
|
||||
{kCpNumber + 1, kContentKeyOdd8Bytes}};
|
||||
BuildCwProvisionRequest(kChannelId, kStreamId, kCpNumber, cp_cw_combination,
|
||||
request_, &request_len_);
|
||||
handler_->HandleRequest(request_, response_, &response_len_);
|
||||
EXPECT_EQ(sizeof(kTestEcmgEcmResponse), response_len_);
|
||||
EXPECT_EQ(0, memcmp(kTestEcmgEcmResponse, response_, 27));
|
||||
}
|
||||
|
||||
TEST_F(EcmgClientHandlerTest, SuccessChannelError) {
|
||||
SetupValidChannel();
|
||||
handler_->HandleRequest(kTestEcmgChannelError, response_, &response_len_);
|
||||
@@ -408,6 +439,18 @@ TEST_F(EcmgClientHandlerTest, WrongParameterInsufficientKey) {
|
||||
response_len_);
|
||||
}
|
||||
|
||||
TEST_F(EcmgClientHandlerTest, WrongContentKeySize) {
|
||||
SetupValidChannelStream();
|
||||
// Content keys should be 16 byes.
|
||||
const std::vector<EcmgCpCwCombination> cp_cw_combination = {
|
||||
{kCpNumber, kContentKeyEven8Bytes},
|
||||
{kCpNumber + 1, kContentKeyOdd8Bytes}};
|
||||
BuildCwProvisionRequest(kChannelId, kStreamId, kCpNumber, cp_cw_combination,
|
||||
request_, &request_len_);
|
||||
handler_->HandleRequest(request_, response_, &response_len_);
|
||||
CheckStreamError(INVALID_VALUE_FOR_DVB_PARAMETER, response_, response_len_);
|
||||
}
|
||||
|
||||
TEST_F(EcmgClientHandlerTest, WrongParameterSuperCasId) {
|
||||
// Setup a channel with an unexpected super cas id (expecting kSuperCasId).
|
||||
BuildChannelSetupRequest(kChannelId, 0, kAgeRestriction, kCryptoMode,
|
||||
|
||||
@@ -60,8 +60,20 @@ Status WvCasEcm::GenerateEcm(const WvCasContentKeyInfo& even_key,
|
||||
LOG(ERROR) << "Failed to get initialize ECM class." << status;
|
||||
return status;
|
||||
}
|
||||
|
||||
EntitledKeyInfo entitled_even_key = ConvertToEntitledKeyInfo(even_key);
|
||||
EntitledKeyInfo entitled_odd_key = ConvertToEntitledKeyInfo(odd_key);
|
||||
// Make content key to 16 bytes if crypto mode is Csa2.
|
||||
if (ecm_param_.crypto_mode == CryptoMode::kDvbCsa2) {
|
||||
if (entitled_even_key.key_value.size() == 8) {
|
||||
entitled_even_key.key_value =
|
||||
entitled_even_key.key_value + entitled_even_key.key_value;
|
||||
}
|
||||
if (entitled_odd_key.key_value.size() == 8) {
|
||||
entitled_odd_key.key_value =
|
||||
entitled_odd_key.key_value + entitled_odd_key.key_value;
|
||||
}
|
||||
}
|
||||
return cas_ecm->GenerateEcm(&entitled_even_key, &entitled_odd_key, track_type,
|
||||
serialized_ecm);
|
||||
}
|
||||
@@ -79,6 +91,12 @@ Status WvCasEcm::GenerateSingleKeyEcm(const WvCasContentKeyInfo& key,
|
||||
}
|
||||
|
||||
EntitledKeyInfo entitled_key = ConvertToEntitledKeyInfo(key);
|
||||
// Make content key to 16 bytes if crypto mode is Csa2.
|
||||
if (ecm_param_.crypto_mode == CryptoMode::kDvbCsa2) {
|
||||
if (entitled_key.key_value.size() == 8) {
|
||||
entitled_key.key_value = entitled_key.key_value + entitled_key.key_value;
|
||||
}
|
||||
}
|
||||
return cas_ecm->GenerateSingleKeyEcm(&entitled_key, track_type,
|
||||
serialized_ecm);
|
||||
}
|
||||
|
||||
@@ -22,11 +22,12 @@ namespace cas {
|
||||
// Information needed to generate content key portion of ECM.
|
||||
// Fields:
|
||||
// |key_id| key ID for the content key, must be 16 bytes.
|
||||
// |key| content key value (aka control word), must be 16 bytes. It will be
|
||||
// wrapped (encrypted) by corresponding entitlement key (decided by track
|
||||
// type), together with |wrapped_key_iv| as the initial vector.
|
||||
// |content_iv| content initial vector, must be 8 or 16 bytes. It is used for
|
||||
// decrypting the content stream.
|
||||
// |key| content key value (aka control word), must be 8 (DvbCsa2) or 16 bytes
|
||||
// (all other crypto modes). It will be wrapped (encrypted) by
|
||||
// corresponding entitlement key (decided by track type), together with
|
||||
// |wrapped_key_iv| as the initial vector.
|
||||
// |content_iv| content initial vector, must be 8 (DvbCsa2) or 16 bytes (all
|
||||
// other crypto modes). It is used for decrypting the content stream.
|
||||
// |wrapped_key_iv| must be 16 bytes. It is used to encrypt |key|.
|
||||
struct WvCasContentKeyInfo {
|
||||
std::string key_id;
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace cas {
|
||||
|
||||
namespace {
|
||||
const char kEvenKey[] = "even_key........"; // 16 bytes
|
||||
const char kEvenKey8Bytes[] = "even_key"; // 8 bytes
|
||||
const char kEvenContentIv8Bytes[] = "even_iv."; // 8 bytes
|
||||
const char kEvenContentIv16Bytes[] = "even_iv.even_iv."; // 16 bytes
|
||||
const char kEvenEntitlementKeyId[] = "even_ent_key_id."; // 16 bytes
|
||||
@@ -34,6 +35,7 @@ const char kEvenEntitlementKey[] =
|
||||
const char kEvenEntitlementWrappedKeyIv[] = "1234567812345678"; // 16 bytes
|
||||
|
||||
const char kOddKey[] = "odd_key........."; // 16 bytes
|
||||
const char kOddKey8Bytes[] = "odd_key."; // 8 bytes
|
||||
const char kOddContentIv8Bytes[] = "odd_iv.."; // 8 bytes
|
||||
const char kOddContentIv16Bytes[] = "odd_iv..odd_iv.."; // 16 bytes
|
||||
const char kOddEntitlementKeyId[] = "odd_ent_key_id.."; // 16 bytes
|
||||
@@ -48,22 +50,24 @@ static constexpr size_t kSingleKeyEcmWith16BytesContentIvSizeBytes =
|
||||
kSingleKeyEcmWith8BytesContentIvSizeBytes + 8;
|
||||
} // namespace
|
||||
|
||||
class WvCasEcmTest
|
||||
: public ::testing::Test,
|
||||
class WvCasEcmTest : public ::testing::Test,
|
||||
public ::testing::WithParamInterface<::testing::tuple<
|
||||
int /*content_iv_size*/, bool /*key_rotation_enabled*/>> {
|
||||
int /*content_iv_size*/, bool /*key_rotation_enabled*/,
|
||||
std::string /*crypto_mode*/>> {
|
||||
protected:
|
||||
WvCasEcmTest() {
|
||||
content_iv_size_ = std::get<0>(GetParam());
|
||||
key_rotation_ = std::get<1>(GetParam());
|
||||
crypto_mode_ = std::get<2>(GetParam());
|
||||
}
|
||||
|
||||
WvCasEcmParameters CreateEcmInitParameters(bool key_rotation,
|
||||
int content_iv_size) {
|
||||
int content_iv_size,
|
||||
std::string crypto_mode) {
|
||||
WvCasEcmParameters params;
|
||||
params.content_iv_size = content_iv_size == 8 ? kIvSize8 : kIvSize16;
|
||||
params.key_rotation_enabled = key_rotation;
|
||||
params.crypto_mode = CryptoMode::kAesScte;
|
||||
EXPECT_TRUE(StringToCryptoMode(crypto_mode, ¶ms.crypto_mode));
|
||||
params.age_restriction = 0;
|
||||
return params;
|
||||
}
|
||||
@@ -95,7 +99,7 @@ class WvCasEcmTest
|
||||
content_keys.reserve(key_rotation ? 2 : 1);
|
||||
content_keys.emplace_back();
|
||||
WvCasContentKeyInfo* content_key = &content_keys.back();
|
||||
content_key->key = kEvenKey;
|
||||
content_key->key = crypto_mode_ == "DvbCsa2" ? kEvenKey8Bytes : kEvenKey;
|
||||
content_key->key_id = crypto_util::DeriveKeyId(content_key->key);
|
||||
content_key->content_iv =
|
||||
content_iv_size == 8 ? kEvenContentIv8Bytes : kEvenContentIv16Bytes;
|
||||
@@ -103,7 +107,7 @@ class WvCasEcmTest
|
||||
if (key_rotation) {
|
||||
content_keys.emplace_back();
|
||||
WvCasContentKeyInfo* content_key = &content_keys.back();
|
||||
content_key->key = kOddKey;
|
||||
content_key->key = crypto_mode_ == "DvbCsa2" ? kOddKey8Bytes : kOddKey;
|
||||
content_key->key_id = crypto_util::DeriveKeyId(content_key->key);
|
||||
content_key->content_iv =
|
||||
content_iv_size == 8 ? kOddContentIv8Bytes : kOddContentIv16Bytes;
|
||||
@@ -115,11 +119,12 @@ class WvCasEcmTest
|
||||
|
||||
int content_iv_size_;
|
||||
bool key_rotation_;
|
||||
std::string crypto_mode_;
|
||||
};
|
||||
|
||||
TEST_P(WvCasEcmTest, InitializeSuccess) {
|
||||
WvCasEcmParameters params =
|
||||
CreateEcmInitParameters(key_rotation_, content_iv_size_);
|
||||
CreateEcmInitParameters(key_rotation_, content_iv_size_, crypto_mode_);
|
||||
std::vector<EntitlementKeyInfo> entitlements =
|
||||
CreateInjectedEntitlements(key_rotation_);
|
||||
WvCasEcm wv_cas_ecm(params, entitlements);
|
||||
@@ -127,7 +132,7 @@ TEST_P(WvCasEcmTest, InitializeSuccess) {
|
||||
|
||||
TEST_P(WvCasEcmTest, GenerateSingleKeyEcmKeyRotationEnabledError) {
|
||||
WvCasEcmParameters params = CreateEcmInitParameters(
|
||||
/*key_rotation*/ true, content_iv_size_);
|
||||
/*key_rotation*/ true, content_iv_size_, crypto_mode_);
|
||||
std::vector<EntitlementKeyInfo> entitlements =
|
||||
CreateInjectedEntitlements(/*key_rotation*/ true);
|
||||
WvCasEcm wv_cas_ecm(params, entitlements);
|
||||
@@ -144,7 +149,7 @@ TEST_P(WvCasEcmTest, GenerateSingleKeyEcmKeyRotationEnabledError) {
|
||||
|
||||
TEST_P(WvCasEcmTest, GenerateEcmKeyRotationDisabledError) {
|
||||
WvCasEcmParameters params = CreateEcmInitParameters(
|
||||
/*key_rotation*/ false, content_iv_size_);
|
||||
/*key_rotation*/ false, content_iv_size_, crypto_mode_);
|
||||
std::vector<EntitlementKeyInfo> entitlements =
|
||||
CreateInjectedEntitlements(/*key_rotation*/ false);
|
||||
WvCasEcm wv_cas_ecm(params, entitlements);
|
||||
@@ -162,7 +167,7 @@ TEST_P(WvCasEcmTest, GenerateEcmKeyRotationDisabledError) {
|
||||
|
||||
TEST_P(WvCasEcmTest, GenerateEcmSuccess) {
|
||||
WvCasEcmParameters params =
|
||||
CreateEcmInitParameters(key_rotation_, content_iv_size_);
|
||||
CreateEcmInitParameters(key_rotation_, content_iv_size_, crypto_mode_);
|
||||
std::vector<EntitlementKeyInfo> entitlements =
|
||||
CreateInjectedEntitlements(key_rotation_);
|
||||
WvCasEcm wv_cas_ecm(params, entitlements);
|
||||
@@ -193,9 +198,10 @@ TEST_P(WvCasEcmTest, GenerateEcmSuccess) {
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(WvCasEcmTests, WvCasEcmTest,
|
||||
::testing::Combine(::testing::Values(8, 16),
|
||||
::testing::Bool()));
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
WvCasEcmTests, WvCasEcmTest,
|
||||
::testing::Combine(::testing::Values(8, 16), ::testing::Bool(),
|
||||
::testing::Values("AesScte", "DvbCsa2")));
|
||||
|
||||
} // namespace cas
|
||||
} // namespace widevine
|
||||
|
||||
Reference in New Issue
Block a user