CAS Proxy SDK git checkin as per g3doc.

Adds support for specifying service type when creating a service certificate.

A recent change to the SDK allows for service certificates (DrmCertificate) to also specify a ServiceType indicating which type of service they are supposed to be used on.  This CL adds certificate creation service support for this.

-------------
Fix typo in cas proxy SDK.

-------------
Migrate C++ proto_library rules to cc_proto_library.

We update dependency edges of cc_* rules on proto_library() rules to use a cc_proto_library() intermediary in preparation for eliminating proto_library()'s cc support as per []

More information: []

Tested:
    TAP --sample for global presubmit queue
    []

-------------
Migrate cc proto_library to cc_proto_library. Also fixes build break introduced by []

-------------
Remove unnecessary #MOE directives

-------------
[Proxy_SDK] Move generateSignature in WvPLSDKEnvironment to signature_util.cc file.

-------------
[SDK]Add service_certificate type check in WVPL LSDK and PROXY SDK.

-------------
[Proxy_SDK] Add new API to get remote_attestation_cert_serial_number for proxy SDK.

-------------
[Proxy_SDK] Add getDrmDeviceId function

-------------
[Proxy_SDK] add getrequesttype function for proxy sdk

-------------
[SDK] Add videoFeature field to WvPLWidevinePsshData in WvPLWidevine.java and wvpl_type.h. Related to []

-------------
Allow specified devices to request licenses even if these devices are in TEST_ONLY state.
This will also override the global setting of TEST_ONLY devices not being allowed to
successfully receive licenses from Widevine License SDK.

-------------
[Proxy_SDK] Add ParseDCSL function and test case.

-------------
[Proxy_SDK] Return non-ok status for service_certificate_request when create proxy sdk session. Add test case in Java test.

-------------
[Proxy_SDK] Add video_feature parsing in GetPsshData function. Also check video_feature when geneateModularDrmLicenseRequest.

-------------
[SDK]Deprecated message_type() function, use request_type() instead.

-------------
Use JDK instead of JRE

The concept of a JRE is going away in JDK 11. The jre/ subdirectory in the JDK will no longer exist and the :jre targets will no longer make sense.

Currently in JDK 8, the JDK is a superset of the JRE (it contains all of the files in the JRE), so this is a safe change.

Tested:
    TAP found no affected targets
    []

-------------
Renaming WvPLSDKSession.request_type() API.
Added LICENSE_TYPE_UNSPECIFIED enumeration to WvPLLicenseType.

-------------
Additional VLOG messaging for licensing with TEST_ONLY devices.

-------------
Remove forward declarations of absl names. The style guide bans this, and those names are not for external users to redeclare. External users should include the public headers instead.

-------------
Change Kokoro to use latest bazel version

-------------
Update the abseil build to the December 18 release.

This fixes a problem where the MOE build is failing because there was no definition for node_hash_map.

-------------
[CAS_Proxy]Add WvPLCASProxyEnvironmentJNI.cc and com_google_video_widevine_sdk_wvpl_WvPLCASProxyEnvironment.h file to implement JNI layer for WvPLCASProxyEnvironment.

-------------
Apply changes to sdk to match device certificate status list updates.

Cleans up some of the protos we're using for the new SignedDeviceInfo. Also, adjusts the sdk implementation to reflect the proto and service changes.

-------------
[CAS_PROXY]Add WvPLCASProxyEnvironment.java, WvPLCASProxySession.java and WvPLCASProxyTest.java file.

-------------
Add API to return the DRM service certificate by provider.

-------------
[CAS_PROXY]Implement SetDrmServiceCertificate and SetDeviceCertificateStatusList JNI layer.

-------------
Get DeviceInfo from request.

-------------
CAS Proxy SDK updated to 1.1.5.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=248640225
This commit is contained in:
Ramji Chandramouli
2019-05-16 18:14:58 -07:00
parent 74b7f405c8
commit be0bb27305
44 changed files with 1496 additions and 577 deletions

View File

@@ -10,7 +10,7 @@ git_repository(
git_repository( git_repository(
name = "abseil_repo", name = "abseil_repo",
commit = "475d64f2de7403a01b1b36c487328ed41d29c20c", #2018-04-10 commit = "fcb104594b0bb4b8ac306cb2f55ecdad40974683", #2018-12-04
remote = "https://github.com/abseil/abseil-cpp.git", remote = "https://github.com/abseil/abseil-cpp.git",
) )

View File

@@ -73,11 +73,11 @@ cc_library(
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"@abseil_repo//absl/time", "@abseil_repo//absl/time",
"//util/gtl:map_util", "//util/gtl:map_util",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:drm_certificate_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:signed_drm_certificate_proto", "//protos/public:signed_drm_certificate_cc_proto",
], ],
) )
@@ -99,9 +99,9 @@ cc_test(
"@abseil_repo//absl/time", "@abseil_repo//absl/time",
"//common:rsa_key", "//common:rsa_key",
"//common:rsa_test_keys", "//common:rsa_test_keys",
"//protos/public:drm_certificate_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:signed_drm_certificate_proto", "//protos/public:signed_drm_certificate_cc_proto",
], ],
) )
@@ -111,22 +111,19 @@ cc_library(
hdrs = ["device_status_list.h"], hdrs = ["device_status_list.h"],
deps = [ deps = [
":client_cert", ":client_cert",
":crypto_util",
":drm_root_certificate",
":drm_service_certificate", ":drm_service_certificate",
":error_space", ":error_space",
":random_util",
":rsa_key", ":rsa_key",
":signing_key_util",
":status", ":status",
"//base", "//base",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//util/gtl:map_util", "//util/gtl:map_util",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:device_certificate_status_proto", "//protos/public:device_certificate_status_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:provisioned_device_info_proto", "//protos/public:provisioned_device_info_cc_proto",
"//protos/public:signed_device_info_cc_proto",
], ],
) )
@@ -137,15 +134,17 @@ cc_test(
deps = [ deps = [
":client_cert", ":client_cert",
":device_status_list", ":device_status_list",
":rsa_key",
":rsa_test_keys",
":status",
"//base", "//base",
"//testing:gunit_main", "//testing:gunit_main",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"//common:rsa_key", "//protos/public:client_identification_cc_proto",
"//common:rsa_test_keys", "//protos/public:device_certificate_status_cc_proto",
"//protos/public:client_identification_proto", "//protos/public:errors_cc_proto",
"//protos/public:errors_proto", "//protos/public:provisioned_device_info_cc_proto",
"//protos/public:provisioned_device_info_proto", "//protos/public:signed_drm_certificate_cc_proto",
"//protos/public:signed_drm_certificate_proto",
], ],
) )
@@ -164,9 +163,9 @@ cc_library(
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//external:openssl", "//external:openssl",
"//protos/public:drm_certificate_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:signed_drm_certificate_proto", "//protos/public:signed_drm_certificate_cc_proto",
], ],
) )
@@ -183,9 +182,9 @@ cc_test(
"//base", "//base",
"//external:protobuf", "//external:protobuf",
"//testing:gunit_main", "//testing:gunit_main",
"//protos/public:drm_certificate_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:signed_drm_certificate_proto", "//protos/public:signed_drm_certificate_cc_proto",
], ],
) )
@@ -200,8 +199,8 @@ cc_library(
":status", ":status",
"//base", "//base",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
], ],
) )
@@ -431,7 +430,7 @@ cc_library(
deps = [ deps = [
":crypto_util", ":crypto_util",
"//base", "//base",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
], ],
) )
@@ -445,7 +444,7 @@ cc_test(
"//testing:gunit", "//testing:gunit",
"//testing:gunit_main", "//testing:gunit_main",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
], ],
) )
@@ -509,7 +508,7 @@ cc_library(
deps = [ deps = [
"//util:error_space", "//util:error_space",
"//util:proto_status", "//util:proto_status",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
], ],
) )
@@ -527,9 +526,9 @@ cc_library(
"//base", "//base",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:remote_attestation_proto", "//protos/public:remote_attestation_cc_proto",
], ],
) )
@@ -549,10 +548,10 @@ cc_library(
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//util/gtl:map_util", "//util/gtl:map_util",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:drm_certificate_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:signed_drm_certificate_proto", "//protos/public:signed_drm_certificate_cc_proto",
], ],
) )
@@ -572,11 +571,11 @@ cc_test(
"//external:protobuf", "//external:protobuf",
"//testing:gunit_main", "//testing:gunit_main",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:drm_certificate_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:license_server_sdk_cc_proto",
"//protos/public:signed_drm_certificate_proto", "//protos/public:signed_drm_certificate_cc_proto",
], ],
) )
@@ -589,7 +588,7 @@ cc_library(
":vmp_checker", ":vmp_checker",
"//base", "//base",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
], ],
) )
@@ -646,8 +645,8 @@ cc_library(
":status", ":status",
":x509_cert", ":x509_cert",
"//base", "//base",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:verified_media_pipeline_proto", "//protos/public:verified_media_pipeline_cc_proto",
], ],
) )
@@ -661,8 +660,8 @@ cc_test(
"//base", "//base",
"//testing:gunit_main", "//testing:gunit_main",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:verified_media_pipeline_proto", "//protos/public:verified_media_pipeline_cc_proto",
], ],
) )

View File

@@ -11,6 +11,7 @@
#include "common/device_status_list.h" #include "common/device_status_list.h"
#include <time.h> #include <time.h>
#include <memory> #include <memory>
#include "glog/logging.h" #include "glog/logging.h"
@@ -24,8 +25,13 @@
#include "common/drm_service_certificate.h" #include "common/drm_service_certificate.h"
#include "common/error_space.h" #include "common/error_space.h"
#include "common/rsa_key.h" #include "common/rsa_key.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h" #include "protos/public/client_identification.pb.h"
#include "protos/public/errors.pb.h" #include "protos/public/errors.pb.h"
#include "protos/public/signed_device_info.pb.h"
using ::widevine::DeviceCertificateStatusListRequest;
using ::widevine::SignedDeviceInfoRequest;
namespace widevine { namespace widevine {
@@ -54,19 +60,13 @@ DeviceStatusList::~DeviceStatusList() {}
Status DeviceStatusList::UpdateStatusList( Status DeviceStatusList::UpdateStatusList(
const std::string& root_certificate_public_key, const std::string& root_certificate_public_key,
const std::string& serialized_certificate_status_list, const std::string& serialized_device_certificate_status_list,
uint32_t expiration_period_seconds) { const std::string& signature, uint32_t expiration_period_seconds) {
SignedDeviceCertificateStatusList signed_certificate_status_list; if (serialized_device_certificate_status_list.empty()) {
if (!signed_certificate_status_list.ParseFromString(
serialized_certificate_status_list)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
}
if (!signed_certificate_status_list.has_certificate_status_list()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list"); "missing-status-list");
} }
if (!signed_certificate_status_list.has_signature()) { if (signature.empty()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list-signature"); "missing-status-list-signature");
} }
@@ -76,17 +76,16 @@ Status DeviceStatusList::UpdateStatusList(
return Status(error_space, INVALID_DRM_CERTIFICATE, return Status(error_space, INVALID_DRM_CERTIFICATE,
"invalid-root-public-key"); "invalid-root-public-key");
} }
if (!root_key->VerifySignature( if (!root_key->VerifySignature(serialized_device_certificate_status_list,
signed_certificate_status_list.certificate_status_list(), signature)) {
signed_certificate_status_list.signature())) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"invalid-status-list-signature"); "invalid-status-list-signature");
} }
DeviceCertificateStatusList certificate_status_list; DeviceCertificateStatusList certificate_status_list;
if (!certificate_status_list.ParseFromString( if (!certificate_status_list.ParseFromString(
signed_certificate_status_list.certificate_status_list())) { serialized_device_certificate_status_list)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error"); "signed-certificate-status-list-parse-error");
} }
if (expiration_period_seconds && if (expiration_period_seconds &&
(GetCurrentTime() > (certificate_status_list.creation_time_seconds() + (GetCurrentTime() > (certificate_status_list.creation_time_seconds() +
@@ -162,8 +161,16 @@ Status DeviceStatusList::GetCertStatus(const ClientCert& client_cert,
if ((device_cert_status->status() == if ((device_cert_status->status() ==
DeviceCertificateStatus::STATUS_TEST_ONLY) && DeviceCertificateStatus::STATUS_TEST_ONLY) &&
!allow_test_only_devices_) { !allow_test_only_devices_) {
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED, if (IsTestOnlyDeviceAllowed(client_cert.system_id(),
"test-only-drm-certificate-not-allowed"); device_info->manufacturer())) {
LOG(WARNING) << "Allowing TEST_ONLY device: "
<< device_info->ShortDebugString();
} else {
VLOG(2) << "TEST ONLY device with systemId: " << client_cert.system_id()
<< " not allowed";
return Status(error_space, DEVELOPMENT_CERTIFICATE_NOT_ALLOWED,
"test-only-drm-certificate-not-allowed");
}
} }
if (!client_cert.signed_by_provisioner() && if (!client_cert.signed_by_provisioner() &&
(client_cert.signer_serial_number() != (client_cert.signer_serial_number() !=
@@ -241,31 +248,83 @@ void DeviceStatusList::AllowRevokedDevices(const std::string& system_id_list) {
std::sort(allowed_revoked_devices_.begin(), allowed_revoked_devices_.end()); std::sort(allowed_revoked_devices_.begin(), allowed_revoked_devices_.end());
} }
void DeviceStatusList::AllowTestOnlyDevices(const std::string& device_list) {
absl::WriterMutexLock lock(&allowed_test_only_devices_mutex_);
// 'device_list' is expected to be of the format <device>,<device>..., and
// each 'device' will contain a 'system_id' and 'manufacturer' OR will contain
// only a 'system_id'.
for (absl::string_view device : absl::StrSplit(device_list, ',')) {
// 'device' is expected to be of the format <system_id>:<manufacturer> OR
// of the format <system_id>:
const std::pair<absl::string_view, absl::string_view> device_split =
absl::StrSplit(device, ':');
if (device_split.second.empty()) {
allowed_test_only_devices_[std::stoi(std::string(device_split.first))] = "*";
} else {
allowed_test_only_devices_[std::stoi(std::string(device_split.first))] =
std::string(device_split.second);
}
VLOG(2)
<< "Whitelisting TEST_ONLY device: systemId = "
<< std::stoi(std::string(device_split.first))
<< allowed_test_only_devices_[std::stoi(std::string(device_split.first))];
}
}
bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) { bool DeviceStatusList::IsRevokedSystemIdAllowed(uint32_t system_id) {
auto it = std::binary_search(allowed_revoked_devices_.begin(), auto it = std::binary_search(allowed_revoked_devices_.begin(),
allowed_revoked_devices_.end(), system_id); allowed_revoked_devices_.end(), system_id);
return it; return it;
} }
Status DeviceStatusList::ExtractFromProvisioningServiceResponse( bool DeviceStatusList::IsTestOnlyDeviceAllowed(uint32_t system_id,
const std::string& certificate_provisioning_service_response, std::string manufacturer) {
std::string* signed_certificate_status_list, std::string* certificate_status_list) { absl::ReaderMutexLock lock(&allowed_test_only_devices_mutex_);
Status status = OkStatus(); std::string* allowed_manufacturer =
size_t signed_list_start = gtl::FindOrNull(allowed_test_only_devices_, system_id);
certificate_provisioning_service_response.find(kSignedList); if (allowed_manufacturer == nullptr) {
if (signed_list_start != std::string::npos) { return false;
size_t signed_list_end = certificate_provisioning_service_response.find( }
kSignedListTerminator, signed_list_start); if (*allowed_manufacturer == "*" || *allowed_manufacturer == manufacturer) {
if (signed_list_end == std::string::npos) { return true;
}
return false;
}
Status DeviceStatusList::ExtractFromServiceResponse(
const std::string& service_response, std::string* serialized_certificate_status_list,
std::string* signature) {
// We support two types of payload parsing. First, is the legacy call which
// is a serialized SignedCertificateStatusList proto. The second is the
// newer SignedDeviceInfo.
// TODO(user): Add support for the new response type.
return ExtractLegacyDeviceList(service_response,
serialized_certificate_status_list, signature);
}
Status DeviceStatusList::ExtractLegacyDeviceList(
const std::string& raw_certificate_provisioning_service_response,
std::string* serialized_certificate_status_list, std::string* signature) {
// Example legacy format.
// "signedList":"<b64 encoded data>"
// where the b64 encoded data is a DeviceCertificateStatusListResponse.
size_t b64_list_response_start =
raw_certificate_provisioning_service_response.find(kSignedList);
std::string serialized_certificate_status_list_response;
if (b64_list_response_start != std::string::npos) {
size_t b64_list_response_end =
raw_certificate_provisioning_service_response.find(
kSignedListTerminator, b64_list_response_start);
if (b64_list_response_end == std::string::npos) {
return Status( return Status(
error_space, error::INVALID_ARGUMENT, error_space, error::INVALID_ARGUMENT,
"Unable to parse the certificate_provisioning_service_response. " "Unable to parse the certificate_provisioning_service_response. "
"SignedList not terminated."); "SignedList not terminated.");
} }
std::string signed_list( std::string signed_list(raw_certificate_provisioning_service_response.begin() +
certificate_provisioning_service_response.begin() + signed_list_start + b64_list_response_start + kSignedListLen,
kSignedListLen, raw_certificate_provisioning_service_response.begin() +
certificate_provisioning_service_response.begin() + signed_list_end); b64_list_response_end);
// Strip off quotes. // Strip off quotes.
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\"'), signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\"'),
@@ -281,9 +340,10 @@ Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
// Strip off carriage return (the control-M character) // Strip off carriage return (the control-M character)
signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\r'), signed_list.erase(std::remove(signed_list.begin(), signed_list.end(), '\r'),
signed_list.end()); signed_list.end());
if (!absl::WebSafeBase64Unescape(signed_list, if (!absl::WebSafeBase64Unescape(
signed_certificate_status_list)) { signed_list, &serialized_certificate_status_list_response)) {
if (!absl::Base64Unescape(signed_list, signed_certificate_status_list)) { if (!absl::Base64Unescape(signed_list,
&serialized_certificate_status_list_response)) {
return Status(error_space, error::INVALID_ARGUMENT, return Status(error_space, error::INVALID_ARGUMENT,
"Base64 decode of signedlist failed."); "Base64 decode of signedlist failed.");
} }
@@ -291,36 +351,32 @@ Status DeviceStatusList::ExtractFromProvisioningServiceResponse(
} else { } else {
// certificate_provisioning_service_response is the signed list and not a // certificate_provisioning_service_response is the signed list and not a
// JSON message. // JSON message.
if (!absl::WebSafeBase64Unescape(certificate_provisioning_service_response, if (!absl::WebSafeBase64Unescape(
signed_certificate_status_list)) { raw_certificate_provisioning_service_response,
if (!absl::Base64Unescape(certificate_provisioning_service_response, &serialized_certificate_status_list_response)) {
signed_certificate_status_list)) { if (!absl::Base64Unescape(raw_certificate_provisioning_service_response,
&serialized_certificate_status_list_response)) {
return Status(error_space, error::INVALID_ARGUMENT, return Status(error_space, error::INVALID_ARGUMENT,
"Base64 decode of certList failed."); "Base64 decode of certList failed.");
} }
} }
} }
SignedDeviceCertificateStatusList signed_status_list;
if (!signed_status_list.ParseFromString(*signed_certificate_status_list)) { return ParseSignedDeviceCertificateStatusList(
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, serialized_certificate_status_list_response,
"signed-certificate-status-list-parse-error"); serialized_certificate_status_list, signature);
} }
if (!signed_status_list.has_certificate_status_list()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST, Status DeviceStatusList::ExtractSignedDeviceInfo(
"missing-status-list"); const std::string& signed_device_info_response,
} std::string* serialized_certificate_status_list, std::string* signature) {
DeviceCertificateStatusList device_certificate_status_list; // TODO(user): Implement this.
if (!device_certificate_status_list.ParseFromString( return Status(error_space, error::UNIMPLEMENTED,
signed_status_list.certificate_status_list())) { "SignedDeviceInfo not yet supported.");
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error");
}
*certificate_status_list = signed_status_list.certificate_status_list();
return OkStatus();
} }
Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
const std::string& version, const std::string& version, const std::string& serialized_service_certificate,
std::string* signed_device_certificate_status_list_request) { std::string* signed_device_certificate_status_list_request) {
if (version.empty()) { if (version.empty()) {
return Status(error_space, error::INVALID_ARGUMENT, "SDK version is empty"); return Status(error_space, error::INVALID_ARGUMENT, "SDK version is empty");
@@ -334,9 +390,10 @@ Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
DeviceCertificateStatusListRequest request; DeviceCertificateStatusListRequest request;
request.set_sdk_version(version); request.set_sdk_version(version);
request.set_sdk_time_seconds(DeviceStatusList::Instance()->GetCurrentTime()); request.set_sdk_time_seconds(DeviceStatusList::Instance()->GetCurrentTime());
request.set_service_certificate(serialized_service_certificate);
std::string device_certificate_status_list_request; std::string device_certificate_status_list_request;
request.SerializeToString(&device_certificate_status_list_request); request.SerializeToString(&device_certificate_status_list_request);
SignedDeviceCertificateStatusListRequest signed_request; SignedDeviceInfoRequest signed_request;
signed_request.set_device_certificate_status_list_request( signed_request.set_device_certificate_status_list_request(
device_certificate_status_list_request); device_certificate_status_list_request);
const DrmServiceCertificate* sc = const DrmServiceCertificate* sc =
@@ -359,4 +416,34 @@ Status DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
signed_device_certificate_status_list_request); signed_device_certificate_status_list_request);
return OkStatus(); return OkStatus();
} }
Status DeviceStatusList::ParseSignedDeviceCertificateStatusList(
const std::string& serialized_signed_device_certificate_status_list,
std::string* serialized_device_certificate_status_list, std::string* signature) {
// Parse the serialized signed device info to extract the certificate
// status list.
SignedDeviceCertificateStatusList signed_device_list;
if (!signed_device_list.ParseFromString(
serialized_signed_device_certificate_status_list)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
}
if (signed_device_list.certificate_status_list().empty()) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"missing-status-list");
}
// Parse the DCSL to verify that it's a properly serialized protobuf.
DeviceCertificateStatusList certificate_status_list;
if (!certificate_status_list.ParseFromString(
signed_device_list.certificate_status_list())) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"certificate-status-list-parse-error");
}
// TODO(user): See if we can refactor this. It seems weird to deserialize
// the proto but then pass around the serialized proto.
*serialized_device_certificate_status_list =
signed_device_list.certificate_status_list();
*signature = signed_device_list.signature();
return OkStatus();
}
} // namespace widevine } // namespace widevine

View File

@@ -19,6 +19,7 @@
#include "common/status.h" #include "common/status.h"
#include "protos/public/device_certificate_status.pb.h" #include "protos/public/device_certificate_status.pb.h"
#include "protos/public/provisioned_device_info.pb.h" #include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/signed_device_info.pb.h"
namespace widevine { namespace widevine {
@@ -37,12 +38,14 @@ class DeviceStatusList {
DeviceStatusList(); DeviceStatusList();
virtual ~DeviceStatusList(); virtual ~DeviceStatusList();
// Takes |serialized_certificate_status_list| and copies to an internal map of // Takes |serialized_device_certificate_status_list| and copies to an
// device certifcate status list. The internal map is used to verify // internal map of device certificate status list. The internal map is used
// a device was not revoked. Returns true is the list was successfully parsed. // to verify a device was not revoked. Returns true is the list was
Status UpdateStatusList(const std::string& root_certificate_public_key, // successfully parsed.
const std::string& serialized_certificate_status_list, Status UpdateStatusList(
uint32_t expiration_period_seconds); const std::string& root_certificate_public_key,
const std::string& serialized_device_certificate_status_list,
const std::string& signature, uint32_t expiration_period_seconds);
void set_allow_unknown_devices(bool flag) { allow_unknown_devices_ = flag; } void set_allow_unknown_devices(bool flag) { allow_unknown_devices_ = flag; }
bool allow_unknown_devices() const { return allow_unknown_devices_; } bool allow_unknown_devices() const { return allow_unknown_devices_; }
void set_allow_test_only_devices(bool allow) { void set_allow_test_only_devices(bool allow) {
@@ -76,18 +79,28 @@ class DeviceStatusList {
// a comma separated list of systems Ids to allow even if revoked. // a comma separated list of systems Ids to allow even if revoked.
virtual void AllowRevokedDevices(const std::string& system_id_list); virtual void AllowRevokedDevices(const std::string& system_id_list);
// Enable delivery of licenses to TEST_ONLY client devices. |device_list| is
// a comma separated list of devices to allow even if the device state is
// TEST_ONLY. Each device is specified by a colon separated system_id and
// manufacturer. If the manufacturer is not specified, all manufacturers for
// that system_id are allowed.
virtual void AllowTestOnlyDevices(const std::string& device_list);
/** /**
* Parses signed device certificate status list and certificate status list * Parses the serialized certificate status list and the signature from the
* from certificateProvisoningServer response. * service_response. The service_response is the JSON payload that comes
* in the response to a certificate status list request. Both the legacy
* format and the newer SignedDeviceInfo format are supported.
* *
* @param certificate_provisioning_service_response * @param service_response
* @param signed_certificate_status_list * @param serialized_certificate_status_list
* @param certificate_status_list * @param signature
* @return WvPLStatus - Status::OK if success, else error. * @return WvPLStatus - Status::OK if success, else error.
*/ */
static Status ExtractFromProvisioningServiceResponse( static Status ExtractFromServiceResponse(
const std::string& certificate_provisioning_service_response, const std::string& service_response,
std::string* signed_certificate_status_list, std::string* certificate_status_list); std::string* serialized_certificate_status_list, std::string* signature);
/** /**
* Constructs signed device certificate status list request string. * Constructs signed device certificate status list request string.
* *
@@ -96,13 +109,60 @@ class DeviceStatusList {
* @return Status - Status::OK if success, else error. * @return Status - Status::OK if success, else error.
*/ */
static Status GenerateSignedDeviceCertificateStatusListRequest( static Status GenerateSignedDeviceCertificateStatusListRequest(
const std::string& version, const std::string& version, const std::string& serialized_service_certificate,
std::string* signed_device_certificate_status_list_request); std::string* signed_device_certificate_status_list_request);
private: private:
friend class DeviceStatusListTest;
/**
* Parses the serialized legacy device certificate status list and signature.
* The certificate_provisioning_service_response is the JSON payload that
* comes in the response to a certificate status list request.
*
* @param legacy_certificate_provisioning_service_response
* @param serialized_certificate_status_list
* @param signature
* @return WvPLStatus - Status::OK if success, else error.
*/
static Status ExtractLegacyDeviceList(
const std::string& raw_certificate_provisioning_service_response,
std::string* serialized_certificate_status_list, std::string* signature);
/**
* Parses the serialized signed device info response.
* The signed_device_info_response is the JSON payload that comes in the
* response to a signed device info request.
*
* @param legacy_certificate_provisioning_service_response
* @param serialized_certificate_status_list
* @param signature
* @return WvPLStatus - Status::OK if success, else error.
*/
static Status ExtractSignedDeviceInfo(
const std::string& signed_device_info_response,
std::string* serialized_certificate_status_list, std::string* signature);
/**
* Returns a |serialized_device_certificate_status_list| in its output
* parameter by parsing |serialized_signed_device_certificate_status_list|
* returned from Widevine Certificate Provisioning Server.
*
* @param serialized_signed_device_certificate_status_list
* @param serialized_device_certificate_status_list
*
* @return Status - Status::OK if success, else error.
*/
static Status ParseSignedDeviceCertificateStatusList(
const std::string& serialized_signed_device_certificate_status_list,
std::string* serialized_device_certificate_status_list, std::string* signature);
// Returns true if the system ID is allowed to be revoked. // Returns true if the system ID is allowed to be revoked.
// Caller owns |system_id|. They must not be null. // Caller owns |system_id|. They must not be null.
bool IsRevokedSystemIdAllowed(uint32_t system_id); bool IsRevokedSystemIdAllowed(uint32_t system_id);
// Returns true if the device, which is identified by system_id and
// manufacturer, is present in |allowed_test_only_devices_|.
bool IsTestOnlyDeviceAllowed(uint32_t system_id, std::string manufacturer);
absl::Mutex status_map_lock_; absl::Mutex status_map_lock_;
// Key is the system id for the device. // Key is the system id for the device.
@@ -114,6 +174,12 @@ class DeviceStatusList {
// Contains the list of system_id values that are allowed to succeed even if // Contains the list of system_id values that are allowed to succeed even if
// revoked. // revoked.
std::vector<uint32_t> allowed_revoked_devices_; std::vector<uint32_t> allowed_revoked_devices_;
absl::Mutex allowed_test_only_devices_mutex_;
// Contains a map of TEST_ONLY devices that are allowed, even if TEST_ONLY
// devices are prohibited. Contains mappings of 'system_id' to
// 'manufacturer'. If 'manufacturer' value is "*", any 'manufacturer' for
// that 'system_id' is allowed.
std::map<uint32_t, std::string> allowed_test_only_devices_;
DISALLOW_COPY_AND_ASSIGN(DeviceStatusList); DISALLOW_COPY_AND_ASSIGN(DeviceStatusList);
}; };

View File

@@ -9,6 +9,7 @@
#include "common/device_status_list.h" #include "common/device_status_list.h"
#include <stddef.h> #include <stddef.h>
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@@ -16,15 +17,26 @@
#include "glog/logging.h" #include "glog/logging.h"
#include "testing/gmock.h" #include "testing/gmock.h"
#include "testing/gunit.h" #include "testing/gunit.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "common/client_cert.h" #include "common/client_cert.h"
#include "common/rsa_key.h" #include "common/rsa_key.h"
#include "common/rsa_test_keys.h" #include "common/rsa_test_keys.h"
#include "common/status.h"
#include "protos/public/client_identification.pb.h" #include "protos/public/client_identification.pb.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/errors.pb.h" #include "protos/public/errors.pb.h"
#include "protos/public/provisioned_device_info.pb.h" #include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/signed_drm_certificate.pb.h" #include "protos/public/signed_drm_certificate.pb.h"
namespace {
const char kTestSystemId_1[] = "4121";
const char kTestManufacturer_1[] = "LG";
const char kTestSystemId_2[] = "8242";
const char kTestManufacturer_2[] = "Samsung";
const char kTestSystemId_3[] = "6556";
} // namespace
namespace widevine { namespace widevine {
using ::testing::_; using ::testing::_;
@@ -103,26 +115,50 @@ class DeviceStatusListTest : public ::testing::Test {
cert_status_list_.set_creation_time_seconds(kStatusListCreationTime); cert_status_list_.set_creation_time_seconds(kStatusListCreationTime);
cert_status_list_.SerializeToString( cert_status_list_.SerializeToString(
signed_cert_status_list_.mutable_certificate_status_list()); legacy_signed_device_status_list_.mutable_certificate_status_list());
std::unique_ptr<RsaPrivateKey> root_key( std::unique_ptr<RsaPrivateKey> root_key(
RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits())); RsaPrivateKey::Create(test_keys_.private_test_key_1_3072_bits()));
ASSERT_TRUE(root_key); ASSERT_TRUE(root_key);
ASSERT_TRUE(root_key->GenerateSignature( ASSERT_TRUE(root_key->GenerateSignature(
signed_cert_status_list_.certificate_status_list(), legacy_signed_device_status_list_.certificate_status_list(),
signed_cert_status_list_.mutable_signature())); legacy_signed_device_status_list_.mutable_signature()));
ASSERT_TRUE( ASSERT_TRUE(legacy_signed_device_status_list_.SerializeToString(
signed_cert_status_list_.SerializeToString(&serialized_status_list_)); &serialized_status_list_));
ASSERT_EQ(OkStatus(), device_status_list_.UpdateStatusList( ASSERT_EQ(OkStatus(),
test_keys_.public_test_key_1_3072_bits(), device_status_list_.UpdateStatusList(
serialized_status_list_, kDefaultExpirePeriod)); test_keys_.public_test_key_1_3072_bits(),
legacy_signed_device_status_list_.certificate_status_list(),
legacy_signed_device_status_list_.signature(),
kDefaultExpirePeriod));
std::string serialized_signed_device_info;
ASSERT_TRUE(legacy_signed_device_status_list_.SerializeToString(
&serialized_signed_device_info));
std::string dcsl;
std::string signature;
ASSERT_EQ(OkStatus(),
DeviceStatusList::ParseSignedDeviceCertificateStatusList(
serialized_signed_device_info, &dcsl, &signature));
ASSERT_EQ(dcsl,
legacy_signed_device_status_list_.certificate_status_list());
ASSERT_EQ(dcsl,
legacy_signed_device_status_list_.certificate_status_list());
}
int VerifyAllowedTestOnlyDevicesAdded() {
return device_status_list_.allowed_test_only_devices_.size();
}
bool VerifyIsTestOnlyDeviceAllowed(uint32_t system_id, std::string manufacturer) {
return device_status_list_.IsTestOnlyDeviceAllowed(system_id, manufacturer);
} }
DeviceStatusList device_status_list_; DeviceStatusList device_status_list_;
RsaTestKeys test_keys_; RsaTestKeys test_keys_;
DeviceCertificateStatusList cert_status_list_; DeviceCertificateStatusList cert_status_list_;
SignedDeviceCertificateStatusList signed_cert_status_list_; SignedDeviceInfo tmp_signed_device_info_;
SignedDeviceCertificateStatusList legacy_signed_device_status_list_;
std::string serialized_status_list_; std::string serialized_status_list_;
}; };
@@ -288,17 +324,19 @@ TEST_F(DeviceStatusListTest, SignerSerialNumberMismatch) {
TEST_F(DeviceStatusListTest, InvalidStatusList) { TEST_F(DeviceStatusListTest, InvalidStatusList) {
EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST, EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST,
device_status_list_ device_status_list_
.UpdateStatusList(test_keys_.public_test_key_2_2048_bits(), .UpdateStatusList(
serialized_status_list_, 0) test_keys_.public_test_key_2_2048_bits(),
legacy_signed_device_status_list_.certificate_status_list(),
legacy_signed_device_status_list_.signature(), 0)
.error_code()); .error_code());
++(*signed_cert_status_list_.mutable_certificate_status_list())[4]; ++(*legacy_signed_device_status_list_.mutable_certificate_status_list())[4];
ASSERT_TRUE(
signed_cert_status_list_.SerializeToString(&serialized_status_list_));
EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST, EXPECT_EQ(INVALID_CERTIFICATE_STATUS_LIST,
device_status_list_ device_status_list_
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(), .UpdateStatusList(
serialized_status_list_, 0) test_keys_.public_test_key_1_3072_bits(),
legacy_signed_device_status_list_.certificate_status_list(),
legacy_signed_device_status_list_.signature(), 0)
.error_code()); .error_code());
} }
@@ -313,13 +351,17 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnSet) {
.Times(2) .Times(2)
.WillOnce(Return(kStatusListCreationTime + 100)) .WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101)); .WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList( EXPECT_EQ(OkStatus(),
test_keys_.public_test_key_1_3072_bits(), mock_device_status_list.UpdateStatusList(
serialized_status_list_, 100)); test_keys_.public_test_key_1_3072_bits(),
legacy_signed_device_status_list_.certificate_status_list(),
legacy_signed_device_status_list_.signature(), 100));
EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST, EXPECT_EQ(EXPIRED_CERTIFICATE_STATUS_LIST,
mock_device_status_list mock_device_status_list
.UpdateStatusList(test_keys_.public_test_key_1_3072_bits(), .UpdateStatusList(
serialized_status_list_, 100) test_keys_.public_test_key_1_3072_bits(),
legacy_signed_device_status_list_.certificate_status_list(),
legacy_signed_device_status_list_.signature(), 100)
.error_code()); .error_code());
} }
@@ -330,9 +372,11 @@ TEST_F(DeviceStatusListTest, ExpiredStatusListOnCertCheck) {
.WillOnce(Return(kStatusListCreationTime + 100)) .WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 100)) .WillOnce(Return(kStatusListCreationTime + 100))
.WillOnce(Return(kStatusListCreationTime + 101)); .WillOnce(Return(kStatusListCreationTime + 101));
EXPECT_EQ(OkStatus(), mock_device_status_list.UpdateStatusList( EXPECT_EQ(OkStatus(),
test_keys_.public_test_key_1_3072_bits(), mock_device_status_list.UpdateStatusList(
serialized_status_list_, 100)); test_keys_.public_test_key_1_3072_bits(),
legacy_signed_device_status_list_.certificate_status_list(),
legacy_signed_device_status_list_.signature(), 100));
ProvisionedDeviceInfo device_info; ProvisionedDeviceInfo device_info;
MockCertificateClientCert valid_client_cert; MockCertificateClientCert valid_client_cert;
@@ -373,4 +417,33 @@ TEST_F(DeviceStatusListTest, IsSystemIdActive) {
device_status_list_.IsSystemIdActive(kRevokedAllowedDeviceCertSystemId)); device_status_list_.IsSystemIdActive(kRevokedAllowedDeviceCertSystemId));
} }
TEST_F(DeviceStatusListTest, IsTestOnlyDeviceAllowed) {
std::string device_list =
std::string(kTestSystemId_1) + ":" + std::string(kTestManufacturer_1);
device_list +=
"," + std::string(kTestSystemId_2) + ":" + std::string(kTestManufacturer_2);
device_list += "," + std::string(kTestSystemId_3) + ":";
device_status_list_.AllowTestOnlyDevices(device_list);
EXPECT_EQ(3, VerifyAllowedTestOnlyDevicesAdded());
// Verify that device with system_id = kTestSystemId_1 and
// manufacturer = kTestManufacturer_1 is allowed.
EXPECT_TRUE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_1),
kTestManufacturer_1));
// Verify that device with system_id = kTestSystemId_2 and
// manufacturer = kTestManufacturer_2 is allowed.
EXPECT_TRUE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_2),
kTestManufacturer_2));
// Verify that device with system_id = kTestSystemId_3 and
// any manufacturer is allowed. This checks that any manufacturer is
// allowed for this system_id.
EXPECT_TRUE(
VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_3), "Cisco"));
EXPECT_TRUE(VerifyIsTestOnlyDeviceAllowed(std::stoi(kTestSystemId_3),
"ScientificAtlanta"));
uint32_t unknown_system_id = 7890;
// Verify that device with system_id = unknown_system_id and
// manufacturer = "Cisco" is not allowed.
EXPECT_FALSE(VerifyIsTestOnlyDeviceAllowed(unknown_system_id, "Cisco"));
}
} // namespace widevine } // namespace widevine

View File

@@ -80,10 +80,11 @@ TEST(DrmRootCertificateTestCertificatesTest, Success) {
->VerifyCertificate(test_certs.test_user_device_certificate(), ->VerifyCertificate(test_certs.test_user_device_certificate(),
nullptr, nullptr) nullptr, nullptr)
.ok()); .ok());
EXPECT_TRUE(root_cert EXPECT_TRUE(
->VerifyCertificate(test_certs.test_service_certificate(), root_cert
nullptr, nullptr) ->VerifyCertificate(test_certs.test_service_certificate_no_type(),
.ok()); nullptr, nullptr)
.ok());
} }
class DrmRootCertificateTest : public testing::Test { class DrmRootCertificateTest : public testing::Test {

View File

@@ -44,8 +44,9 @@ class DrmServiceCertificateMap {
void AddCert(std::unique_ptr<DrmServiceCertificate> new_cert); void AddCert(std::unique_ptr<DrmServiceCertificate> new_cert);
void ClearDefaultDrmServiceCertificate(); void ClearDefaultDrmServiceCertificate();
const DrmServiceCertificate* GetDefaultCert(); const DrmServiceCertificate* GetDefaultCert();
const DrmServiceCertificate* GetCert(const std::string& serial_number); const DrmServiceCertificate* GetCertBySerialNumber(
const std::string& serial_number);
const DrmServiceCertificate* GetCertByProvider(const std::string& provider_id);
static DrmServiceCertificateMap* GetInstance(); static DrmServiceCertificateMap* GetInstance();
private: private:
@@ -94,12 +95,30 @@ const DrmServiceCertificate* DrmServiceCertificateMap::GetDefaultCert() {
return default_cert_; return default_cert_;
} }
const DrmServiceCertificate* DrmServiceCertificateMap::GetCert( const DrmServiceCertificate* DrmServiceCertificateMap::GetCertBySerialNumber(
const std::string& serial_number) { const std::string& serial_number) {
absl::ReaderMutexLock lock(&mutex_); absl::ReaderMutexLock lock(&mutex_);
return map_[serial_number].get(); return map_[serial_number].get();
} }
const DrmServiceCertificate* DrmServiceCertificateMap::GetCertByProvider(
const std::string& provider_id) {
absl::ReaderMutexLock lock(&mutex_);
DrmServiceCertificate* provider_drm_cert = nullptr;
for (const auto& drm_cert : map_) {
if (drm_cert.second->provider_id() == provider_id) {
if (provider_drm_cert == nullptr) {
provider_drm_cert = drm_cert.second.get();
} else if (drm_cert.second->creation_time_seconds() >
provider_drm_cert->creation_time_seconds()) {
// Use the newest cert.
provider_drm_cert = drm_cert.second.get();
}
}
}
return provider_drm_cert;
}
DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() { DrmServiceCertificateMap* DrmServiceCertificateMap::GetInstance() {
static auto* const kInstance = new DrmServiceCertificateMap(); static auto* const kInstance = new DrmServiceCertificateMap();
return kInstance; return kInstance;
@@ -166,9 +185,17 @@ DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie() {
return default_cert; return default_cert;
} }
const DrmServiceCertificate* DrmServiceCertificate::GetDrmServiceCertificate( const DrmServiceCertificate*
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
const std::string& serial_number) { const std::string& serial_number) {
return DrmServiceCertificateMap::GetInstance()->GetCert(serial_number); return DrmServiceCertificateMap::GetInstance()->GetCertBySerialNumber(
serial_number);
}
const DrmServiceCertificate*
DrmServiceCertificate::GetDrmServiceCertificateByProvider(
const std::string& provider) {
return DrmServiceCertificateMap::GetInstance()->GetCertByProvider(provider);
} }
Status DrmServiceCertificate::SetDefaultDrmServiceCertificate( Status DrmServiceCertificate::SetDefaultDrmServiceCertificate(
@@ -207,7 +234,7 @@ Status DrmServiceCertificate::DecryptClientIdentification(
} }
std::string privacy_key; std::string privacy_key;
std::string provider_id; std::string provider_id;
const DrmServiceCertificate* cert = GetDrmServiceCertificate( const DrmServiceCertificate* cert = GetDrmServiceCertificateBySerialNumber(
encrypted_client_id.service_certificate_serial_number()); encrypted_client_id.service_certificate_serial_number());
if (!cert) { if (!cert) {
return Status( return Status(

View File

@@ -69,11 +69,17 @@ class DrmServiceCertificate {
// Certificate is set. This method is thread-safe. // Certificate is set. This method is thread-safe.
static const DrmServiceCertificate* GetDefaultDrmServiceCertificateOrDie(); static const DrmServiceCertificate* GetDefaultDrmServiceCertificateOrDie();
// Returns the service certificate with the given serial number if found, or // Returns the service certificate with the given |cert_serial_number|, or
// null otherwise. // null otherwise.
static const DrmServiceCertificate* GetDrmServiceCertificate( static const DrmServiceCertificate* GetDrmServiceCertificateBySerialNumber(
const std::string& cert_serial_number); const std::string& cert_serial_number);
// Returns the service certificate with the given |provider_id|, or
// null otherwise. If multple certificates exist for the provider, the
// newest certificate is returned.
static const DrmServiceCertificate* GetDrmServiceCertificateByProvider(
const std::string& provider_id);
// Decrypts the EncryptedClientIdentification message passed in // Decrypts the EncryptedClientIdentification message passed in
// |encrypted_client_id| into |client_id| using the private key for the // |encrypted_client_id| into |client_id| using the private key for the
// certificate which was used to encrypt the information. |client_id| must // certificate which was used to encrypt the information. |client_id| must
@@ -86,6 +92,7 @@ class DrmServiceCertificate {
const std::string& certificate() const { return certificate_; } const std::string& certificate() const { return certificate_; }
const std::string& provider_id() const { return provider_id_; } const std::string& provider_id() const { return provider_id_; }
const std::string& serial_number() const { return serial_number_; } const std::string& serial_number() const { return serial_number_; }
uint32_t creation_time_seconds() const { return creation_time_seconds_; }
const RsaPrivateKey* const private_key() const { return private_key_.get(); } const RsaPrivateKey* const private_key() const { return private_key_.get(); }
const RsaPublicKey* const public_key() const { return public_key_.get(); } const RsaPublicKey* const public_key() const { return public_key_.get(); }

View File

@@ -160,6 +160,9 @@ TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificates) {
uint32_t creation_time_seconds1(1234); uint32_t creation_time_seconds1(1234);
std::string serial_number2("serial_number2"); std::string serial_number2("serial_number2");
uint32_t creation_time_seconds2(1234); uint32_t creation_time_seconds2(1234);
std::string serial_number3("serial_number3");
std::string provider_id3("service3.com");
uint32_t creation_time_seconds3(1235);
std::string bogus_serial_number("bogus-serial-number2"); std::string bogus_serial_number("bogus-serial-number2");
EXPECT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate()); EXPECT_EQ(nullptr, DrmServiceCertificate::GetDefaultDrmServiceCertificate());
@@ -172,6 +175,9 @@ TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificates) {
EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id1, EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id1,
creation_time_seconds2)); creation_time_seconds2));
EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id3,
creation_time_seconds3));
EncryptedClientIdentification encrypted_client_id; EncryptedClientIdentification encrypted_client_id;
EncryptClientIdentification(serial_number1, provider_id1, EncryptClientIdentification(serial_number1, provider_id1,
test_keys_.public_test_key_2_2048_bits(), test_keys_.public_test_key_2_2048_bits(),
@@ -199,6 +205,61 @@ TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificates) {
.error_code()); .error_code());
} }
TEST_F(DrmServiceCertificateTest, MultipleDrmServiceCertificatesLookup) {
std::string serial_number1("serial_number1");
std::string provider_id1("service1.com");
uint32_t creation_time_seconds1(1231);
std::string serial_number2("serial_number2");
std::string provider_id2("service2.com");
uint32_t creation_time_seconds2(1232);
std::string serial_number3("serial_number3");
std::string provider_id3("service3.com");
uint32_t creation_time_seconds3(1234);
std::string serial_number4("serial_number4");
std::string bogus_serial_number("bogus-serial-number");
EXPECT_OK(AddDrmServiceCertificate(serial_number1, provider_id1,
creation_time_seconds1));
EXPECT_OK(AddDrmServiceCertificate(serial_number2, provider_id2,
creation_time_seconds2));
EXPECT_OK(AddDrmServiceCertificate(serial_number3, provider_id3,
creation_time_seconds3));
EXPECT_EQ(provider_id1,
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
serial_number1)
->provider_id());
EXPECT_EQ(provider_id2,
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
serial_number2)
->provider_id());
EXPECT_EQ(provider_id3,
DrmServiceCertificate::GetDrmServiceCertificateBySerialNumber(
serial_number3)
->provider_id());
EXPECT_EQ(
serial_number1,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id1)
->serial_number());
EXPECT_EQ(
serial_number2,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id2)
->serial_number());
EXPECT_EQ(
serial_number3,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id3)
->serial_number());
// Add a second cert for provider 3.
EXPECT_OK(AddDrmServiceCertificate(serial_number4, provider_id3,
creation_time_seconds3 + 60));
EXPECT_EQ(
serial_number4,
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider_id3)
->serial_number());
}
TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) { TEST_F(DrmServiceCertificateTest, MultipleCertsPerService) {
std::string serial_number1("serial_number1"); std::string serial_number1("serial_number1");
std::string serial_number2("serial_number2"); std::string serial_number2("serial_number2");

View File

@@ -250,7 +250,130 @@ const unsigned char kTestUserDrmCertificate[] = {
0x82, 0xc8, 0xff, 0x4d, 0xef, 0x98, 0xcf, 0xb5, 0x6f, 0x6b, 0x55, 0xf8, 0x82, 0xc8, 0xff, 0x4d, 0xef, 0x98, 0xcf, 0xb5, 0x6f, 0x6b, 0x55, 0xf8,
0xd4, 0x4a, 0xa2, 0x84, 0x3c, 0xec, 0x1a}; 0xd4, 0x4a, 0xa2, 0x84, 0x3c, 0xec, 0x1a};
const unsigned char kTestDrmServiceCertificate[] = { const unsigned char kTestDrmServiceCertificateLicenseSdk[] = {
0x0a, 0xbe, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32,
0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18,
0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02,
0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54,
0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58,
0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57,
0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa,
0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e,
0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda,
0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9,
0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2,
0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e,
0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a,
0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67,
0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56,
0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b,
0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83,
0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1,
0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f,
0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40,
0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46,
0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86,
0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b,
0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b,
0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00,
0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x40, 0x01, 0x12, 0x80, 0x03,
0x1e, 0xa4, 0x3f, 0x68, 0x74, 0x1c, 0xcd, 0x8c, 0xa3, 0xfe, 0xa7, 0x08,
0x95, 0x31, 0x32, 0x97, 0x9b, 0x0a, 0x20, 0x55, 0x5a, 0xc3, 0xbb, 0x1c,
0xf8, 0x04, 0x9c, 0x31, 0x26, 0xc0, 0x93, 0xb3, 0x18, 0x5b, 0x98, 0x23,
0x8f, 0xc3, 0x7e, 0xdf, 0x59, 0xa5, 0x30, 0xb6, 0x2e, 0x13, 0x14, 0xd6,
0xfd, 0x24, 0xf1, 0xca, 0x6a, 0x9f, 0x5b, 0xe0, 0x0e, 0x73, 0x43, 0xd9,
0x7a, 0x2e, 0x05, 0x1c, 0x9e, 0x95, 0xc1, 0x0a, 0xa6, 0x1a, 0xcc, 0x96,
0x91, 0x03, 0x39, 0xaf, 0xd5, 0xb5, 0xdf, 0x0a, 0xa7, 0x51, 0x1d, 0x6c,
0x31, 0xa7, 0x24, 0x06, 0x5b, 0x14, 0x25, 0xff, 0x8f, 0x88, 0x83, 0x81,
0xc3, 0xb5, 0xf8, 0x3e, 0xa8, 0x0e, 0xe7, 0xe4, 0x5b, 0x83, 0xad, 0xc0,
0xe8, 0x31, 0x2d, 0x22, 0x11, 0x3e, 0xed, 0xd4, 0xde, 0x41, 0x49, 0x08,
0x37, 0x6d, 0x3e, 0x27, 0x2e, 0x89, 0xc0, 0x9f, 0x9c, 0x75, 0xfa, 0xff,
0x54, 0x22, 0x6f, 0x3f, 0x0d, 0x38, 0x4f, 0xb1, 0x49, 0xd3, 0xef, 0x37,
0x80, 0x39, 0x41, 0x1f, 0x03, 0x93, 0xd1, 0x19, 0xb1, 0xba, 0x61, 0xa7,
0x86, 0xbb, 0x3f, 0xd3, 0xa2, 0x1a, 0xa3, 0x8a, 0xfa, 0xef, 0x14, 0x36,
0xe1, 0xec, 0xfd, 0x7d, 0xcc, 0xe5, 0x8d, 0x3e, 0x4c, 0x30, 0xa7, 0x9e,
0x59, 0xe6, 0x27, 0xf2, 0xed, 0x07, 0xc8, 0x18, 0xf2, 0x14, 0x4c, 0x25,
0x0e, 0x72, 0xdd, 0x75, 0x9e, 0x8b, 0xf9, 0x41, 0xac, 0x5b, 0x26, 0x2d,
0x56, 0x0d, 0x18, 0x3d, 0xaa, 0x16, 0x48, 0x7c, 0xd1, 0x09, 0x89, 0x68,
0xac, 0x95, 0x06, 0xce, 0xa8, 0xfa, 0x93, 0x10, 0x60, 0xe3, 0x43, 0x26,
0x16, 0x0b, 0xbc, 0x44, 0x40, 0x02, 0xf5, 0x72, 0x87, 0x70, 0x08, 0x92,
0x28, 0xcb, 0xa8, 0x14, 0x41, 0xbf, 0x59, 0xaa, 0x14, 0x0c, 0x10, 0x2f,
0x1d, 0x89, 0xe4, 0x1e, 0x83, 0x76, 0x48, 0x82, 0x1f, 0x3c, 0x63, 0x36,
0x6b, 0xaa, 0x33, 0x4f, 0xe0, 0x00, 0x4b, 0x48, 0x71, 0x39, 0x5e, 0x85,
0xd4, 0x47, 0x7a, 0x31, 0x0a, 0x3b, 0x31, 0x90, 0x28, 0x1c, 0x4e, 0x4e,
0x3e, 0xb2, 0x02, 0xf0, 0xb9, 0x71, 0xe3, 0xef, 0x22, 0x63, 0xf2, 0x97,
0x9c, 0xe8, 0x16, 0xfc, 0x06, 0xa4, 0xf8, 0xfa, 0xe6, 0xd2, 0x82, 0x7f,
0xd5, 0x70, 0x9b, 0xd8, 0xb9, 0xcd, 0xbc, 0xc6, 0x9d, 0xd3, 0x52, 0xf7,
0x05, 0xa6, 0x25, 0xb8, 0x71, 0x3c, 0x15, 0x29, 0x36, 0xab, 0xb2, 0xa2,
0xc7, 0xe5, 0xa1, 0x0b, 0x85, 0x4d, 0xa5, 0xb5, 0x4f, 0xda, 0xcd, 0x0a,
0x8e, 0x8a, 0xbd, 0x2e, 0xf1, 0x2b, 0x0e, 0xdb, 0xf7, 0x9c, 0x9d, 0xcb,
0x69, 0xe0, 0x37, 0xea, 0xb1, 0x32, 0x71, 0x09, 0x4f, 0x72, 0x42, 0x3c,
0xdf, 0xe9, 0x5c, 0x40, 0x28, 0x32, 0x82, 0xb2, 0x4e, 0x77, 0xdd, 0x06};
const unsigned char kTestDrmServiceCertificateAllTypes[] = {
0x0a, 0xc2, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32,
0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18,
0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02,
0x82, 0x01, 0x01, 0x00, 0xa7, 0x00, 0x36, 0x60, 0x65, 0xdc, 0xbd, 0x54,
0x5a, 0x2a, 0x40, 0xb4, 0xe1, 0x15, 0x94, 0x58, 0x11, 0x4f, 0x94, 0x58,
0xdd, 0xde, 0xa7, 0x1f, 0x3c, 0x2c, 0xe0, 0x88, 0x09, 0x29, 0x61, 0x57,
0x67, 0x5e, 0x56, 0x7e, 0xee, 0x27, 0x8f, 0x59, 0x34, 0x9a, 0x2a, 0xaa,
0x9d, 0xb4, 0x4e, 0xfa, 0xa7, 0x6a, 0xd4, 0xc9, 0x7a, 0x53, 0xc1, 0x4e,
0x9f, 0xe3, 0x34, 0xf7, 0x3d, 0xb7, 0xc9, 0x10, 0x47, 0x4f, 0x28, 0xda,
0x3f, 0xce, 0x31, 0x7b, 0xfd, 0x06, 0x10, 0xeb, 0xf7, 0xbe, 0x92, 0xf9,
0xaf, 0xfb, 0x3e, 0x68, 0xda, 0xee, 0x1a, 0x64, 0x4c, 0xf3, 0x29, 0xf2,
0x73, 0x9e, 0x39, 0xd8, 0xf6, 0x6f, 0xd8, 0xb2, 0x80, 0x82, 0x71, 0x8e,
0xb5, 0xa4, 0xf2, 0xc2, 0x3e, 0xcd, 0x0a, 0xca, 0xb6, 0x04, 0xcd, 0x9a,
0x13, 0x8b, 0x54, 0x73, 0x54, 0x25, 0x54, 0x8c, 0xbe, 0x98, 0x7a, 0x67,
0xad, 0xda, 0xb3, 0x4e, 0xb3, 0xfa, 0x82, 0xa8, 0x4a, 0x67, 0x98, 0x56,
0x57, 0x54, 0x71, 0xcd, 0x12, 0x7f, 0xed, 0xa3, 0x01, 0xc0, 0x6a, 0x8b,
0x24, 0x03, 0x96, 0x88, 0xbe, 0x97, 0x66, 0x2a, 0xbc, 0x53, 0xc9, 0x83,
0x06, 0x51, 0x5a, 0x88, 0x65, 0x13, 0x18, 0xe4, 0x3a, 0xed, 0x6b, 0xf1,
0x61, 0x5b, 0x4c, 0xc8, 0x1e, 0xf4, 0xc2, 0xae, 0x08, 0x5e, 0x2d, 0x5f,
0xf8, 0x12, 0x7f, 0xa2, 0xfc, 0xbb, 0x21, 0x18, 0x30, 0xda, 0xfe, 0x40,
0xfb, 0x01, 0xca, 0x2e, 0x37, 0x0e, 0xce, 0xdd, 0x76, 0x87, 0x82, 0x46,
0x0b, 0x3a, 0x77, 0x8f, 0xc0, 0x72, 0x07, 0x2c, 0x7f, 0x9d, 0x1e, 0x86,
0x5b, 0xed, 0x27, 0x29, 0xdf, 0x03, 0x97, 0x62, 0xef, 0x44, 0xd3, 0x5b,
0x3d, 0xdb, 0x9c, 0x5e, 0x1b, 0x7b, 0x39, 0xb4, 0x0b, 0x6d, 0x04, 0x6b,
0xbb, 0xbb, 0x2c, 0x5f, 0xcf, 0xb3, 0x7a, 0x05, 0x02, 0x03, 0x01, 0x00,
0x01, 0x3a, 0x10, 0x73, 0x6f, 0x6d, 0x65, 0x5f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x40, 0x01, 0x40, 0x02, 0x40,
0x03, 0x12, 0x80, 0x03, 0x78, 0x86, 0x5a, 0xfa, 0x0f, 0x0d, 0x39, 0x6c,
0x19, 0x33, 0x24, 0x2d, 0x20, 0xbd, 0x34, 0xcc, 0x6e, 0xb8, 0x68, 0x36,
0x8d, 0x75, 0xc6, 0xbe, 0x6f, 0x8b, 0x98, 0x53, 0x4f, 0xed, 0x6e, 0x78,
0x2e, 0x15, 0xde, 0x82, 0x37, 0xa3, 0xc5, 0x1f, 0x82, 0xb4, 0xec, 0x4b,
0x5f, 0xb3, 0xd8, 0x99, 0xf4, 0xb1, 0x9a, 0x49, 0x15, 0xd8, 0x80, 0xcc,
0x7c, 0x16, 0xd9, 0xd8, 0x57, 0x59, 0x36, 0x34, 0xd0, 0x0e, 0xbb, 0x62,
0x76, 0x96, 0x73, 0x3b, 0xd9, 0xea, 0x61, 0x16, 0x3d, 0xdd, 0x38, 0xef,
0x25, 0x13, 0xbd, 0xe4, 0xa8, 0x69, 0x17, 0x81, 0x79, 0x2a, 0xe3, 0x29,
0xac, 0x68, 0xb1, 0x5f, 0x4e, 0x5f, 0xb5, 0x45, 0x71, 0xa6, 0x38, 0x6d,
0xce, 0x90, 0x7e, 0x0c, 0x5a, 0x7b, 0x6a, 0xce, 0xfa, 0x77, 0xf2, 0x57,
0xa9, 0x2f, 0x8e, 0xc1, 0x0f, 0x9b, 0x0f, 0xe1, 0xf5, 0x6e, 0x12, 0xf4,
0xac, 0x43, 0x95, 0x72, 0x73, 0x75, 0x0d, 0x3f, 0xc5, 0xac, 0x82, 0x04,
0x79, 0xab, 0x01, 0xc1, 0x71, 0x67, 0x3a, 0x0d, 0xf0, 0xa7, 0x74, 0x94,
0xd8, 0xe3, 0xf4, 0x3d, 0x92, 0x6b, 0x62, 0x63, 0xad, 0x3a, 0x95, 0x1a,
0x84, 0x00, 0x2d, 0x4b, 0x06, 0x8a, 0x26, 0x65, 0xa9, 0xeb, 0xb4, 0x4f,
0x7f, 0x66, 0x32, 0x59, 0x55, 0x89, 0x1d, 0x00, 0x5e, 0xed, 0x53, 0x4f,
0x36, 0xce, 0xc9, 0x9b, 0xfb, 0xa4, 0x04, 0x3a, 0x2f, 0xd9, 0x68, 0x9c,
0x98, 0xf3, 0xfc, 0xc6, 0x07, 0xc2, 0x00, 0x17, 0x39, 0x27, 0xb4, 0x13,
0x49, 0x23, 0x4a, 0xf4, 0x96, 0xf1, 0x3e, 0x5d, 0x66, 0x04, 0xe2, 0x93,
0xf9, 0x2c, 0x08, 0xa7, 0x08, 0x65, 0x39, 0x0f, 0xa9, 0xec, 0x55, 0x24,
0xab, 0x46, 0x32, 0x48, 0xd0, 0xd2, 0x44, 0x64, 0x29, 0x0d, 0xd5, 0x26,
0x4d, 0x85, 0xbb, 0x79, 0x7d, 0xa0, 0xf3, 0x83, 0x02, 0xe0, 0x4f, 0xd7,
0xa0, 0x55, 0x9f, 0x20, 0x4e, 0x58, 0x0b, 0x39, 0xbc, 0x2b, 0xa0, 0x1f,
0x98, 0x46, 0x3d, 0x96, 0xc0, 0xff, 0x43, 0x78, 0xdc, 0x49, 0x89, 0xf4,
0x01, 0x83, 0xec, 0x33, 0x4c, 0x8a, 0xe0, 0x6c, 0x92, 0x95, 0xfd, 0x74,
0x2e, 0x55, 0x86, 0xc8, 0x54, 0x7c, 0x63, 0xce, 0x58, 0xe6, 0xfc, 0xc1,
0xc3, 0x9d, 0x67, 0x85, 0xe8, 0xa1, 0x4d, 0x11, 0xb2, 0xbe, 0x9f, 0x70,
0x32, 0x08, 0x67, 0x3a, 0x07, 0xd5, 0xf5, 0xdf, 0xc1, 0x40, 0x8a, 0x60,
0xc1, 0x1e, 0xa7, 0x64, 0x23, 0x1d, 0x93, 0x3b, 0xfa, 0x64, 0x87, 0x64,
0xfc, 0x09, 0x1c, 0xad, 0xf8, 0x44, 0x5b, 0x1d, 0x75, 0xde, 0x7c, 0xf2,
0x9e, 0x9f, 0x17, 0xa0, 0xb4, 0x33, 0xc7, 0x5c, 0x73, 0x19, 0x61, 0x7b,
0xde, 0xff, 0x0c, 0xf9, 0x66, 0x99, 0xf1, 0xae, 0x42, 0x04, 0x65, 0xf2,
0x56, 0xdc, 0x1a, 0x8d};
const unsigned char kTestDrmServiceCertificateNoType[] = {
0x0a, 0xbc, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32, 0x0a, 0xbc, 0x02, 0x08, 0x03, 0x12, 0x10, 0x30, 0x30, 0x31, 0x31, 0x32,
0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x18,
0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02, 0xb1, 0x97, 0xd3, 0x03, 0x22, 0x8e, 0x02, 0x30, 0x82, 0x01, 0x0a, 0x02,
@@ -321,8 +444,17 @@ TestDrmCertificates::TestDrmCertificates()
test_user_device_certificate_( test_user_device_certificate_(
kTestUserDrmCertificate, kTestUserDrmCertificate,
kTestUserDrmCertificate + sizeof(kTestUserDrmCertificate)), kTestUserDrmCertificate + sizeof(kTestUserDrmCertificate)),
test_service_certificate_( test_service_certificate_license_sdk_(
kTestDrmServiceCertificate, kTestDrmServiceCertificateLicenseSdk,
kTestDrmServiceCertificate + sizeof(kTestDrmServiceCertificate)) {} kTestDrmServiceCertificateLicenseSdk +
sizeof(kTestDrmServiceCertificateLicenseSdk)),
test_service_certificate_all_types_(
kTestDrmServiceCertificateAllTypes,
kTestDrmServiceCertificateAllTypes +
sizeof(kTestDrmServiceCertificateAllTypes)),
test_service_certificate_no_type_(
kTestDrmServiceCertificateNoType,
kTestDrmServiceCertificateNoType +
sizeof(kTestDrmServiceCertificateNoType)) {}
} // namespace widevine } // namespace widevine

View File

@@ -36,16 +36,29 @@ class TestDrmCertificates {
return test_user_device_certificate_; return test_user_device_certificate_;
} }
// returns a service certificate // returns a service certificate with license sdk service type
const std::string& test_service_certificate() const { const std::string& test_service_certificate_license_sdk() const {
return test_service_certificate_; return test_service_certificate_license_sdk_;
}
// returns a service certificate with all service types
const std::string& test_service_certificate_all_types() const {
return test_service_certificate_all_types_;
}
// returns a service certificate prior to a change requiring the service
// type to be specified.
const std::string& test_service_certificate_no_type() const {
return test_service_certificate_no_type_;
} }
private: private:
const std::string test_root_certificate_; const std::string test_root_certificate_;
const std::string test_intermediate_certificate_; const std::string test_intermediate_certificate_;
const std::string test_user_device_certificate_; const std::string test_user_device_certificate_;
const std::string test_service_certificate_; const std::string test_service_certificate_license_sdk_;
const std::string test_service_certificate_all_types_;
const std::string test_service_certificate_no_type_;
DISALLOW_COPY_AND_ASSIGN(TestDrmCertificates); DISALLOW_COPY_AND_ASSIGN(TestDrmCertificates);
}; };

View File

@@ -108,7 +108,7 @@ std::string a2b_hex(const std::string& a) {
int main(int argc, char** argv) { int main(int argc, char** argv) {
std::map<std::string, std::string> config_values; std::map<std::string, std::string> config_values;
config_values["drm_certficate_type"] = "test"; config_values["drm_certificate_type"] = "test";
config_values["provider"] = kWidevineTestProvider; config_values["provider"] = kWidevineTestProvider;
widevine_server::wv_pl_sdk::WvPLCASProxyEnvironment environment( widevine_server::wv_pl_sdk::WvPLCASProxyEnvironment environment(
config_values); config_values);

View File

@@ -36,11 +36,14 @@ cc_library(
deps = [ deps = [
":sdk", ":sdk",
"//base", "//base",
"//external:protobuf",
"//strings", "//strings",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//util/endian", "//util/endian",
"//util/gtl:map_util",
"//util/random:global_id", "//util/random:global_id",
"//util:error_space",
"//common:aes_cbc_util", "//common:aes_cbc_util",
"//common:client_cert", "//common:client_cert",
"//common:crypto_util", "//common:crypto_util",
@@ -56,12 +59,14 @@ cc_library(
"//common:status", "//common:status",
"//common:verified_media_pipeline", "//common:verified_media_pipeline",
"//common:vmp_checker", "//common:vmp_checker",
"//protos/public:client_identification_proto", "//protos/public:oem_key_container_cc_proto",
"//protos/public:errors_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:device_certificate_status_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:errors_cc_proto",
"//protos/public:provisioned_device_info_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:widevine_pssh_proto", "//protos/public:license_server_sdk_cc_proto",
"//protos/public:provisioned_device_info_cc_proto",
"//protos/public:widevine_pssh_cc_proto",
], ],
) )
@@ -88,11 +93,11 @@ cc_library(
"//common:drm_service_certificate", "//common:drm_service_certificate",
"//common:error_space", "//common:error_space",
"//common:status", "//common:status",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:license_server_sdk_cc_proto",
"//protos/public:widevine_pssh_proto", "//protos/public:widevine_pssh_cc_proto",
], ],
) )
@@ -122,16 +127,17 @@ cc_test(
"//common:signing_key_util", "//common:signing_key_util",
"//common:test_drm_certificates", "//common:test_drm_certificates",
"//common:test_utils", "//common:test_utils",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:device_certificate_status_proto", "//protos/public:device_certificate_status_cc_proto",
"//protos/public:drm_certificate_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:license_server_sdk_cc_proto",
"//protos/public:provisioned_device_info_proto", "//protos/public:provisioned_device_info_cc_proto",
"//protos/public:remote_attestation_proto", "//protos/public:remote_attestation_cc_proto",
"//protos/public:signed_drm_certificate_proto", "//protos/public:signed_device_info_cc_proto",
"//protos/public:widevine_pssh_proto", "//protos/public:signed_drm_certificate_cc_proto",
"//protos/public:widevine_pssh_cc_proto",
], ],
) )
@@ -145,8 +151,8 @@ cc_test(
"//base", "//base",
"//testing:gunit_main", "//testing:gunit_main",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:license_server_sdk_cc_proto",
], ],
) )
@@ -160,7 +166,7 @@ cc_test(
"//testing:gunit_main", "//testing:gunit_main",
"//util/endian", "//util/endian",
"//common:error_space", "//common:error_space",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:license_server_sdk_cc_proto",
], ],
) )

View File

@@ -28,6 +28,7 @@ bool GenerateErrorResponse(const Status& create_session_status,
std::string* license_response) { std::string* license_response) {
DCHECK(license_response); DCHECK(license_response);
const std::string empty_provider = "";
LicenseError error_proto; LicenseError error_proto;
if (create_session_status.error_space() == error_space) { if (create_session_status.error_space() == error_space) {
switch (create_session_status.error_code()) { switch (create_session_status.error_code()) {
@@ -45,15 +46,8 @@ bool GenerateErrorResponse(const Status& create_session_status,
error_proto.set_error_code(LicenseError::SERVICE_UNAVAILABLE); error_proto.set_error_code(LicenseError::SERVICE_UNAVAILABLE);
break; break;
case SERVICE_CERTIFICATE_REQUEST_MESSAGE: { case SERVICE_CERTIFICATE_REQUEST_MESSAGE: {
SignedMessage signed_message; return GenerateServiceCertificateResponse(empty_provider,
signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE); license_response);
signed_message.set_msg(
DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie()
->certificate());
if (!signed_message.SerializeToString(license_response)) {
return false;
}
return true;
} }
default: default:
break; break;
@@ -84,4 +78,27 @@ bool GenerateErrorResponse(const Status& create_session_status,
} }
return true; return true;
} }
bool GenerateServiceCertificateResponse(const std::string& provider,
std::string* license_response) {
DCHECK(license_response);
SignedMessage signed_message;
signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE);
const DrmServiceCertificate* drm_cert;
if (provider.empty()) {
drm_cert = DrmServiceCertificate::GetDefaultDrmServiceCertificate();
} else {
drm_cert =
DrmServiceCertificate::GetDrmServiceCertificateByProvider(provider);
}
if (drm_cert == nullptr) {
return false;
}
signed_message.set_msg(drm_cert->certificate());
if (!signed_message.SerializeToString(license_response)) {
return false;
}
return true;
}
} // namespace widevine } // namespace widevine

View File

@@ -22,5 +22,12 @@ namespace widevine {
// there is an error license to be sent to the client, or false otherwise. // there is an error license to be sent to the client, or false otherwise.
// Example usage in the Session::Create comments above. // Example usage in the Session::Create comments above.
bool GenerateErrorResponse(const Status& status, std::string* license_response); bool GenerateErrorResponse(const Status& status, std::string* license_response);
// Generates a SignedMessage containing a service certifcate for the specified
// |provider|. Returns false if |provider| does not exist. Returns the default
// service certificate if |provider| is empty.
bool GenerateServiceCertificateResponse(const std::string& provider,
std::string* license_response);
} // namespace widevine } // namespace widevine
#endif // LICENSE_SERVER_SDK_INTERNAL_GENERATE_ERROR_RESPONSE_H_ #endif // LICENSE_SERVER_SDK_INTERNAL_GENERATE_ERROR_RESPONSE_H_

View File

@@ -78,6 +78,7 @@ bool Generate(
} }
switch (key_container.type()) { switch (key_container.type()) {
case License::KeyContainer::CONTENT: case License::KeyContainer::CONTENT:
case License::KeyContainer::OEM_CONTENT:
case License::KeyContainer::ENTITLEMENT: { case License::KeyContainer::ENTITLEMENT: {
if (key_container.has_required_protection() && if (key_container.has_required_protection() &&
key_container.required_protection().has_cgms_flags()) { key_container.required_protection().has_cgms_flags()) {

View File

@@ -14,6 +14,7 @@
#include <list> #include <list>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility>
#include "glog/logging.h" #include "glog/logging.h"
#include "base/timestamp.h" #include "base/timestamp.h"
@@ -24,6 +25,7 @@
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
#include "util/endian/endian.h" #include "util/endian/endian.h"
#include "util/gtl/map_util.h"
#include "util/random/global_id.h" #include "util/random/global_id.h"
#include "common/aes_cbc_util.h" #include "common/aes_cbc_util.h"
#include "common/client_cert.h" #include "common/client_cert.h"
@@ -43,9 +45,12 @@
#include "license_server_sdk/internal/key_control_block.h" #include "license_server_sdk/internal/key_control_block.h"
#include "license_server_sdk/internal/parse_content_id.h" #include "license_server_sdk/internal/parse_content_id.h"
#include "license_server_sdk/internal/session_usage_report.h" #include "license_server_sdk/internal/session_usage_report.h"
#include "protos/public/device_certificate_status.pb.h"
#include "protos/public/errors.pb.h" #include "protos/public/errors.pb.h"
#include "protos/public/widevine_pssh.pb.h" #include "protos/public/widevine_pssh.pb.h"
using ::widevine::SignedDeviceCertificateStatusList;
namespace widevine { namespace widevine {
// TODO(user): These constants are also defined in public/session.cc. Fix the // TODO(user): These constants are also defined in public/session.cc. Fix the
@@ -92,13 +97,24 @@ void SessionImpl::SetPreProvisioningKeys(
} }
Status SessionImpl::SetCertificateStatusList( Status SessionImpl::SetCertificateStatusList(
const DrmRootCertificate* root_cert, const std::string& certificate_status_list, const DrmRootCertificate* root_cert,
const std::string& serialized_signed_certificate_status_list,
uint32_t expiration_period_seconds, bool allow_unknown_devices) { uint32_t expiration_period_seconds, bool allow_unknown_devices) {
CHECK(root_cert); CHECK(root_cert);
// TODO(user): Refactor to enable SignedDeviceInfo response. This
// assumes a SignedDeviceCertificateStatusList request.
SignedDeviceCertificateStatusList signed_certificate_status_list;
if (!signed_certificate_status_list.ParseFromString(
serialized_signed_certificate_status_list)) {
return Status(error_space, INVALID_CERTIFICATE_STATUS_LIST,
"signed-certificate-status-list-parse-error");
}
Status status = DeviceStatusList::Instance()->UpdateStatusList( Status status = DeviceStatusList::Instance()->UpdateStatusList(
root_cert->public_key(), certificate_status_list, root_cert->public_key(),
expiration_period_seconds); signed_certificate_status_list.certificate_status_list(),
signed_certificate_status_list.signature(), expiration_period_seconds);
if (!status.ok()) { if (!status.ok()) {
return status; return status;
} }
@@ -131,6 +147,10 @@ void SessionImpl::AllowDevelopmentClients(bool enable) {
VmpChecker::Instance()->set_allow_development_vmp(enable); VmpChecker::Instance()->set_allow_development_vmp(enable);
} }
void SessionImpl::AllowTestOnlyDevices(const std::string& device_list) {
DeviceStatusList::Instance()->AllowTestOnlyDevices(device_list);
}
void SessionImpl::AllowRevokedDevices(const std::string& system_id_list) { void SessionImpl::AllowRevokedDevices(const std::string& system_id_list) {
DeviceStatusList::Instance()->AllowRevokedDevices(system_id_list); DeviceStatusList::Instance()->AllowRevokedDevices(system_id_list);
} }
@@ -782,26 +802,40 @@ Status SessionImpl::GenerateSignedLicense(
return status; return status;
} }
} }
std::string wrapping_key; std::string wrapping_key;
if (key_container && !key_container->empty()) { if (client_cert_) {
if (!client_cert_.get()) {
status = Status(error_space, MISSING_CLIENT_CERT, "");
return status;
}
wrapping_key = DeriveKey(client_cert_->key(), kWrappingKeyLabel, wrapping_key = DeriveKey(client_cert_->key(), kWrappingKeyLabel,
license_request_->protocol_version() < VERSION_2_2 license_request_->protocol_version() < VERSION_2_2
? signed_message_->msg() ? signed_message_->msg()
: Sha512_Hash(signed_message_->msg()), : Sha512_Hash(signed_message_->msg()),
kWrappingKeySizeBits); kWrappingKeySizeBits);
}
std::map<std::string, std::string> oem_content_key_map;
if ((key_container && !key_container->empty()) ||
oem_key_container_ != nullptr) {
if (!client_cert_) {
status = Status(error_space, MISSING_CLIENT_CERT, "");
return status;
}
if (wrapping_key.empty()) { if (wrapping_key.empty()) {
status = Status(error_space, MISSING_ENCRYPTION_KEY, ""); status = Status(error_space, MISSING_ENCRYPTION_KEY, "");
return status; return status;
} }
for (std::list<License::KeyContainer>::const_iterator iter = if (oem_key_container_ == nullptr) {
key_container->begin(); for (std::list<License::KeyContainer>::const_iterator iter =
iter != key_container->end(); iter++) { key_container->begin();
*license.add_key() = *iter; iter != key_container->end(); iter++) {
*license.add_key() = *iter;
}
} else {
for (auto oem_key : *oem_key_container_) {
*license.add_key() = oem_key.key();
if (oem_key.key().type() == License::KeyContainer::OEM_CONTENT &&
!oem_key.wrapping_key().empty()) {
oem_content_key_map.insert(
std::make_pair(oem_key.key().id(), oem_key.wrapping_key()));
}
}
} }
} }
std::string provider_client_token = std::string provider_client_token =
@@ -880,12 +914,20 @@ Status SessionImpl::GenerateSignedLicense(
// key. Key control blocks for renewals (type = KEY_CONTROL) are not // key. Key control blocks for renewals (type = KEY_CONTROL) are not
// encrypted. // encrypted.
kcb.set_iv(Random16Bytes()); kcb.set_iv(Random16Bytes());
std::string kcb_encryption_key; // key used to encrypt the KCB.
status = GetOemEncryptionKeyForKCB(oem_content_key_map, license.key(i),
&kcb_encryption_key);
if (!status.ok()) {
LOG(WARNING) << "Could not find KCB Encryption key: Status = "
<< status;
return status;
}
kcb.set_key_control_block( kcb.set_key_control_block(
license_request_->protocol_version() < VERSION_2_2 license_request_->protocol_version() < VERSION_2_2
? crypto_util::EncryptAesCbc(license.key(i).key().substr(0, 16), ? crypto_util::EncryptAesCbc(kcb_encryption_key.substr(0, 16),
kcb.iv(), kcb.key_control_block()) kcb.iv(), kcb.key_control_block())
: crypto_util::EncryptAesCbcNoPad( : crypto_util::EncryptAesCbcNoPad(
license.key(i).key().substr(0, 16), kcb.iv(), kcb_encryption_key.substr(0, 16), kcb.iv(),
kcb.key_control_block())); kcb.key_control_block()));
} }
} }
@@ -905,6 +947,7 @@ Status SessionImpl::GenerateSignedLicense(
} }
} }
license.mutable_key(i)->set_iv(Random16Bytes()); license.mutable_key(i)->set_iv(Random16Bytes());
// Encrypt specified CONTENT key or ENTITLEMENT or OEM_CONTENT key.
license.mutable_key(i)->set_key( license.mutable_key(i)->set_key(
license_request_->protocol_version() < VERSION_2_2 license_request_->protocol_version() < VERSION_2_2
? crypto_util::EncryptAesCbc(wrapping_key, license.key(i).iv(), ? crypto_util::EncryptAesCbc(wrapping_key, license.key(i).iv(),
@@ -916,9 +959,22 @@ Status SessionImpl::GenerateSignedLicense(
} }
} }
} }
if (!oem_content_key_map.empty()) {
oem_content_key_map.clear();
}
if (platform_verification_status_ != PLATFORM_NO_VERIFICATION) { if (platform_verification_status_ != PLATFORM_NO_VERIFICATION) {
license.set_platform_verification_status(platform_verification_status_); license.set_platform_verification_status(platform_verification_status_);
if (platform_verification_status_ == PLATFORM_HARDWARE_VERIFIED) {
// In the cases where the 'Platform' has already been verified at the
// proxy, it may make more sense to have the 'Remote Attestation' status
// to be sent from the proxy as part of the license request. However,
// since b/65054419 intends to do away with 'Remote Attestation'
// altogether, it is preferred not to add any 'Remote Attestation' status
// to the license request that is sent from the proxy
// (ModularDrmLicenseRequest).
remote_attestation_verified_ = true;
}
} }
// TODO(b/65054419): Deprecate remote_attestation_verified altogether. // TODO(b/65054419): Deprecate remote_attestation_verified altogether.
if (remote_attestation_verified_) { if (remote_attestation_verified_) {
@@ -966,6 +1022,12 @@ bool SessionImpl::GenerateErrorResponse(const Status& status,
return widevine::GenerateErrorResponse(status, signed_message_bytes); return widevine::GenerateErrorResponse(status, signed_message_bytes);
} }
bool SessionImpl::GenerateServiceCertificateResponse(
const std::string& provider, std::string* signed_message_bytes) {
return widevine::GenerateServiceCertificateResponse(
provider, signed_message_bytes);
}
std::string SessionImpl::GetSdkVersionString() { std::string SessionImpl::GetSdkVersionString() {
return absl::StrCat(kMajorVersion, ".", kMinorVersion, ".", kRelease); return absl::StrCat(kMajorVersion, ".", kMinorVersion, ".", kRelease);
} }
@@ -1156,7 +1218,7 @@ bool SessionImpl::GetClientInfo(ClientIdentification* client_info) const {
} }
std::string SessionImpl::GetDrmDeviceServiceId() const { std::string SessionImpl::GetDrmDeviceServiceId() const {
if (client_cert_.get()) { if (client_cert_) {
return client_cert_->service_id(); return client_cert_->service_id();
} }
return std::string(); return std::string();
@@ -1166,7 +1228,35 @@ Status SessionImpl::GenerateDeviceStatusListRequest(
std::string* signed_device_certificate_status_list_request) { std::string* signed_device_certificate_status_list_request) {
std::string version = GetSdkVersionString(); std::string version = GetSdkVersionString();
return DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest( return DeviceStatusList::GenerateSignedDeviceCertificateStatusListRequest(
version, signed_device_certificate_status_list_request); version,
DrmServiceCertificate::GetDefaultDrmServiceCertificateOrDie()
->certificate(),
signed_device_certificate_status_list_request);
}
void SessionImpl::SetKeys(std::list<OemKeyContainer>* oem_key_container) {
oem_key_container_ = oem_key_container;
}
Status SessionImpl::GetOemEncryptionKeyForKCB(
const std::map<std::string, std::string>& oem_keys, const License::KeyContainer& key,
std::string* encryption_key) const {
if (encryption_key == nullptr) {
return Status(error_space, error::INVALID_ARGUMENT,
"encryption key cannot be null");
}
if (key.type() == License::KeyContainer::OEM_CONTENT) {
auto it = oem_keys.find(key.id());
if (it != oem_keys.end()) {
*encryption_key = (*it).second;
} else {
return Status(error_space, ENCRYPT_ERROR,
"Encryption key not found for paired OEM_CONTENT key");
}
} else {
*encryption_key = key.key();
}
return OkStatus();
} }
} // namespace widevine } // namespace widevine

View File

@@ -21,6 +21,7 @@
#include "protos/public/client_identification.pb.h" #include "protos/public/client_identification.pb.h"
#include "protos/public/license_protocol.pb.h" #include "protos/public/license_protocol.pb.h"
#include "protos/public/license_server_sdk.pb.h" #include "protos/public/license_server_sdk.pb.h"
#include "protos/public/oem_key_container.pb.h"
#include "protos/public/provisioned_device_info.pb.h" #include "protos/public/provisioned_device_info.pb.h"
namespace widevine { namespace widevine {
@@ -36,7 +37,7 @@ class SessionUsage;
const uint32_t kMajorVersion = 4; const uint32_t kMajorVersion = 4;
const uint32_t kMinorVersion = 5; const uint32_t kMinorVersion = 5;
const uint32_t kRelease = 2; const uint32_t kRelease = 4;
const uint32_t kMasterSigningKeySizeBytes = 16; const uint32_t kMasterSigningKeySizeBytes = 16;
const uint32_t kSigningKeySizeBytes = 64; const uint32_t kSigningKeySizeBytes = 64;
@@ -89,12 +90,19 @@ std::string GetProviderClientToken(const SessionInit& session_init,
// &init, // &init,
// &cache, // &cache,
// &signed_license); // &signed_license);
// // For renewal, either SessionState may be cached and provided to the call // For renewal, either SessionState may be cached and provided to the call
// // to GenerateSignedLicense. Or if it is not possible to cache the // to GenerateSignedLicense. Or if it is not possible to cache the
// // SessionState, then SessionInit must be provided with either // SessionState, then SessionInit must be provided with either
// // |signing_key| or |master_signing_key|, in order to allow the sdk to // |signing_key| or |master_signing_key|, in order to allow the sdk to
// // validate the signature of the renewal request, and to sign the // validate the signature of the renewal request, and to sign the
// // license issued. // license issued.
// To use the OEM_CONTENT_KEY key type, the API SetKeys(
// std::list<OemKeyContainer>* oem_key_container) must be called prior to the
// GenerateSignedLicense(...) API. Each OemKeyContainer contains a
// 'wrapping key', which will used to 'wrap' the KCB when generating a license.
// Note that when this SetKeys(std::list<OemKeyContainer>* oem_key_container) is
// called, license generation is only for the keys in this |oem_key_container|.
// The keys passed into the |key_container| parameter are ignored.
class SessionImpl { class SessionImpl {
public: public:
@@ -134,6 +142,12 @@ class SessionImpl {
// Defaults to false. // Defaults to false.
static void AllowDevelopmentClients(bool enable); static void AllowDevelopmentClients(bool enable);
// Enable delivery of licenses to TEST_ONLY client devices. |device_list| is
// a comma separated list of devices to allow even if the device is in a
// TEST_ONLY state. This list wil be used only if
// AllowDevelopmentClient(false) is in use.
static void AllowTestOnlyDevices(const std::string& device_list);
// Enable delivery of licenses to revoked client devices. |system_id_list| is // Enable delivery of licenses to revoked client devices. |system_id_list| is
// a comma separated list of systems Ids to allow even if the device is in the // a comma separated list of systems Ids to allow even if the device is in the
// revoked state. // revoked state.
@@ -200,6 +214,12 @@ class SessionImpl {
static bool GenerateErrorResponse(const Status& status, static bool GenerateErrorResponse(const Status& status,
std::string* signed_message_bytes); std::string* signed_message_bytes);
// Generates a SignedMessage containing a service certifcate for the specified
// |provider|. Returns false if |provider| does not exist. Returns the
// default service certificate if |provider| is empty.
static bool GenerateServiceCertificateResponse(const std::string& provider,
std::string* signed_message_bytes);
// DeriveKey uses the NIST 800-108 KDF recommendation, using AES-CMAC PRF. // DeriveKey uses the NIST 800-108 KDF recommendation, using AES-CMAC PRF.
// NIST 800-108: // NIST 800-108:
// http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf // http://csrc.nist.gov/publications/nistpubs/800-108/sp800-108.pdf
@@ -343,6 +363,11 @@ class SessionImpl {
// Level 1 devices are verified by default. // Level 1 devices are verified by default.
virtual Status VerifyPlatform(); virtual Status VerifyPlatform();
// Sets the list of keys that have been wrapped by associated wrapping keys.
// Each OemKeyContainer contains a "License.KeyContainer" and the associated
// wrapping key.
virtual void SetKeys(std::list<OemKeyContainer>* oem_key_container);
// Extracts the nonce from |request| and populates |key_control_nonce|. Sets // Extracts the nonce from |request| and populates |key_control_nonce|. Sets
// |key_control_nonce| to true if the nonce is found. // |key_control_nonce| to true if the nonce is found.
static Status LoadKeyControlNonce(const LicenseRequest& request, static Status LoadKeyControlNonce(const LicenseRequest& request,
@@ -361,6 +386,12 @@ class SessionImpl {
// Validates the Provider Session Token from |pst_src|. // Validates the Provider Session Token from |pst_src|.
static Status CheckProviderSessionToken(const std::string& pst_src); static Status CheckProviderSessionToken(const std::string& pst_src);
// Return true, if |key| is found in |oem_keys| and |encryption_key| is found.
// This |encryption_key| is used to encrypt the KCB.
Status GetOemEncryptionKeyForKCB(const std::map<std::string, std::string>& oem_keys,
const License::KeyContainer& key,
std::string* encryption_key) const;
std::unique_ptr<SignedMessage> signed_message_; std::unique_ptr<SignedMessage> signed_message_;
std::unique_ptr<LicenseRequest> license_request_; std::unique_ptr<LicenseRequest> license_request_;
// Client cert object used for all crypto operations. // Client cert object used for all crypto operations.
@@ -374,8 +405,8 @@ class SessionImpl {
uint32_t key_control_nonce_; uint32_t key_control_nonce_;
std::unique_ptr<ProvisionedDeviceInfo> provisioned_device_info_; std::unique_ptr<ProvisionedDeviceInfo> provisioned_device_info_;
std::string remote_attestation_cert_serial_number_; std::string remote_attestation_cert_serial_number_;
std::list<OemKeyContainer>* oem_key_container_ = nullptr;
private:
DISALLOW_COPY_AND_ASSIGN(SessionImpl); DISALLOW_COPY_AND_ASSIGN(SessionImpl);
}; };

View File

@@ -49,6 +49,7 @@
#include "protos/public/license_server_sdk.pb.h" #include "protos/public/license_server_sdk.pb.h"
#include "protos/public/provisioned_device_info.pb.h" #include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/remote_attestation.pb.h" #include "protos/public/remote_attestation.pb.h"
#include "protos/public/signed_device_info.pb.h"
#include "protos/public/signed_drm_certificate.pb.h" #include "protos/public/signed_drm_certificate.pb.h"
#include "protos/public/widevine_pssh.pb.h" #include "protos/public/widevine_pssh.pb.h"
@@ -56,7 +57,7 @@ using google::protobuf::TextFormat;
using testing::Eq; using testing::Eq;
using testing::Return; using testing::Return;
using widevine::DeviceCertificateStatusListRequest; using widevine::DeviceCertificateStatusListRequest;
using widevine::SignedDeviceCertificateStatusListRequest; using widevine::SignedDeviceInfoRequest;
// TODO(user): Add test case for generateSignedLicense. // TODO(user): Add test case for generateSignedLicense.
namespace widevine { namespace widevine {
namespace { namespace {
@@ -514,6 +515,10 @@ class SessionTest : public ::testing::Test {
license.platform_verification_status()); license.platform_verification_status());
} }
bool remote_attestation_verified(const SessionImpl& session) {
return session.remote_attestation_verified_;
}
void SetupCertificateStatusList( void SetupCertificateStatusList(
bool allow_unknown_devices, bool allow_unknown_devices,
SignedDeviceCertificateStatusList* status_list) { SignedDeviceCertificateStatusList* status_list) {
@@ -1375,7 +1380,77 @@ class SessionTest : public ::testing::Test {
ASSERT_TRUE(session.get()); ASSERT_TRUE(session.get());
} }
void TestKeyControlBlocks(const std::string& request_msg) { void TestOemContentKeysWithNoWrappingKey(const std::string& request_msg) {
SessionImpl* session_ptr = nullptr;
Status status =
SessionImpl::Create(test_root_.get(), request_msg, &session_ptr);
std::unique_ptr<SessionImpl> session(session_ptr);
ASSERT_EQ(OkStatus(), status);
ASSERT_TRUE(session.get());
std::list<OemKeyContainer> oem_keys;
OemKeyContainer oem_key;
oem_key.mutable_key()->set_key("0123456789abcdef0123456789abcdef");
oem_key.mutable_key()->set_id("oem_content");
oem_key.mutable_key()->set_type(License::KeyContainer::OEM_CONTENT);
oem_keys.push_back(oem_key);
// Specify content key via OemKeyContainer.
oem_key.Clear();
oem_key.mutable_key()->set_id("content");
oem_key.mutable_key()->set_key("fedcba9876543210");
oem_key.mutable_key()->set_type(License::KeyContainer::CONTENT);
oem_keys.push_back(oem_key);
session->SetKeys(&oem_keys);
SessionInit init;
License::Policy policies;
SessionState cache;
std::list<License::KeyContainer> keys;
std::string signed_license_bytes;
status = session->GenerateSignedLicense(&policies, &keys, &init, &cache,
&signed_license_bytes);
EXPECT_EQ(ENCRYPT_ERROR, status.error_code());
}
void TestOemContentKeys(const std::string& request_msg) {
SessionImpl* session_ptr = nullptr;
Status status =
SessionImpl::Create(test_root_.get(), request_msg, &session_ptr);
std::unique_ptr<SessionImpl> session(session_ptr);
ASSERT_EQ(OkStatus(), status);
ASSERT_TRUE(session.get());
std::list<OemKeyContainer> oem_keys;
License::KeyContainer key;
key.set_id("oem_content");
const std::string oem_content_key("0123456789abcdef0123456789abcdef");
key.set_key(oem_content_key);
key.set_type(License::KeyContainer::OEM_CONTENT);
OemKeyContainer oem_key;
oem_key.mutable_key()->CopyFrom(key);
const std::string content_key("0123456789abcdef");
oem_key.set_wrapping_key(content_key);
oem_keys.push_back(oem_key);
// Specify operator key via OemKeyContainer.
key.set_id("operator");
const std::string operator_key("fedcba9876543210");
key.set_key(operator_key);
key.set_type(License::KeyContainer::OPERATOR_SESSION);
oem_key.mutable_key()->CopyFrom(key);
oem_keys.push_back(oem_key);
session->SetKeys(&oem_keys);
SessionInit init;
init.set_purchase_id("Purchases!");
License::Policy policies;
policies.set_can_persist(true);
SessionState cache;
std::list<License::KeyContainer> keys;
std::string signed_license_bytes;
status = session->GenerateSignedLicense(&policies, &keys, &init, &cache,
&signed_license_bytes);
ASSERT_EQ(OkStatus(), status);
}
void TestKeyControlBlocks(const std::string& request_msg,
bool is_oem_key_container) {
SessionImpl* session_ptr = nullptr; SessionImpl* session_ptr = nullptr;
Status status = Status status =
SessionImpl::Create(test_root_.get(), request_msg, &session_ptr); SessionImpl::Create(test_root_.get(), request_msg, &session_ptr);
@@ -1403,6 +1478,17 @@ class SessionTest : public ::testing::Test {
key.clear_track_label(); key.clear_track_label();
keys.push_back(key); keys.push_back(key);
// CONTENT keys added via OemKeyContainer proto.
if (is_oem_key_container) {
std::list<OemKeyContainer> oem_keys;
for (std::list<License::KeyContainer>::iterator it = keys.begin();
it != keys.end(); ++it) {
OemKeyContainer oem_key;
*oem_key.mutable_key() = *it;
oem_keys.push_back(oem_key);
}
session->SetKeys(&oem_keys);
}
SessionInit init; SessionInit init;
init.set_purchase_id("Purchases!"); init.set_purchase_id("Purchases!");
License::Policy policies; License::Policy policies;
@@ -1585,6 +1671,14 @@ class SessionTest : public ::testing::Test {
ra->set_salt(salt); ra->set_salt(salt);
} }
Status GetOemEncryptionKeyForKCB(const SessionImpl& session_impl,
const std::map<std::string, std::string>& oem_keys,
const License::KeyContainer& key,
std::string* encryption_key) {
return session_impl.GetOemEncryptionKeyForKCB(oem_keys, key,
encryption_key);
}
protected: protected:
RsaTestKeys test_keys_; RsaTestKeys test_keys_;
std::unique_ptr<DrmRootCertificate> dev_root_; std::unique_ptr<DrmRootCertificate> dev_root_;
@@ -2284,10 +2378,12 @@ TEST_F(SessionTest, NewLicenseWithKeyControlBlock) {
client_capabilities.set_client_token(false); client_capabilities.set_client_token(false);
client_capabilities.set_session_token(false); client_capabilities.set_session_token(false);
client_capabilities.set_anti_rollback_usage_table(false); client_capabilities.set_anti_rollback_usage_table(false);
TestKeyControlBlocks(GenerateBasicLicenseRequest( TestKeyControlBlocks(
VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime, GenerateBasicLicenseRequest(
client_capabilities, kIncludeProviderToken, VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime,
LicenseRequest::ContentIdentification::InitData::WEBM)); client_capabilities, kIncludeProviderToken,
LicenseRequest::ContentIdentification::InitData::WEBM),
false);
} }
TEST_F(SessionTest, NewLicenseWithKeyControlBlockOffline) { TEST_F(SessionTest, NewLicenseWithKeyControlBlockOffline) {
@@ -2295,10 +2391,12 @@ TEST_F(SessionTest, NewLicenseWithKeyControlBlockOffline) {
client_capabilities.set_client_token(false); client_capabilities.set_client_token(false);
client_capabilities.set_session_token(false); client_capabilities.set_session_token(false);
client_capabilities.set_anti_rollback_usage_table(false); client_capabilities.set_anti_rollback_usage_table(false);
TestKeyControlBlocks(GenerateBasicLicenseRequest( TestKeyControlBlocks(
VERSION_2_1, kNoDeprecatedNonce, OFFLINE, kUseCurrentTime, GenerateBasicLicenseRequest(
client_capabilities, kIncludeProviderToken, VERSION_2_1, kNoDeprecatedNonce, OFFLINE, kUseCurrentTime,
LicenseRequest::ContentIdentification::InitData::WEBM)); client_capabilities, kIncludeProviderToken,
LicenseRequest::ContentIdentification::InitData::WEBM),
false);
} }
TEST_F(SessionTest, NewLicenseWithKeyControlBlockDeprecatedNonce) { TEST_F(SessionTest, NewLicenseWithKeyControlBlockDeprecatedNonce) {
@@ -2306,10 +2404,12 @@ TEST_F(SessionTest, NewLicenseWithKeyControlBlockDeprecatedNonce) {
client_capabilities.set_client_token(false); client_capabilities.set_client_token(false);
client_capabilities.set_session_token(false); client_capabilities.set_session_token(false);
client_capabilities.set_anti_rollback_usage_table(false); client_capabilities.set_anti_rollback_usage_table(false);
TestKeyControlBlocks(GenerateBasicLicenseRequest( TestKeyControlBlocks(
VERSION_2_1, kDeprecatedNonce, STREAMING, kUseCurrentTime, GenerateBasicLicenseRequest(
client_capabilities, kIncludeProviderToken, VERSION_2_1, kDeprecatedNonce, STREAMING, kUseCurrentTime,
LicenseRequest::ContentIdentification::InitData::WEBM)); client_capabilities, kIncludeProviderToken,
LicenseRequest::ContentIdentification::InitData::WEBM),
false);
} }
TEST_F(SessionTest, NewLicenseWithKeyControlBlockAntiRollback) { TEST_F(SessionTest, NewLicenseWithKeyControlBlockAntiRollback) {
@@ -2317,8 +2417,26 @@ TEST_F(SessionTest, NewLicenseWithKeyControlBlockAntiRollback) {
client_capabilities.set_client_token(false); client_capabilities.set_client_token(false);
client_capabilities.set_session_token(false); client_capabilities.set_session_token(false);
client_capabilities.set_anti_rollback_usage_table(true); client_capabilities.set_anti_rollback_usage_table(true);
TestKeyControlBlocks(GenerateBasicLicenseRequest( TestKeyControlBlocks(
VERSION_2_1, kDeprecatedNonce, STREAMING, kUseCurrentTime, GenerateBasicLicenseRequest(
VERSION_2_1, kDeprecatedNonce, STREAMING, kUseCurrentTime,
client_capabilities, kIncludeProviderToken,
LicenseRequest::ContentIdentification::InitData::WEBM),
false);
}
TEST_F(SessionTest, NewLicenseWithKeyControlBlockForOemContentKeys) {
ClientIdentification::ClientCapabilities client_capabilities;
TestOemContentKeys(GenerateBasicLicenseRequest(
VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime,
client_capabilities, kIncludeProviderToken,
LicenseRequest::ContentIdentification::InitData::WEBM));
}
TEST_F(SessionTest, NewLicenseWithKeyControlBlockForOemContentKeysError) {
ClientIdentification::ClientCapabilities client_capabilities;
TestOemContentKeysWithNoWrappingKey(GenerateBasicLicenseRequest(
VERSION_2_1, kNoDeprecatedNonce, STREAMING, kUseCurrentTime,
client_capabilities, kIncludeProviderToken, client_capabilities, kIncludeProviderToken,
LicenseRequest::ContentIdentification::InitData::WEBM)); LicenseRequest::ContentIdentification::InitData::WEBM));
} }
@@ -3055,22 +3173,73 @@ TEST_F(SessionTest, BasicRequestResponse_OEMVersion14) {
} }
TEST_F(SessionTest, GenerateDeviceStatusListRequest) { TEST_F(SessionTest, GenerateDeviceStatusListRequest) {
std::string signed_device_certificate_status_list; std::string serialized_signed_device_info_request;
Status status = session_impl_.GenerateDeviceStatusListRequest( Status status = session_impl_.GenerateDeviceStatusListRequest(
&signed_device_certificate_status_list); &serialized_signed_device_info_request);
EXPECT_TRUE(status.ok()); EXPECT_TRUE(status.ok());
SignedDeviceCertificateStatusListRequest signed_request; SignedDeviceInfoRequest signed_request;
signed_request.ParseFromString(signed_device_certificate_status_list); signed_request.ParseFromString(serialized_signed_device_info_request);
std::string device_certificate_status_list = std::string serialized_device_certificate_status_list_request =
signed_request.device_certificate_status_list_request(); signed_request.device_certificate_status_list_request();
DeviceCertificateStatusListRequest request; DeviceCertificateStatusListRequest request;
request.ParseFromString(device_certificate_status_list); request.ParseFromString(serialized_device_certificate_status_list_request);
EXPECT_EQ(request.sdk_version(), SessionImpl::GetSdkVersionString()); EXPECT_EQ(request.sdk_version(), SessionImpl::GetSdkVersionString());
EXPECT_EQ(DeviceStatusList::Instance()->GetCurrentTime(), EXPECT_EQ(DeviceStatusList::Instance()->GetCurrentTime(),
request.sdk_time_seconds()); request.sdk_time_seconds());
} }
TEST_F(SessionTest, GetOemEncryptionKeyForKCBForOemContentKeySuccess) {
License::KeyContainer key;
key.set_id("oem_content");
const std::string oem_content_key("0123456789abcdef0123456789abcdef");
key.set_key(oem_content_key);
key.set_type(License::KeyContainer::OEM_CONTENT);
OemKeyContainer oem_key;
oem_key.mutable_key()->CopyFrom(key);
const std::string content_key("0123456789abcdef");
oem_key.set_wrapping_key(content_key);
std::map<std::string, std::string> oem_content_key_map;
// Expect to find the 'wrapping key'.
oem_content_key_map.insert(
std::make_pair(oem_key.key().id(), oem_key.wrapping_key()));
std::string encryption_key;
EXPECT_OK(GetOemEncryptionKeyForKCB(session_impl_, oem_content_key_map, key,
&encryption_key));
EXPECT_EQ(oem_key.wrapping_key(), encryption_key);
}
TEST_F(SessionTest, GetOemEncryptionKeyForKCBForOemContentKeyFailure) {
License::KeyContainer key;
key.set_id("oem_content");
const std::string oem_content_key("0123456789abcdef0123456789abcdef");
key.set_key(oem_content_key);
key.set_type(License::KeyContainer::OEM_CONTENT);
OemKeyContainer oem_key;
oem_key.mutable_key()->CopyFrom(key);
const std::string content_key("0123456789abcdef");
oem_key.set_wrapping_key(content_key);
std::map<std::string, std::string> oem_content_key_map;
std::string encryption_key;
Status status = GetOemEncryptionKeyForKCB(session_impl_, oem_content_key_map,
key, &encryption_key);
EXPECT_EQ(ENCRYPT_ERROR, status.error_code());
}
TEST_F(SessionTest, GetOemEncryptionKeyForKCBForContentKeySuccess) {
License::KeyContainer key;
key.set_id("content");
const std::string content_key("0123456789abcdef0123456789abcdef");
key.set_key(content_key);
key.set_type(License::KeyContainer::CONTENT);
std::map<std::string, std::string> oem_content_key_map;
// Expect to find the 'content key'.
std::string encryption_key;
EXPECT_OK(GetOemEncryptionKeyForKCB(session_impl_, oem_content_key_map, key,
&encryption_key));
EXPECT_EQ(key.key(), encryption_key);
}
INSTANTIATE_TEST_SUITE_P(SessionVmpTests, SessionVmpTest, INSTANTIATE_TEST_SUITE_P(SessionVmpTests, SessionVmpTest,
::testing::Values(PLATFORM_NO_VERIFICATION, ::testing::Values(PLATFORM_NO_VERIFICATION,
PLATFORM_UNVERIFIED, PLATFORM_UNVERIFIED,

View File

@@ -40,7 +40,7 @@ cc_library(
"//base", "//base",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//sdk/external/common/wvpl:sdk", "//sdk/external/common/wvpl:sdk",
"//protos/public:media_cas_license_proto", "//protos/public:media_cas_license_cc_proto",
], ],
) )
@@ -54,16 +54,17 @@ cc_library(
], ],
copts = PUBLIC_COPTS, copts = PUBLIC_COPTS,
deps = [ deps = [
"//external:protobuf",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//common:error_space", "//common:error_space",
"//common:status", "//common:status",
"//sdk/external/common/wvpl:wvpl_sdk_session", "//sdk/external/common/wvpl:wvpl_sdk_session",
"//sdk/external/common/wvpl:wvpl_types", "//sdk/external/common/wvpl:wvpl_types",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:media_cas_encryption_proto", "//protos/public:media_cas_encryption_cc_proto",
"//protos/public:media_cas_license_proto", "//protos/public:media_cas_license_cc_proto",
], ],
) )
@@ -85,7 +86,7 @@ cc_library(
"//common:error_space", "//common:error_space",
"//sdk/external/common/wvpl:wvpl_sdk_environment", "//sdk/external/common/wvpl:wvpl_sdk_environment",
"//sdk/external/common/wvpl:wvpl_sdk_session", "//sdk/external/common/wvpl:wvpl_sdk_session",
"//protos/public:media_cas_license_proto", "//protos/public:media_cas_license_cc_proto",
], ],
) )
@@ -95,6 +96,7 @@ cc_test(
deps = [ deps = [
":wvpl_cas_proxy_environment", ":wvpl_cas_proxy_environment",
":wvpl_cas_proxy_session", ":wvpl_cas_proxy_session",
"//external:protobuf",
"//testing:gunit", "//testing:gunit",
"//testing:gunit_main", "//testing:gunit_main",
"@abseil_repo//absl/memory", "@abseil_repo//absl/memory",
@@ -103,10 +105,10 @@ cc_test(
"//common:drm_root_certificate", "//common:drm_root_certificate",
"//common:status", "//common:status",
"//sdk/external/common/wvpl:wvpl_types", "//sdk/external/common/wvpl:wvpl_types",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:media_cas_encryption_proto", "//protos/public:media_cas_encryption_cc_proto",
"//protos/public:media_cas_license_proto", "//protos/public:media_cas_license_cc_proto",
], ],
) )

View File

@@ -36,11 +36,11 @@ WvPLCASProxyEnvironment::WvPLCASProxyEnvironment(
} }
it = config_values.find(kProviderIv); it = config_values.find(kProviderIv);
if (it != config_values.end()) { if (it != config_values.end()) {
provider_iv_ = new std::string(absl::HexStringToBytes((*it).second)); provider_iv_ = absl::HexStringToBytes((*it).second);
} }
it = config_values.find(kProviderKey); it = config_values.find(kProviderKey);
if (it != config_values.end()) { if (it != config_values.end()) {
provider_key_ = new std::string(absl::HexStringToBytes((*it).second)); provider_key_ = absl::HexStringToBytes((*it).second);
} }
} }

View File

@@ -12,11 +12,9 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "sdk/external/common/wvpl/wvpl_sdk_session.h"
namespace absl { #include "absl/synchronization/mutex.h"
class Mutex; #include "sdk/external/common/wvpl/wvpl_sdk_session.h"
} // namespace absl
namespace widevine { namespace widevine {
class CasDrmLicenseRequest; class CasDrmLicenseRequest;
@@ -27,7 +25,7 @@ namespace wv_pl_sdk {
constexpr uint32_t kMajorVersion = 1; constexpr uint32_t kMajorVersion = 1;
constexpr uint32_t kMinorVersion = 1; constexpr uint32_t kMinorVersion = 1;
constexpr uint32_t kRelease = 3; constexpr uint32_t kRelease = 5;
/** /**
* Models a session for Widevine CAS Proxy functionality for * Models a session for Widevine CAS Proxy functionality for

View File

@@ -177,6 +177,13 @@ TEST_F(WvPLCASProxySessionTest, ParseValidLicenseRequest) {
EXPECT_GT(names_values.size(), 0); EXPECT_GT(names_values.size(), 0);
for (const auto name_value : names_values) { for (const auto name_value : names_values) {
} }
WvPLDeviceInfo wvpl_device_info;
status = wvpl_cas_proxy_session_->GetDeviceInfo(&wvpl_device_info);
EXPECT_TRUE(status.ok());
EXPECT_EQ(
"\x8B\x88"
"2\xFBy!\xB3\xE6T\x19\xC6\x11/\x96\xD1\xCE",
wvpl_device_info.drm_certificate_serial_number());
} }
TEST_F(WvPLCASProxySessionTest, ParseEmptyLicenseRequest) { TEST_F(WvPLCASProxySessionTest, ParseEmptyLicenseRequest) {

View File

@@ -29,6 +29,7 @@ proto_library(
"license_server_sdk.proto", "license_server_sdk.proto",
"provisioned_device_info.proto", "provisioned_device_info.proto",
"remote_attestation.proto", "remote_attestation.proto",
"signed_device_info.proto",
"signed_drm_certificate.proto", "signed_drm_certificate.proto",
"verified_media_pipeline.proto", "verified_media_pipeline.proto",
"widevine_pssh.proto", "widevine_pssh.proto",
@@ -44,228 +45,238 @@ java_proto_library(
) )
proto_library( proto_library(
name = "license_services_proto_base", name = "license_services_proto",
srcs = ["license_services.proto"], srcs = ["license_services.proto"],
deps = [ deps = [
":client_identification_proto_base", ":client_identification_proto",
":license_protocol_proto_base", ":license_protocol_proto",
":license_server_sdk_proto_base", ":license_server_sdk_proto",
":errors_proto_base", ":errors_proto",
], ],
) )
cc_proto_library( cc_proto_library(
name = "license_services_proto", name = "license_services_cc_proto",
deps = [":license_services_proto_base"], deps = [":license_services_proto"],
) )
java_proto_library( java_proto_library(
name = "license_services_java_proto", name = "license_services_java_proto",
deps = [":license_services_proto_base"], deps = [":license_services_proto"],
) )
proto_library( proto_library(
name = "client_identification_proto_base", name = "client_identification_proto",
srcs = ["client_identification.proto"], srcs = ["client_identification.proto"],
) )
cc_proto_library( cc_proto_library(
name = "client_identification_proto", name = "client_identification_cc_proto",
deps = [":client_identification_proto_base"], deps = [":client_identification_proto"],
) )
java_proto_library( java_proto_library(
name = "client_identification_java_proto", name = "client_identification_java_proto",
deps = [":client_identification_proto_base"], deps = [":client_identification_proto"],
) )
proto_library( proto_library(
name = "device_certificate_status_proto_base", name = "device_certificate_status_proto",
srcs = ["device_certificate_status.proto"], srcs = ["device_certificate_status.proto"],
deps = [":provisioned_device_info_proto_base"], deps = [":provisioned_device_info_proto"],
) )
cc_proto_library( cc_proto_library(
name = "device_certificate_status_proto", name = "device_certificate_status_cc_proto",
deps = [":device_certificate_status_proto_base"], deps = [":device_certificate_status_proto"],
) )
java_proto_library( java_proto_library(
name = "device_certificate_status_java_proto", name = "device_certificate_status_java_proto",
deps = [":device_certificate_status_proto_base"], deps = [":device_certificate_status_proto"],
) )
proto_library( proto_library(
name = "sdk_stats_proto_base", name = "sdk_stats_proto",
srcs = ["sdk_stats.proto"], srcs = ["sdk_stats.proto"],
) )
cc_proto_library( cc_proto_library(
name = "sdk_stats_proto", name = "sdk_stats_cc_proto",
deps = [":sdk_stats_proto_base"], deps = [":sdk_stats_proto"],
) )
java_proto_library( java_proto_library(
name = "sdk_stats_java_proto", name = "sdk_stats_java_proto",
deps = [":sdk_stats_proto_base"], deps = [":sdk_stats_proto"],
) )
proto_library( proto_library(
name = "drm_certificate_proto_base", name = "drm_certificate_proto",
srcs = ["drm_certificate.proto"], srcs = ["drm_certificate.proto"],
) )
cc_proto_library( cc_proto_library(
name = "drm_certificate_proto", name = "drm_certificate_cc_proto",
deps = [":drm_certificate_proto_base"], deps = [":drm_certificate_proto"],
) )
java_proto_library( java_proto_library(
name = "drm_certificate_java_proto", name = "drm_certificate_java_proto",
deps = [":drm_certificate_proto_base"], deps = [":drm_certificate_proto"],
) )
proto_library( proto_library(
name = "errors_proto_base", name = "errors_proto",
srcs = ["errors.proto"], srcs = ["errors.proto"],
) )
cc_proto_library( cc_proto_library(
name = "errors_proto", name = "errors_cc_proto",
deps = [":errors_proto_base"], deps = [":errors_proto"],
) )
java_proto_library( java_proto_library(
name = "errors_java_proto", name = "errors_java_proto",
deps = [":errors_proto_base"], deps = [":errors_proto"],
) )
proto_library( proto_library(
name = "license_protocol_proto_base", name = "license_protocol_proto",
srcs = ["license_protocol.proto"], srcs = ["license_protocol.proto"],
deps = [ deps = [
":client_identification_proto_base", ":client_identification_proto",
":remote_attestation_proto_base", ":remote_attestation_proto",
], ],
) )
cc_proto_library( cc_proto_library(
name = "license_protocol_proto", name = "license_protocol_cc_proto",
deps = [":license_protocol_proto_base"], deps = [":license_protocol_proto"],
) )
java_proto_library( java_proto_library(
name = "license_protocol_java_proto", name = "license_protocol_java_proto",
deps = [":license_protocol_proto_base"], deps = [":license_protocol_proto"],
) )
proto_library( proto_library(
name = "license_server_sdk_proto_base", name = "license_server_sdk_proto",
srcs = ["license_server_sdk.proto"], srcs = ["license_server_sdk.proto"],
deps = [":license_protocol_proto_base", deps = [":license_protocol_proto",
":widevine_pssh_proto_base"], ":widevine_pssh_proto"],
) )
cc_proto_library( cc_proto_library(
name = "license_server_sdk_proto", name = "license_server_sdk_cc_proto",
deps = [":license_server_sdk_proto_base"], deps = [":license_server_sdk_proto"],
) )
java_proto_library( java_proto_library(
name = "license_server_sdk_java_proto", name = "license_server_sdk_java_proto",
deps = [":license_server_sdk_proto_base"], deps = [":license_server_sdk_proto"],
) )
proto_library( proto_library(
name = "provisioned_device_info_proto_base", name = "provisioned_device_info_proto",
srcs = ["provisioned_device_info.proto"], srcs = ["provisioned_device_info.proto"],
) )
cc_proto_library( cc_proto_library(
name = "provisioned_device_info_proto", name = "provisioned_device_info_cc_proto",
deps = [":provisioned_device_info_proto_base"], deps = [":provisioned_device_info_proto"],
) )
java_proto_library( java_proto_library(
name = "provisioned_device_info_java_proto", name = "provisioned_device_info_java_proto",
deps = [":provisioned_device_info_proto_base"], deps = [":provisioned_device_info_proto"],
) )
proto_library( proto_library(
name = "remote_attestation_proto_base", name = "remote_attestation_proto",
srcs = ["remote_attestation.proto"], srcs = ["remote_attestation.proto"],
deps = [":client_identification_proto_base"], deps = [":client_identification_proto"],
) )
cc_proto_library( cc_proto_library(
name = "remote_attestation_proto", name = "remote_attestation_cc_proto",
deps = [":remote_attestation_proto_base"], deps = [":remote_attestation_proto"],
) )
java_proto_library( java_proto_library(
name = "remote_attestation_java_proto", name = "remote_attestation_java_proto",
deps = [":remote_attestation_proto_base"], deps = [":remote_attestation_proto"],
) )
proto_library( proto_library(
name = "signed_drm_certificate_proto_base", name = "signed_device_info_proto",
srcs = ["signed_device_info.proto"],
)
cc_proto_library(
name = "signed_device_info_cc_proto",
deps = [":signed_device_info_proto"],
)
proto_library(
name = "signed_drm_certificate_proto",
srcs = ["signed_drm_certificate.proto"], srcs = ["signed_drm_certificate.proto"],
) )
cc_proto_library( cc_proto_library(
name = "signed_drm_certificate_proto", name = "signed_drm_certificate_cc_proto",
deps = [":signed_drm_certificate_proto_base"], deps = [":signed_drm_certificate_proto"],
) )
proto_library( proto_library(
name = "verified_media_pipeline_proto_base", name = "verified_media_pipeline_proto",
srcs = ["verified_media_pipeline.proto"], srcs = ["verified_media_pipeline.proto"],
) )
cc_proto_library( cc_proto_library(
name = "verified_media_pipeline_proto", name = "verified_media_pipeline_cc_proto",
deps = [":verified_media_pipeline_proto_base"], deps = [":verified_media_pipeline_proto"],
) )
proto_library( proto_library(
name = "widevine_pssh_proto_base", name = "widevine_pssh_proto",
srcs = ["widevine_pssh.proto"], srcs = ["widevine_pssh.proto"],
) )
cc_proto_library( cc_proto_library(
name = "widevine_pssh_proto", name = "widevine_pssh_cc_proto",
deps = [":widevine_pssh_proto_base"], deps = [":widevine_pssh_proto"],
) )
java_proto_library( java_proto_library(
name = "widevine_pssh_java_proto", name = "widevine_pssh_java_proto",
deps = [":widevine_pssh_proto_base"], deps = [":widevine_pssh_proto"],
) )
proto_library( proto_library(
name = "media_cas_license_proto_base", name = "media_cas_license_proto",
srcs = ["media_cas_license.proto"], srcs = ["media_cas_license.proto"],
deps = [ deps = [
":license_protocol_proto_base", ":license_protocol_proto",
":license_server_sdk_proto_base", ":license_server_sdk_proto",
":errors_proto_base", ":errors_proto",
":media_cas_encryption_proto_base", ":media_cas_encryption_proto",
], ],
) )
cc_proto_library( cc_proto_library(
name = "media_cas_license_proto", name = "media_cas_license_cc_proto",
deps = [":media_cas_license_proto_base"], deps = [":media_cas_license_proto"],
) )
proto_library( proto_library(
name = "media_cas_encryption_proto_base", name = "media_cas_encryption_proto",
srcs = ["media_cas_encryption.proto"], srcs = ["media_cas_encryption.proto"],
) )
cc_proto_library( cc_proto_library(
name = "media_cas_encryption_proto", name = "media_cas_encryption_cc_proto",
deps = [":media_cas_encryption_proto_base"], deps = [":media_cas_encryption_proto"],
) )

View File

@@ -13,8 +13,8 @@
syntax = "proto2"; syntax = "proto2";
package widevine; package widevine;
option java_package = "com.google.video.widevine.protos";
option java_package = "com.google.video.widevine.protos";
option java_outer_classname = "ClientIdentificationProtos"; option java_outer_classname = "ClientIdentificationProtos";
// ClientIdentification message used to authenticate the client device. // ClientIdentification message used to authenticate the client device.
@@ -110,8 +110,8 @@ message EncryptedClientIdentification {
// Serial number for the service certificate for which ClientIdentification is // Serial number for the service certificate for which ClientIdentification is
// encrypted. // encrypted.
optional bytes service_certificate_serial_number = 2; optional bytes service_certificate_serial_number = 2;
// Serialized ClientIdentification message, encrypted with the privacy key using // Serialized ClientIdentification message, encrypted with the privacy key
// AES-128-CBC with PKCS#5 padding. // using AES-128-CBC with PKCS#5 padding.
optional bytes encrypted_client_id = 3; optional bytes encrypted_client_id = 3;
// Initialization vector needed to decrypt encrypted_client_id. // Initialization vector needed to decrypt encrypted_client_id.
optional bytes encrypted_client_id_iv = 4; optional bytes encrypted_client_id_iv = 4;

View File

@@ -14,11 +14,11 @@ syntax = "proto2";
package widevine; package widevine;
import "protos/public/provisioned_device_info.proto";
option java_outer_classname = "DeviceCertificateStatusProtos"; option java_outer_classname = "DeviceCertificateStatusProtos";
option java_package = "com.google.video.widevine.protos"; option java_package = "com.google.video.widevine.protos";
import "protos/public/provisioned_device_info.proto";
// Contains DRM and OEM certificate status and device information for a // Contains DRM and OEM certificate status and device information for a
// specific system ID. // specific system ID.
// TODO(user): Move this to its own file. // TODO(user): Move this to its own file.
@@ -72,42 +72,3 @@ message SignedDeviceCertificateStatusList {
// key using RSASSA-PSS. Required. // key using RSASSA-PSS. Required.
optional bytes signature = 2; optional bytes signature = 2;
} }
// A signed request sent to Widevine Provisioning Server (keysmith) to retrieve
// 'DeviceCertificateStatusList'.
message SignedDeviceCertificateStatusListRequest {
// Serialized DeviceCertificateStatusListRequest. Required.
optional bytes device_certificate_status_list_request = 1;
// Signature of device_certificate_status_list_request. Signed with root
// certificate private key using RSASSA-PSS. Required.
optional bytes signature = 2;
}
// A request sent to Widevine Provisioning Server (keysmith) to retrieve
// 'DeviceCertificateStatusList'.
message DeviceCertificateStatusListRequest {
// The version of sdk. Required.
optional string sdk_version = 1;
// POSIX time, in seconds, when this request was created. Required.
optional uint64 sdk_time_seconds = 2;
}
// Contains response from Widevine Provisioning Server with status and
// DeviceCertificateStatusList information.
message DeviceCertificateStatusListResponse {
enum Status {
UNKNOWN = 0;
OK = 1;
SIGNATURE_FAILED = 2;
NOT_AUTHORIZED = 3;
AUTHORIZATION_EXPIRED = 4;
PROVIDER_ID_MISSING = 5;
INTERNAL_ERROR = 6;
}
// Status returned by the Widevine Provisioning Server. Required.
optional Status status = 1;
// String message returned by the Widevine Provisioning Server.
optional string status_message = 2;
// Serialized SignedDeviceCertificateStatusList. Required.
optional bytes signed_device_certificate_status_list = 3;
}

View File

@@ -28,7 +28,11 @@ message DrmCertificate {
PROVISIONER = 4; PROVISIONER = 4;
} }
enum ServiceType { enum ServiceType {
UNKNOWN = 0; LICENSE_SERVER_SDK = 1; LICENSE_SERVER_PROXY_SDK = 2; UNKNOWN_SERVICE_TYPE = 0;
LICENSE_SERVER_SDK = 1;
LICENSE_SERVER_PROXY_SDK = 2;
PROVISIONING_SDK = 3;
CAS_PROXY_SDK = 4;
} }
// Type of certificate. Required. // Type of certificate. Required.
optional Type type = 1; optional Type type = 1;
@@ -50,6 +54,8 @@ message DrmCertificate {
// certificate. Required for service and provisioner certificates. // certificate. Required for service and provisioner certificates.
optional string provider_id = 7; optional string provider_id = 7;
// This field is used only when type = SERVICE to specify which SDK uses // This field is used only when type = SERVICE to specify which SDK uses
// service certificate. // service certificate. This repeated field is treated as a set. A certificate
optional ServiceType service_type = 8 [default = UNKNOWN]; // may be used for the specified service SDK if the appropriate ServiceType
// is specified in this field.
repeated ServiceType service_types = 8;
} }

View File

@@ -12,6 +12,7 @@
syntax = "proto2"; syntax = "proto2";
package widevine; package widevine;
option java_package = "com.google.video.widevine.protos"; option java_package = "com.google.video.widevine.protos";
@@ -245,4 +246,10 @@ enum Errors {
// Even Key not specified, CasEncryptionResponse.KeyInfo.KeySlot // Even Key not specified, CasEncryptionResponse.KeyInfo.KeySlot
MISSING_EVEN_KEY = 172; MISSING_EVEN_KEY = 172;
// VMP verification required for this platform, however VMP data is missing.
VMP_ERROR_PLATFORM_NOT_VERIFIED = 173;
// VMP verification failed this platform, perhaps was tampered with.
VMP_ERROR_PLATFORM_TAMPERED = 174;
} }

View File

@@ -14,11 +14,12 @@
syntax = "proto2"; syntax = "proto2";
package widevine; package widevine;
option java_package = "com.google.video.widevine.protos";
import "protos/public/client_identification.proto"; import "protos/public/client_identification.proto";
import "protos/public/remote_attestation.proto"; import "protos/public/remote_attestation.proto";
option java_package = "com.google.video.widevine.protos";
// option optimize_for = LITE_RUNTIME; // option optimize_for = LITE_RUNTIME;
enum LicenseType { enum LicenseType {
STREAMING = 1; STREAMING = 1;
@@ -117,11 +118,12 @@ message License {
message KeyContainer { message KeyContainer {
enum KeyType { enum KeyType {
SIGNING = 1; // Exactly one key of this type must appear. SIGNING = 1; // Exactly one key of this type must appear.
CONTENT = 2; // Content key. CONTENT = 2; // Content key.
KEY_CONTROL = 3; // Key control block for license renewals. No key. KEY_CONTROL = 3; // Key control block for license renewals. No key.
OPERATOR_SESSION = 4; // wrapped keys for auxiliary crypto operations. OPERATOR_SESSION = 4; // wrapped keys for auxiliary crypto operations.
ENTITLEMENT = 5; // Entitlement keys. ENTITLEMENT = 5; // Entitlement keys.
OEM_CONTENT = 6; // Partner-specific content key.
} }
// The SecurityLevel enumeration allows the server to communicate the level // The SecurityLevel enumeration allows the server to communicate the level
@@ -269,7 +271,6 @@ message License {
[default = PLATFORM_NO_VERIFICATION]; [default = PLATFORM_NO_VERIFICATION];
// IDs of the groups for which keys are delivered in this license, if any. // IDs of the groups for which keys are delivered in this license, if any.
repeated bytes group_ids = 11; repeated bytes group_ids = 11;
} }
enum ProtocolVersion { enum ProtocolVersion {
@@ -381,6 +382,15 @@ message MetricData {
repeated TypeValue metric_data = 2; repeated TypeValue metric_data = 2;
} }
message VersionInfo {
// License SDK version reported by the Widevine License SDK. This field
// is populated automatically by the SDK.
optional string license_sdk_version = 1;
// Version of the service hosting the license SDK. This field is optional.
// It may be provided by the hosting service.
optional string license_service_version = 2;
}
message SignedMessage { message SignedMessage {
enum MessageType { enum MessageType {
LICENSE_REQUEST = 1; LICENSE_REQUEST = 1;
@@ -403,4 +413,7 @@ message SignedMessage {
optional RemoteAttestation remote_attestation = 5; optional RemoteAttestation remote_attestation = 5;
repeated MetricData metric_data = 6; repeated MetricData metric_data = 6;
// Version information from the SDK and license service. This information is
// provided in the license response.
optional VersionInfo service_version_info = 7;
} }

View File

@@ -14,11 +14,12 @@
syntax = "proto2"; syntax = "proto2";
package widevine; package widevine;
option java_package = "com.google.video.widevine.protos";
import "protos/public/license_protocol.proto"; import "protos/public/license_protocol.proto";
import "protos/public/widevine_pssh.proto"; import "protos/public/widevine_pssh.proto";
option java_package = "com.google.video.widevine.protos";
// This message is used to pass optional data on initial license issuance. // This message is used to pass optional data on initial license issuance.
// LINT.IfChange // LINT.IfChange
message SessionInit { message SessionInit {

View File

@@ -11,9 +11,12 @@
syntax = "proto2"; syntax = "proto2";
option java_package = "com.google.video.widevine.licensing"; option java_package = "com.google.video.widevine.licensing";
import "protos/public/client_identification.proto"; import "protos/public/client_identification.proto";
import "protos/public/license_protocol.proto"; import "protos/public/license_protocol.proto";
import "protos/public/license_server_sdk.proto"; import "protos/public/license_server_sdk.proto";
package widevine; package widevine;
// TODO(user): refactor license_services.proto and sdk_stats.proto. // TODO(user): refactor license_services.proto and sdk_stats.proto.
@@ -79,6 +82,11 @@ message ModularDrmLicenseRequest {
// be reported. // be reported.
repeated License.KeyContainer.VideoResolutionConstraint repeated License.KeyContainer.VideoResolutionConstraint
video_resolution_constraints = 10; video_resolution_constraints = 10;
// Video feature associated with this key. Common value is HDR.
// If specified and the key_id/key is not specified, this value will be
// used to derive the key_id/key.
optional string video_feature = 11;
} }
// Specifies a list of content keys and policies to be included in a license. // Specifies a list of content keys and policies to be included in a license.
@@ -207,6 +215,38 @@ message ModularDrmLicenseRequest {
// field by using the ProxySDK(internally, RequestInspector) API. // field by using the ProxySDK(internally, RequestInspector) API.
optional PlatformVerificationStatus platform_verification_status = 26 optional PlatformVerificationStatus platform_verification_status = 26
[default = PLATFORM_NO_VERIFICATION]; [default = PLATFORM_NO_VERIFICATION];
// By default, a license request will fail if VMP status is unverified for
// Chrome. Set this field to 'true' to allow license request to succeed when
// VMP status is unverified for Chrome platforms.
// TODO (b/126434032) Change the default to false once partners are notified
optional bool allow_unverified_platform = 27 [default = true];
// By default, a license request will fail if VMP status is tampered for
// Chrome. Set this field to 'true' to allow license request to succeed when
// VMP status is tampered for Chrome platforms.
// TODO (b/126434032) Change the default to false once partners are notified
optional bool allow_tampered_platform = 28 [default = true];
// A shortcut for specifying whether to return keys for the video feature only
// or to return all keys or ignore the video feature.
// The VideoFeatureKeySet only applies when video feature is specified in the
// PSSH.
enum VideoFeatureKeySet {
VF_UNSPECIFIED = 0;
// License should not include keys for the video feature, instead only
// include keys not associated with the video feature.
VF_EXCLUDED = 1;
// License should only include keys associated with the video feature
// (e.g., HDR).
VF_ONLY = 2;
// License should include keys for the video feature and also for keys
// not associated with the video feature (e.g., SDR keys).
VF_INCLUDED = 3;
}
// This field is ignored if one or more content_key_specs is specified.
optional VideoFeatureKeySet video_feature_key_set = 29
[default = VF_EXCLUDED];
} }
@@ -291,6 +331,7 @@ message ModularDrmLicenseResponse {
message Track { message Track {
optional string type = 1; optional string type = 1;
optional bytes key_id = 2; optional bytes key_id = 2;
optional string video_feature = 3;
} }
// A subset of data from the Widevine PSSH. // A subset of data from the Widevine PSSH.
message Pssh { message Pssh {
@@ -310,7 +351,7 @@ message ModularDrmLicenseResponse {
optional bool remote_attestation_verified = 8; optional bool remote_attestation_verified = 8;
// Widevine-defined security level. // Widevine-defined security level.
optional uint32 security_level = 9; optional uint32 security_level = 9;
// Actual SDK license status as defined in widevine/server/sdk/error.proto. // Actual SDK license status as defined in widevine/protos/public/errors.proto
optional uint32 internal_status = 10; optional uint32 internal_status = 10;
// Usage report sent in a license release. // Usage report sent in a license release.
optional SessionUsage session_usage = 11; optional SessionUsage session_usage = 11;
@@ -342,7 +383,7 @@ message ModularDrmLicenseResponse {
optional bool is_live = 24 [default = false]; optional bool is_live = 24 [default = false];
// Platform verification status // Platform verification status
optional PlatformVerificationStatus platform_verification_status = 25 optional PlatformVerificationStatus platform_verification_status = 25
[default = PLATFORM_UNVERIFIED]; [default = PLATFORM_UNVERIFIED];
// The "provider" field in ModularDrmLicenseRequest. // The "provider" field in ModularDrmLicenseRequest.
optional string content_owner = 26; optional string content_owner = 26;
// The "requesting_provider" in ModularDrmLicenseRequest. If // The "requesting_provider" in ModularDrmLicenseRequest. If

View File

@@ -10,10 +10,10 @@
syntax = "proto2"; syntax = "proto2";
option java_package = "com.google.video.widevine.mediacasencryption";
package widevine; package widevine;
option java_package = "com.google.video.widevine.mediacasencryption";
message CasEncryptionRequest { message CasEncryptionRequest {
optional bytes content_id = 1; optional bytes content_id = 1;
optional string provider = 2; optional string provider = 2;
@@ -43,7 +43,7 @@ message CasEncryptionResponse {
SINGLE = 1; SINGLE = 1;
EVEN = 2; EVEN = 2;
ODD = 3; ODD = 3;
}; }
optional bytes key_id = 1; optional bytes key_id = 1;
optional bytes key = 2; optional bytes key = 2;
// Optional label used for the key. // Optional label used for the key.

View File

@@ -14,6 +14,7 @@ syntax = "proto2";
option java_package = "com.google.video.widevine.mediacaslicense"; option java_package = "com.google.video.widevine.mediacaslicense";
import "protos/public/license_protocol.proto"; import "protos/public/license_protocol.proto";
import "protos/public/license_server_sdk.proto"; import "protos/public/license_server_sdk.proto";
import "protos/public/media_cas_encryption.proto"; import "protos/public/media_cas_encryption.proto";
@@ -70,7 +71,7 @@ message CasDrmLicenseResponse {
// TODO(user): Until a CAS license protocol is defined, this field is a // TODO(user): Until a CAS license protocol is defined, this field is a
// serialized License message defined in license_protocol.proto. // serialized License message defined in license_protocol.proto.
optional bytes license = 3; optional bytes license = 3;
// Actual SDK license status as defined in widevine/server/sdk/error.proto. // Actual SDK license status as defined in widevine/protos/public/errors.proto
optional uint32 internal_status = 4; optional uint32 internal_status = 4;
// Indicates the type of message in the license response. // Indicates the type of message in the license response.
optional SignedMessage.MessageType message_type = 5; optional SignedMessage.MessageType message_type = 5;
@@ -78,6 +79,8 @@ message CasDrmLicenseResponse {
message PsshData { message PsshData {
repeated bytes key_id = 1; repeated bytes key_id = 1;
optional bytes content_id = 2; optional bytes content_id = 2;
// If this is a group key license, this is the group identifier.
optional bytes group_id = 3;
} }
message LicenseMetadata { message LicenseMetadata {
optional bytes content_id = 1; optional bytes content_id = 1;
@@ -88,6 +91,27 @@ message CasDrmLicenseResponse {
optional string content_owner = 8; optional string content_owner = 8;
optional string content_provider = 9; optional string content_provider = 9;
optional LicenseMetadata license_metadata = 10; optional LicenseMetadata license_metadata = 10;
message DeviceInfo {
// Make as identified from the provisioned device info. If that is not
// available, the device make will be retrieved from the license request.
optional string make = 1;
// Model as identified from the provisioned device info. If that is not
// available, the device model will be retrieved from the license request.
optional string model = 2;
// Widevine-defined device security level.
optional uint32 security_level = 3;
// Globally unique serial number of certificate associated with this
// device.
optional bytes drm_cert_serial_number = 4;
// Platform specifies the OS or device type and perhaps other software
// information for the device receving this license response.
// Example: Android, iOS, Chrome, PC.
optional string platform = 5;
// SystemID of the requesting device.
optional uint32 system_id = 6;
}
// Device information for the device making the CAS license request.
optional DeviceInfo device_info = 11;
} }
message SignedCasDrmRequest { message SignedCasDrmRequest {
@@ -103,8 +127,3 @@ message SignedCasDrmRequest {
optional string user_agent = 5; optional string user_agent = 5;
optional string provider = 6; optional string provider = 6;
} }
message SignedCasDrmResponse {
optional bytes response = 1;
optional bytes signature = 2;
}

View File

@@ -13,10 +13,11 @@
syntax = "proto2"; syntax = "proto2";
package widevine; package widevine;
option java_package = "com.google.video.widevine.protos";
import "protos/public/client_identification.proto"; import "protos/public/client_identification.proto";
option java_package = "com.google.video.widevine.protos";
message RemoteAttestation { message RemoteAttestation {
// Encrypted ClientIdentification message containing the device remote // Encrypted ClientIdentification message containing the device remote
// attestation certificate. Required. // attestation certificate. Required.
@@ -27,4 +28,3 @@ message RemoteAttestation {
// Signed remote attestation challenge + salt. Required. // Signed remote attestation challenge + salt. Required.
optional bytes signature = 3; optional bytes signature = 3;
} }

View File

@@ -9,14 +9,14 @@
// //
// Main protocol buffers for Widevine external SDK // Main protocol buffers for Widevine external SDK
// licensing statistics. // licensing statistics.
// Design doc: https://docs.google.com/document/d/1yyt5TxApYbI0N07aH94zwnKYuzYdFcmqZtC3jCyph8k/edit# // Design doc:
// https://docs.google.com/document/d/1yyt5TxApYbI0N07aH94zwnKYuzYdFcmqZtC3jCyph8k/edit#
syntax = "proto2"; syntax = "proto2";
package widevine; package widevine;
option java_package = "com.google.video.widevine.protos"; option java_package = "com.google.video.widevine.protos";
option java_outer_classname = "LicenseStatsProtos"; option java_outer_classname = "LicenseStatsProtos";
@@ -29,14 +29,16 @@ message DeviceLicenseCounterByStatus {
} }
message DeviceLicenseCounterByModel { message DeviceLicenseCounterByModel {
// The model of the device sending a license request to the Widevine SDK. Optional. // The model of the device sending a license request to the Widevine SDK.
// Optional.
optional string device_model = 1; optional string device_model = 1;
// license status specific breakdown of counter data // license status specific breakdown of counter data
repeated DeviceLicenseCounterByStatus counter_by_status = 2; repeated DeviceLicenseCounterByStatus counter_by_status = 2;
} }
message DeviceLicenseCounterByMake { message DeviceLicenseCounterByMake {
// The make of the device sending a license request to the Widevine SDK. Optional. // The make of the device sending a license request to the Widevine SDK.
// Optional.
optional string device_make = 1; optional string device_make = 1;
// device model specific breakdown of counter data. // device model specific breakdown of counter data.
repeated DeviceLicenseCounterByModel counter_by_model = 2; repeated DeviceLicenseCounterByModel counter_by_model = 2;

View File

@@ -0,0 +1,66 @@
////////////////////////////////////////////////////////////////////////////////
// Copyright 2019 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.
////////////////////////////////////////////////////////////////////////////////
//
// This is a pared down copy of the file in:
//
// Do not modify this file without keeping the other file in sync.
// Items in the original file but removed here include.
// - comments
// - SignedDeviceInfoService definition
// - Google api annotations.
//
// TODO(user, yawenyu): Figure out how we can avoid having two copies
// of the same file.
syntax = "proto3";
package widevine;
option csharp_namespace = "Google.Chrome.Widevine.Deviceinfo.V1";
option java_multiple_files = true;
option java_outer_classname = "DeviceCertificateStatusProtos";
option java_package = "com.google.chrome.widevine.deviceinfo.v1";
// GCWDI == Google Chrome Widevine Device Info
option objc_class_prefix = "GCWDI";
// A request sent to Widevine Provisioning Server (keysmith) to retrieve
// 'DeviceCertificateStatusList'.
message DeviceCertificateStatusListRequest {
// The version of sdk. Required.
string sdk_version = 1;
// POSIX time, in seconds, when this request was created. Required.
uint64 sdk_time_seconds = 2;
// The serialized service certificate used to sign the request. Required.
bytes service_certificate = 3;
}
// A device certificate status resource in the Widevine Signed Device Info
// API. It intended to carry information about DRM and OEM certificate
// status and device information for a specific system ID. The information is
// intended to be shared publicly.
// A signed request sent to Widevine Provisioning Server (keysmith) to retrieve
// 'DeviceCertificateStatusList'.
message SignedDeviceInfoRequest {
// A serialized DeviceCertificateStatusListRequest. Required.
bytes device_certificate_status_list_request = 1;
// TODO(user): What's the signature algorithm and the key used?
bytes signature = 2;
}
// Contains a serialized DeviceCertificateStatusList and the signature.
message SignedDeviceInfo {
// Serialized DeviceCertificateStatusList. Required.
bytes device_certificate_status_list = 1;
// Signature of device_certificate_status_list_request. Signed with root
// certificate private key using RSASSA-PSS. Required.
bytes signature = 2;
}

View File

@@ -12,10 +12,10 @@
syntax = "proto2"; syntax = "proto2";
option optimize_for = LITE_RUNTIME;
package vmp; package vmp;
option optimize_for = LITE_RUNTIME;
message VmpData { message VmpData {
message SignedBinaryInfo { message SignedBinaryInfo {
// File name of the binary. Required. // File name of the binary. Required.

View File

@@ -12,6 +12,7 @@
syntax = "proto2"; syntax = "proto2";
package widevine; package widevine;
option java_package = "com.google.video.widevine.protos"; option java_package = "com.google.video.widevine.protos";
message WidevinePsshData { message WidevinePsshData {
@@ -75,8 +76,8 @@ message WidevinePsshData {
// Group identifiers for all groups to which the content belongs. This can // Group identifiers for all groups to which the content belongs. This can
// be used to deliver licenses to unlock multiple titles / channels. // be used to deliver licenses to unlock multiple titles / channels.
// Optional, and may only be present in ENTITLEMENT and ENTITLED_KEY PSSHs, and // Optional, and may only be present in ENTITLEMENT and ENTITLED_KEY PSSHs,
// not in conjunction with key_ids. // and not in conjunction with key_ids.
repeated bytes group_ids = 13; repeated bytes group_ids = 13;
// Copy/copies of the content key used to decrypt the media stream in which // Copy/copies of the content key used to decrypt the media stream in which
@@ -86,11 +87,17 @@ message WidevinePsshData {
// PSSHs of type ENTITLED_KEY. // PSSHs of type ENTITLED_KEY.
repeated EntitledKey entitled_keys = 14; repeated EntitledKey entitled_keys = 14;
// Video feature identifier, which is used in conjunction with |content_id|
// to determine the set of keys to be returned in the license. Cannot be
// present in conjunction with |key_ids|.
// Current values are "HDR".
optional string video_feature = 15;
//////////////////////////// Deprecated Fields //////////////////////////// //////////////////////////// Deprecated Fields ////////////////////////////
enum Algorithm { enum Algorithm {
UNENCRYPTED = 0; UNENCRYPTED = 0;
AESCTR = 1; AESCTR = 1;
}; }
optional Algorithm algorithm = 1 [deprecated = true]; optional Algorithm algorithm = 1 [deprecated = true];
optional string provider = 3 [deprecated = true]; optional string provider = 3 [deprecated = true];
optional string track_type = 5 [deprecated = true]; optional string track_type = 5 [deprecated = true];

View File

@@ -42,20 +42,20 @@ cc_library(
"//base", "//base",
"@abseil_repo//absl/memory", "@abseil_repo//absl/memory",
"//common:client_cert", "//common:client_cert",
"//common:drm_root_certificate",
"//common:drm_service_certificate", "//common:drm_service_certificate",
"//common:error_space", "//common:error_space",
"//common:remote_attestation_verifier", "//common:remote_attestation_verifier",
"//common:status", "//common:status",
"//common:verified_media_pipeline", "//common:verified_media_pipeline",
"//license_server_sdk/internal:sdk", "//license_server_sdk/internal:sdk",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:device_certificate_status_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:license_server_sdk_cc_proto",
"//protos/public:provisioned_device_info_proto", "//protos/public:provisioned_device_info_cc_proto",
"//protos/public:widevine_pssh_proto", "//protos/public:signed_drm_certificate_cc_proto",
"//protos/public:widevine_pssh_cc_proto",
], ],
) )
@@ -73,18 +73,19 @@ cc_library(
"//base", "//base",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//common:aes_cbc_util",
"//common:device_status_list", "//common:device_status_list",
"//common:drm_root_certificate", "//common:drm_root_certificate",
"//common:error_space", "//common:error_space",
"//common:drm_service_certificate", "//common:drm_service_certificate",
"//common:sha_util",
"//common:status", "//common:status",
"//common:vmp_checker", "//common:vmp_checker",
"//license_server_sdk/internal:sdk", "//license_server_sdk/internal:sdk",
"//protos/public:device_certificate_status_proto", "//protos/public:device_certificate_status_cc_proto",
"//protos/public:errors_proto", "//protos/public:errors_cc_proto",
"//protos/public:provisioned_device_info_proto", "//protos/public:provisioned_device_info_cc_proto",
"//protos/public:drm_certificate_cc_proto",
"//protos/public:signed_device_info_cc_proto",
"//protos/public:signed_drm_certificate_cc_proto",
], ],
) )
@@ -102,24 +103,25 @@ cc_library(
"@abseil_repo//absl/memory", "@abseil_repo//absl/memory",
"@abseil_repo//absl/strings", "@abseil_repo//absl/strings",
"@abseil_repo//absl/synchronization", "@abseil_repo//absl/synchronization",
"//common:aes_cbc_util",
"//common:client_cert", "//common:client_cert",
"//common:device_status_list", "//common:device_status_list",
"//common:drm_root_certificate", "//common:drm_root_certificate",
"//common:drm_service_certificate", "//common:drm_service_certificate",
"//common:error_space", "//common:error_space",
"//common:remote_attestation_verifier", "//common:remote_attestation_verifier",
"//common:sha_util",
"//common:status", "//common:status",
"//common:verified_media_pipeline", "//common:verified_media_pipeline",
"//common:vmp_checker", "//common:vmp_checker",
"//license_server_sdk/internal:sdk", "//license_server_sdk/internal:sdk",
"//protos/public:client_identification_proto", "//protos/public:client_identification_cc_proto",
"//protos/public:device_certificate_status_proto", "//protos/public:device_certificate_status_cc_proto",
"//protos/public:errors_proto", "//protos/public:drm_certificate_cc_proto",
"//protos/public:license_protocol_proto", "//protos/public:errors_cc_proto",
"//protos/public:license_server_sdk_proto", "//protos/public:license_protocol_cc_proto",
"//protos/public:provisioned_device_info_proto", "//protos/public:license_server_sdk_cc_proto",
"//protos/public:widevine_pssh_proto", "//protos/public:provisioned_device_info_cc_proto",
"//protos/public:signed_device_info_cc_proto",
"//protos/public:signed_drm_certificate_cc_proto",
"//protos/public:widevine_pssh_cc_proto",
], ],
) )

View File

@@ -7,35 +7,37 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include "sdk/external/common/wvpl/wvpl_sdk_environment.h" #include "sdk/external/common/wvpl/wvpl_sdk_environment.h"
#include "glog/logging.h" #include "glog/logging.h"
#include "absl/strings/escaping.h" #include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
#include "common/aes_cbc_util.h"
#include "common/device_status_list.h" #include "common/device_status_list.h"
#include "common/drm_root_certificate.h" #include "common/drm_root_certificate.h"
#include "common/drm_service_certificate.h" #include "common/drm_service_certificate.h"
#include "common/error_space.h" #include "common/error_space.h"
#include "common/sha_util.h"
#include "common/status.h" #include "common/status.h"
#include "common/vmp_checker.h" #include "common/vmp_checker.h"
#include "license_server_sdk/internal/generate_error_response.h" #include "license_server_sdk/internal/generate_error_response.h"
#include "protos/public/device_certificate_status.pb.h" #include "protos/public/device_certificate_status.pb.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h" #include "protos/public/errors.pb.h"
#include "protos/public/provisioned_device_info.pb.h" #include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
using widevine::DeviceCertificateStatus; using widevine::DeviceCertificateStatus;
using widevine::DeviceCertificateStatusList; using widevine::DeviceCertificateStatusList;
using widevine::DeviceStatusList; using widevine::DeviceStatusList;
using widevine::DrmCertificate;
using widevine::DrmServiceCertificate; using widevine::DrmServiceCertificate;
using widevine::error_space; using widevine::error_space;
using widevine::kCertificateTypeDevelopment; using widevine::kCertificateTypeDevelopment;
using widevine::kCertificateTypeProduction; using widevine::kCertificateTypeProduction;
using widevine::kCertificateTypeTesting; using widevine::kCertificateTypeTesting;
using widevine::OkStatus;
using widevine::ProvisionedDeviceInfo; using widevine::ProvisionedDeviceInfo;
using widevine::SignedDeviceCertificateStatusList; using widevine::SignedDrmCertificate;
using widevine::VmpChecker; using widevine::VmpChecker;
using widevine::crypto_util::EncryptAesCbc;
namespace error = widevine::error; namespace error = widevine::error;
namespace widevine_server { namespace widevine_server {
@@ -82,8 +84,10 @@ WvPLSDKEnvironment::~WvPLSDKEnvironment() = default;
WvPLStatus WvPLSDKEnvironment::SetDrmServiceCertificate( WvPLStatus WvPLSDKEnvironment::SetDrmServiceCertificate(
const std::string& service_certificate, const std::string& service_private_key, const std::string& service_certificate, const std::string& service_private_key,
const std::string& service_private_key_passphrase) { const std::string& service_private_key_passphrase) {
CHECK(drm_root_certificate()) << "DRM root certificate not set!"; DCHECK(drm_root_certificate());
WvPLStatus wvpl_status = DrmServiceCertificate::AddDrmServiceCertificate( WvPLStatus wvpl_status = CheckServiceCertificateType(service_certificate);
if (!wvpl_status.ok()) return wvpl_status;
wvpl_status = DrmServiceCertificate::AddDrmServiceCertificate(
drm_root_certificate(), service_certificate, service_private_key, drm_root_certificate(), service_certificate, service_private_key,
service_private_key_passphrase); service_private_key_passphrase);
if (!wvpl_status.ok()) return wvpl_status; if (!wvpl_status.ok()) return wvpl_status;
@@ -151,80 +155,24 @@ void WvPLSDKEnvironment::AddDeviceInfo(
device_info_map.InsertOrUpdate(provisioned_device_info); device_info_map.InsertOrUpdate(provisioned_device_info);
} }
WvPLStatus WvPLSDKEnvironment::GenerateSignature(const std::string& plain_text,
std::string* signature) {
DCHECK(signature);
if (plain_text.empty()) {
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
"Plain_text for signature is empty.");
}
if (signature == nullptr) {
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
"Signature must not be null.");
}
const std::map<std::string, std::string>* config_values = GetConfigValue();
std::map<std::string, std::string>::const_iterator it =
config_values->find(kDrmCertificateType);
it = config_values->find(kProviderIv);
std::string provider_iv;
std::string provider_key;
if (it != config_values->end()) {
provider_iv = absl::HexStringToBytes((*it).second);
if (provider_iv.empty()) {
return WvPLStatus(error_space, error::NOT_FOUND, "Provider IV is empty.");
}
}
it = config_values->find(kProviderKey);
if (it != config_values->end()) {
provider_key = absl::HexStringToBytes((*it).second);
if (provider_key.empty()) {
return WvPLStatus(error_space, error::NOT_FOUND,
"Provider Key is empty.");
}
}
std::string hashed_text = widevine::Sha1_Hash(plain_text);
if (hashed_text.empty()) {
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
"Hash for signature is empty.");
} else {
*signature = EncryptAesCbc(provider_key, provider_iv, hashed_text);
if (signature->empty()) {
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
"Generated signature failed");
}
}
return WvPLStatus();
}
std::map<std::string, std::string>* WvPLSDKEnvironment::config_values_ =
new std::map<std::string, std::string>();
std::map<std::string, std::string>* WvPLSDKEnvironment::GetConfigValue() {
return config_values_;
}
void WvPLSDKEnvironment::SetConfigValue(
const std::map<std::string, std::string>& config_values) {
config_values_->insert(config_values.begin(), config_values.end());
}
WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList( WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList(
const std::string& cert_list) const { const std::string& cert_list) const {
WvPLStatus status; WvPLStatus status;
SignedDeviceCertificateStatusList device_certificate_status_list; std::string serialized_device_certicate_status_list;
std::string decoded_certificate_status_list; std::string signature;
std::string device_certicate_status_list; status = DeviceStatusList::ExtractFromServiceResponse(
status = DeviceStatusList::ExtractFromProvisioningServiceResponse( cert_list, &serialized_device_certicate_status_list, &signature);
cert_list, &decoded_certificate_status_list,
&device_certicate_status_list);
if (!status.ok()) return status; if (!status.ok()) return status;
DeviceCertificateStatusList certificate_status_list; DeviceCertificateStatusList certificate_status_list;
if (!certificate_status_list.ParseFromString(device_certicate_status_list)) { if (!certificate_status_list.ParseFromString(
serialized_device_certicate_status_list)) {
return WvPLStatus(error_space, return WvPLStatus(error_space,
widevine::INVALID_CERTIFICATE_STATUS_LIST, widevine::INVALID_CERTIFICATE_STATUS_LIST,
"certificate status list parse error"); "certificate status list parse error");
} }
status = DeviceStatusList::Instance()->UpdateStatusList( status = DeviceStatusList::Instance()->UpdateStatusList(
drm_root_certificate_->public_key(), decoded_certificate_status_list, drm_root_certificate_->public_key(),
serialized_device_certicate_status_list, signature,
device_certificate_expiration_seconds_); device_certificate_expiration_seconds_);
if (!status.ok()) return status; if (!status.ok()) return status;
status = WvPLSDKEnvironment::UpdateProvisionedDeviceInfoMap( status = WvPLSDKEnvironment::UpdateProvisionedDeviceInfoMap(
@@ -232,5 +180,44 @@ WvPLStatus WvPLSDKEnvironment::SetDeviceCertificateStatusList(
return status; return status;
} }
WvPLStatus WvPLSDKEnvironment::CheckServiceCertificateType(
const std::string& service_certificate) {
SignedDrmCertificate signed_drm_certificate;
DrmCertificate drm_certificate;
std::string drm_service_certificate;
if (signed_drm_certificate.ParseFromString(service_certificate)) {
drm_service_certificate = signed_drm_certificate.drm_certificate();
}
if (!drm_certificate.ParseFromString(drm_service_certificate)) {
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
"Fail to parse service_certificate");
}
// TODO(user): after Q3-2019, only support UNKNOWN_SERVICE_TYPE for LSDK
// whose version is older than 5.0.Here is the design doc.
// (https://docs.google.com/document/d/1QVdQ6YfpjVqqNpRbikCWU7DdMHQLyUE4Mimzs9u61lc/edit#heading=h.gyz0lrew3paj)
if (drm_certificate.type() == DrmCertificate::SERVICE) {
if (GetExpectedServiceCertificateType() ==
DrmCertificate::LICENSE_SERVER_SDK) {
return OkStatus();
}
for (auto type : drm_certificate.service_types()) {
if (type == GetExpectedServiceCertificateType()) {
return OkStatus();
}
}
return WvPLStatus(
error_space, error::INVALID_ARGUMENT,
absl::StrCat("Service type in drm certificate is mismatch"));
}
return WvPLStatus(error_space, error::INVALID_ARGUMENT,
absl::StrCat("Type", drm_certificate.type(),
"Service Certificate is wrong type"));
}
widevine::DrmCertificate::ServiceType
WvPLSDKEnvironment::GetExpectedServiceCertificateType() {
return DrmCertificate::UNKNOWN_SERVICE_TYPE;
}
} // namespace wv_pl_sdk } // namespace wv_pl_sdk
} // namespace widevine_server } // namespace widevine_server

View File

@@ -13,10 +13,12 @@
#include <string> #include <string>
#include "sdk/external/common/wvpl/wvpl_types.h" #include "sdk/external/common/wvpl/wvpl_types.h"
#include "protos/public/drm_certificate.pb.h"
namespace widevine { namespace widevine {
class DeviceCertificateStatusList; class DeviceCertificateStatusList;
class DrmRootCertificate; class DrmRootCertificate;
class DrmCertificate;
class ProvisionedDeviceInfo; class ProvisionedDeviceInfo;
} // namespace widevine } // namespace widevine
namespace widevine_server { namespace widevine_server {
@@ -88,8 +90,6 @@ class WvPLSDKEnvironment {
WvPLStatus SetDeviceCertificateStatusList(const std::string& cert_list) const; WvPLStatus SetDeviceCertificateStatusList(const std::string& cert_list) const;
static void SetConfigValue(const std::map<std::string, std::string>& config_values);
// Number of seconds until the certificate status list expires after its // Number of seconds until the certificate status list expires after its
// creation time. Default value is 604800 seconds. // creation time. Default value is 604800 seconds.
uint32_t device_certificate_expiration_seconds_ = 604800; uint32_t device_certificate_expiration_seconds_ = 604800;
@@ -99,10 +99,9 @@ class WvPLSDKEnvironment {
// name of the provider hosting this service. // name of the provider hosting this service.
std::string provider_; std::string provider_;
// value of the "iv" specified for the provider. // value of the "iv" specified for the provider.
std::string* provider_iv_; std::string provider_iv_;
// value of the "key" specified for the provider. // value of the "key" specified for the provider.
std::string* provider_key_; std::string provider_key_;
static std::map<std::string, std::string>* config_values_;
// is_service_certificate_loaded_ is not thread safe. // is_service_certificate_loaded_ is not thread safe.
bool is_service_certificate_loaded_ = false; bool is_service_certificate_loaded_ = false;
// If true, allow devices not in the certificate status list. // If true, allow devices not in the certificate status list.
@@ -111,6 +110,15 @@ class WvPLSDKEnvironment {
std::unique_ptr<widevine::DrmRootCertificate> drm_root_certificate_; std::unique_ptr<widevine::DrmRootCertificate> drm_root_certificate_;
private: private:
// Get the expected service type for drm service certificate.
virtual widevine::DrmCertificate::ServiceType
GetExpectedServiceCertificateType();
// Check the type of |service_certificate|. Returns "OK" if the cert can be
// used for the current SDK, else an error status.
virtual WvPLStatus CheckServiceCertificateType(
const std::string& service_certificate);
/** /**
* Return provisioned_device_info if the device_info_map_ contains system_id. * Return provisioned_device_info if the device_info_map_ contains system_id.
* *
@@ -126,8 +134,6 @@ class WvPLSDKEnvironment {
static void AddDeviceInfo( static void AddDeviceInfo(
const widevine::ProvisionedDeviceInfo& provisioned_device_info); const widevine::ProvisionedDeviceInfo& provisioned_device_info);
static std::map<std::string, std::string>* GetConfigValue();
friend class WvPLSDKSession; friend class WvPLSDKSession;
friend class WvPLProxySession; friend class WvPLProxySession;
friend class WvPLProxySessionTest; friend class WvPLProxySessionTest;

View File

@@ -19,10 +19,12 @@
#include "sdk/external/common/wvpl/wvpl_sdk_environment.h" #include "sdk/external/common/wvpl/wvpl_sdk_environment.h"
#include "sdk/external/common/wvpl/wvpl_types.h" #include "sdk/external/common/wvpl/wvpl_types.h"
#include "protos/public/client_identification.pb.h" #include "protos/public/client_identification.pb.h"
#include "protos/public/drm_certificate.pb.h"
#include "protos/public/errors.pb.h" #include "protos/public/errors.pb.h"
#include "protos/public/license_protocol.pb.h" #include "protos/public/license_protocol.pb.h"
#include "protos/public/license_server_sdk.pb.h" #include "protos/public/license_server_sdk.pb.h"
#include "protos/public/provisioned_device_info.pb.h" #include "protos/public/provisioned_device_info.pb.h"
#include "protos/public/signed_drm_certificate.pb.h"
#include "protos/public/widevine_pssh.pb.h" #include "protos/public/widevine_pssh.pb.h"
// TODO(user): Mark getProvisionedDeviceInfo as deprecated, move the // TODO(user): Mark getProvisionedDeviceInfo as deprecated, move the
@@ -34,7 +36,7 @@
// wvpl_sdk_session_test.cc. // wvpl_sdk_session_test.cc.
// TODO(user): Remove sdk_license_request_ and both proxy and wvpl LSDK set // TODO(user): Remove sdk_license_request_ and both proxy and wvpl LSDK set
// signed_message_request_from_cdm_ when create session. // signed_message_request_from_cdm_ when create session.
// TODO(user): Move all the protected memeber variables to private and use // TODO(user): Move all the protected member variables to private and use
// getter and setter to access it. // getter and setter to access it.
// TODO(user): (b/119566765) Refactor ParseLicenseRequest and break it into // TODO(user): (b/119566765) Refactor ParseLicenseRequest and break it into
// different classes. // different classes.
@@ -332,8 +334,6 @@ void WvPLSDKSession::CopySessionState(
} }
} }
MessageType WvPLSDKSession::message_type() const { return message_type_; }
void WvPLSDKSession::CopyHDCP( void WvPLSDKSession::CopyHDCP(
HDCP hdcp_value, HDCP hdcp_value,
License::KeyContainer::OutputProtection* output_protection) { License::KeyContainer::OutputProtection* output_protection) {
@@ -504,7 +504,7 @@ WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
case SignedMessage::LICENSE_REQUEST: case SignedMessage::LICENSE_REQUEST:
// TODO(user): Add CAS enum(s) to message_type_ in wvpl_types.h. // TODO(user): Add CAS enum(s) to message_type_ in wvpl_types.h.
case SignedMessage::CAS_LICENSE_REQUEST: case SignedMessage::CAS_LICENSE_REQUEST:
message_type_ = LICENSE_REQUEST; type_.set_message_type(LICENSE_REQUEST);
DCHECK(signed_message_request_from_cdm_); DCHECK(signed_message_request_from_cdm_);
sdk_license_request_ = absl::make_unique<LicenseRequest>(); sdk_license_request_ = absl::make_unique<LicenseRequest>();
if (!sdk_license_request_->ParseFromString( if (!sdk_license_request_->ParseFromString(
@@ -516,14 +516,17 @@ WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
} }
break; break;
case SignedMessage::SERVICE_CERTIFICATE_REQUEST: case SignedMessage::SERVICE_CERTIFICATE_REQUEST:
message_type_ = SERVICE_CERTIFICATE_REQUEST; type_.set_message_type(SERVICE_CERTIFICATE_REQUEST);
return WvPLStatus(error_space,
widevine::SERVICE_CERTIFICATE_REQUEST_MESSAGE,
"Service Certificate Request message received.");
break; break;
default: default:
break; break;
} }
} }
// This code is used by proxy and wvpl license server sdk. // This code is used by proxy and wvpl license server sdk.
if (message_type_ == LICENSE_REQUEST) { if (type_.message_type() == LICENSE_REQUEST) {
// Parse for ClientIdentification in license request. // Parse for ClientIdentification in license request.
if (sdk_license_request_->has_client_id() && if (sdk_license_request_->has_client_id() &&
sdk_license_request_->has_encrypted_client_id()) { sdk_license_request_->has_encrypted_client_id()) {
@@ -556,13 +559,14 @@ WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
SetSystemId(KeyboxClientCert::GetSystemId(client_id_->token())); SetSystemId(KeyboxClientCert::GetSystemId(client_id_->token()));
} }
if (!HasSystemId()) { if (!HasSystemId()) {
ClientCert* client_cert_ptr = nullptr; widevine::SignedDrmCertificate signed_drm_certificate;
status = ClientCert::Create( if (signed_drm_certificate.ParseFromString(client_id_->token())) {
drm_root_certificate_, sdk_license_request_->client_id().type(), widevine::DrmCertificate drm_certificate;
sdk_license_request_->client_id().token(), &client_cert_ptr); if (drm_certificate.ParseFromString(
std::unique_ptr<ClientCert> client_cert(client_cert_ptr); signed_drm_certificate.drm_certificate())) {
if (client_cert != nullptr) { SetSystemId(drm_certificate.system_id());
SetSystemId(client_cert->system_id()); device_id_ = drm_certificate.serial_number();
}
} }
} }
// TODO(user): Consider enforcing missing client id here. // TODO(user): Consider enforcing missing client id here.
@@ -581,7 +585,6 @@ WvPLStatus WvPLSDKSession::ParseLicenseRequest() {
LicenseRequestType request_type = LicenseRequestType request_type =
static_cast<LicenseRequestType>(sdk_license_request_->type()); static_cast<LicenseRequestType>(sdk_license_request_->type());
type_.set_license_request_type(request_type); type_.set_license_request_type(request_type);
type_.set_message_type(message_type_);
if (is_offline_license()) { if (is_offline_license()) {
type_.set_license_type(OFFLINE); type_.set_license_type(OFFLINE);
} }
@@ -812,6 +815,9 @@ WvPLStatus WvPLSDKSession::GetPsshData(
wv_pssh.entitled_keys(idx).entitlement_key_size_bytes()); wv_pssh.entitled_keys(idx).entitlement_key_size_bytes());
wvpl_widevine_pssh_data->add_entitled_key(wvpl_entitled_key); wvpl_widevine_pssh_data->add_entitled_key(wvpl_entitled_key);
} }
if (wv_pssh.has_video_feature()) {
wvpl_widevine_pssh_data->set_video_feature(wv_pssh.video_feature());
}
} }
return status; return status;
} else if (content_info.init_data_type() == } else if (content_info.init_data_type() ==
@@ -850,9 +856,11 @@ WvPLStatus WvPLSDKSession::GetDeviceInfo(WvPLDeviceInfo* device_info) const {
ProvisionedDeviceInfo provisioned_device_info; ProvisionedDeviceInfo provisioned_device_info;
status = LookupDeviceInfo(GetSystemId(), &provisioned_device_info); status = LookupDeviceInfo(GetSystemId(), &provisioned_device_info);
if (!status.ok()) { if (!status.ok()) {
return status; LOG(WARNING) << "Request from unknown device. SystemId = "
<< GetSystemId();
} }
device_info->set_system_id(provisioned_device_info.system_id()); device_info->set_drm_certificate_serial_number(device_id_);
device_info->set_system_id(GetSystemId());
if (provisioned_device_info.has_soc()) { if (provisioned_device_info.has_soc()) {
device_info->set_soc(provisioned_device_info.soc()); device_info->set_soc(provisioned_device_info.soc());
} }
@@ -884,7 +892,7 @@ WvPLStatus WvPLSDKSession::GetDeviceInfo(WvPLDeviceInfo* device_info) const {
default: default:
break; break;
} }
return status; return OkStatus();
} }
WvPLStatus WvPLSDKSession::LookupDeviceInfo( WvPLStatus WvPLSDKSession::LookupDeviceInfo(
@@ -904,20 +912,6 @@ uint32_t WvPLSDKSession::GetSystemId() const {
return *system_id_; return *system_id_;
} }
std::string WvPLSDKSession::session_id() const {
DCHECK(sdk_license_request_);
const LicenseRequest::ContentIdentification& content_id =
sdk_license_request_->content_id();
if (content_id.existing_license().license_id().has_session_id())
return content_id.existing_license().license_id().session_id();
else if (content_id.has_widevine_pssh_data())
return content_id.widevine_pssh_data().request_id();
else if (content_id.has_webm_key_id())
return content_id.webm_key_id().request_id();
else
return std::string();
}
bool WvPLSDKSession::is_offline_license() const { bool WvPLSDKSession::is_offline_license() const {
DCHECK(sdk_license_request_); DCHECK(sdk_license_request_);
if (sdk_license_request_ == nullptr) return false; if (sdk_license_request_ == nullptr) return false;

View File

@@ -38,7 +38,7 @@ class WvPLSDKSession {
virtual WvPLStatus AddKey(const WvPLKey& key); virtual WvPLStatus AddKey(const WvPLKey& key);
// Get the WvPLKey. // Get the WvPLKey.
virtual const std::vector<WvPLKey>& key() const { return keys_; } virtual const std::vector<WvPLKey>& keys() const { return keys_; }
// Set the license policy. // Set the license policy.
virtual void set_policy(const WvPLPlaybackPolicy& policy) { virtual void set_policy(const WvPLPlaybackPolicy& policy) {
@@ -95,18 +95,9 @@ class WvPLSDKSession {
*/ */
virtual WvPLStatus GetDeviceInfo(WvPLDeviceInfo* device_info) const; virtual WvPLStatus GetDeviceInfo(WvPLDeviceInfo* device_info) const;
/**
* Returns the type of the message handled by this session.
*
* @return MessageType enumeration.
* @deprecated use request_type instead.
* @since end of Q1, 2019
*/
virtual MessageType message_type() const;
virtual PlatformVerificationStatus VerifyPlatform() = 0; virtual PlatformVerificationStatus VerifyPlatform() = 0;
virtual WvPLRequestType request_type() const { return type_; } virtual WvPLRequestType GetRequestType() const { return type_; }
/** /**
* Returns true if the license type is offline, otherwise return false. * Returns true if the license type is offline, otherwise return false.
@@ -115,14 +106,6 @@ class WvPLSDKSession {
*/ */
virtual bool is_offline_license() const; virtual bool is_offline_license() const;
/**
* A session id that remains constant throughout a session. All license
* and heartbeat requests in a session have the same session id.
*
* @return string.
*/
virtual std::string session_id() const;
/** /**
* Returns the license request contains client id or not. * Returns the license request contains client id or not.
* *
@@ -130,16 +113,6 @@ class WvPLSDKSession {
*/ */
virtual bool has_client_id() const { return has_client_id_; } virtual bool has_client_id() const { return has_client_id_; }
/**
* Returns true if remote_attestation_cert_serial_number is not empty.
* Otherwise return false.
*
* @return bool.
*/
virtual bool remote_attestation_verified() {
return !remote_attestation_cert_serial_number_.empty();
}
/** /**
* Returns true if license request has encrypted_client_id. Otherwise return * Returns true if license request has encrypted_client_id. Otherwise return
* false. * false.
@@ -151,6 +124,7 @@ class WvPLSDKSession {
protected: protected:
const widevine::DrmRootCertificate* drm_root_certificate_; const widevine::DrmRootCertificate* drm_root_certificate_;
std::string user_agent_; std::string user_agent_;
std::string device_id_;
std::vector<WvPLKey> keys_; std::vector<WvPLKey> keys_;
WvPLPlaybackPolicy policy_; WvPLPlaybackPolicy policy_;
WvPLSessionInit session_init_; WvPLSessionInit session_init_;
@@ -158,7 +132,6 @@ class WvPLSDKSession {
std::unique_ptr<widevine::ClientIdentification> client_id_; std::unique_ptr<widevine::ClientIdentification> client_id_;
bool has_pssh_data_ = false; bool has_pssh_data_ = false;
bool has_client_id_ = false; bool has_client_id_ = false;
MessageType message_type_ = UNKNOWN;
PlatformVerificationStatus platform_verification_status_ = PlatformVerificationStatus platform_verification_status_ =
PLATFORM_NO_VERIFICATION; PLATFORM_NO_VERIFICATION;
std::unique_ptr<widevine::SignedMessage> std::unique_ptr<widevine::SignedMessage>

View File

@@ -41,8 +41,27 @@ enum KeyType {
ENTITLEMENT = 2 ENTITLEMENT = 2
}; };
// A shortcut for specifying whether to return keys for the video feature only
// or to return all keys or ignore the video feature.
// The VideoFeatureKeySet only applies when video feature is specified in the
// PSSH.
// LINT.IfChange
enum VideoFeatureKeySet {
VF_UNSPECIFIED = 0,
// License should not include keys for the video feature, instead only
// include keys not associated with the video feature.
VF_EXCLUDED = 1,
// License should only include keys associated with the video feature
// (e.g., HDR).
VF_ONLY = 2,
// License should include keys for the video feature and also for keys
// not associated with the video feature (e.g., SDR keys).
VF_INCLUDED = 3,
};
// LINT.IfChange // LINT.IfChange
enum LicenseType { enum LicenseType {
LICENSE_TYPE_UNSPECIFIED = 0,
STREAMING = 1, STREAMING = 1,
OFFLINE = 2, OFFLINE = 2,
}; };
@@ -586,10 +605,13 @@ struct WvPLDeviceInfo {
void set_test_device(bool test_device) { test_device_ = test_device; } void set_test_device(bool test_device) { test_device_ = test_device; }
bool test_device() const { return test_device_; } bool test_device() const { return test_device_; }
void set_serial_number(const std::string& serial_number) { void set_drm_certificate_serial_number(
serial_number_ = serial_number; const std::string& drm_certificate_serial_number) {
drm_certificate_serial_number_ = drm_certificate_serial_number;
}
const std::string& drm_certificate_serial_number() const {
return drm_certificate_serial_number_;
} }
const std::string& serial_number() const { return serial_number_; }
void set_service_id(const std::string& service_id) { void set_service_id(const std::string& service_id) {
service_id_ = service_id; service_id_ = service_id;
@@ -611,7 +633,7 @@ struct WvPLDeviceInfo {
// True if the certificate corresponds to a test (non production) device. // True if the certificate corresponds to a test (non production) device.
bool test_device_; bool test_device_;
// 128-bit globally unique serial number of certificate. // 128-bit globally unique serial number of certificate.
std::string serial_number_; std::string drm_certificate_serial_number_;
// Service identifier (web origin) for the provider which owns the // Service identifier (web origin) for the provider which owns the
// certificate. // certificate.
std::string service_id_; std::string service_id_;
@@ -975,6 +997,11 @@ struct WvPLWidevinePsshData {
return entitled_keys_; return entitled_keys_;
} }
void set_video_feature(const std::string& video_feature) {
video_feature_ = video_feature;
}
const std::string video_feature() const { return video_feature_; }
// Member variables // Member variables
// A list of key identifiers, for entitlement keys or content keys. // A list of key identifiers, for entitlement keys or content keys.
std::list<std::string> key_ids_; std::list<std::string> key_ids_;
@@ -982,6 +1009,8 @@ struct WvPLWidevinePsshData {
std::string content_id_; std::string content_id_;
// A list of wrapped keys. // A list of wrapped keys.
std::list<WvPLEntitledKey> entitled_keys_; std::list<WvPLEntitledKey> entitled_keys_;
// Video feature identifier.
std::string video_feature_;
}; };
struct WvPLCasKey { struct WvPLCasKey {