OEMCrypto v16.1
Merge of http://go/wvgerrit/93404 This CL updates the Widevine CDM to support OEMCrypto v16.1 Test: Tested in 16.2 CL Bug: 141247171 Change-Id: I69bd993500f6fb63bf6010c8b0250dc7acc3d71b
This commit is contained in:
@@ -53,7 +53,8 @@ using video_widevine::LicenseRequest_ContentIdentification_WebmDeprecated;
|
||||
using video_widevine::SignedDrmDeviceCertificate;
|
||||
using video_widevine::SignedMessage;
|
||||
|
||||
static std::vector<CryptoKey> ExtractEntitlementKeys(const License& license) {
|
||||
namespace {
|
||||
std::vector<CryptoKey> ExtractEntitlementKeys(const License& license) {
|
||||
std::vector<CryptoKey> key_array;
|
||||
|
||||
for (int i = 0; i < license.key_size(); ++i) {
|
||||
@@ -108,7 +109,7 @@ static std::vector<CryptoKey> ExtractEntitlementKeys(const License& license) {
|
||||
return key_array;
|
||||
}
|
||||
|
||||
static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
std::vector<CryptoKey> key_array;
|
||||
|
||||
// Extract content key(s)
|
||||
@@ -174,6 +175,7 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
|
||||
return key_array;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
: crypto_session_(nullptr),
|
||||
@@ -182,6 +184,7 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
initialized_(false),
|
||||
renew_with_client_id_(false),
|
||||
is_offline_(false),
|
||||
supports_core_messages_(true),
|
||||
use_privacy_mode_(false),
|
||||
clock_(new Clock()),
|
||||
license_key_type_(kLicenseKeyTypeContent) {}
|
||||
@@ -193,6 +196,7 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock)
|
||||
initialized_(false),
|
||||
renew_with_client_id_(false),
|
||||
is_offline_(false),
|
||||
supports_core_messages_(true),
|
||||
use_privacy_mode_(false),
|
||||
license_key_type_(kLicenseKeyTypeContent) {
|
||||
clock_.reset(clock);
|
||||
@@ -336,10 +340,12 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
|
||||
key_request_ = serialized_license_req;
|
||||
|
||||
// Derive signing and encryption keys and construct signature.
|
||||
// Derive signing and encryption keys and construct core message and
|
||||
// signature.
|
||||
std::string core_message;
|
||||
std::string license_request_signature;
|
||||
status = crypto_session_->PrepareRequest(serialized_license_req, false,
|
||||
&license_request_signature);
|
||||
status = crypto_session_->PrepareAndSignLicenseRequest(
|
||||
serialized_license_req, &core_message, &license_request_signature);
|
||||
|
||||
if (status != NO_ERROR) {
|
||||
signed_request->clear();
|
||||
@@ -357,6 +363,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
signed_message.set_type(SignedMessage::LICENSE_REQUEST);
|
||||
signed_message.set_signature(license_request_signature);
|
||||
signed_message.set_msg(serialized_license_req);
|
||||
signed_message.set_oemcrypto_core_message(core_message);
|
||||
|
||||
signed_message.SerializeToString(signed_request);
|
||||
|
||||
@@ -474,10 +481,11 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
std::string serialized_license_req;
|
||||
license_request.SerializeToString(&serialized_license_req);
|
||||
|
||||
// Construct signature.
|
||||
// Construct signature and core message.
|
||||
std::string core_message;
|
||||
std::string license_request_signature;
|
||||
status = crypto_session_->PrepareRenewalRequest(serialized_license_req,
|
||||
&license_request_signature);
|
||||
status = crypto_session_->PrepareAndSignRenewalRequest(
|
||||
serialized_license_req, &core_message, &license_request_signature);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
if (license_request_signature.empty()) {
|
||||
@@ -490,6 +498,11 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
signed_message.set_type(SignedMessage::LICENSE_REQUEST);
|
||||
signed_message.set_signature(license_request_signature);
|
||||
signed_message.set_msg(serialized_license_req);
|
||||
if (supports_core_messages()) {
|
||||
// Only include the |core_message| in renewal requests if it is
|
||||
// already known that the license is v16.
|
||||
signed_message.set_oemcrypto_core_message(core_message);
|
||||
}
|
||||
|
||||
signed_message.SerializeToString(signed_request);
|
||||
*server_url = server_url_;
|
||||
@@ -543,8 +556,23 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
return LICENSE_RESPONSE_NOT_SIGNED;
|
||||
}
|
||||
|
||||
// Check that the server returned a |core_message|. If missing, then
|
||||
// the server is assumed to operate as V15. This will imply that the
|
||||
// |signature| field in the respones does not include a core message
|
||||
// either.
|
||||
if (!signed_response.has_oemcrypto_core_message()) {
|
||||
supports_core_messages_ = false;
|
||||
}
|
||||
|
||||
const std::string& signed_message = signed_response.msg();
|
||||
const std::string core_message =
|
||||
signed_response.has_oemcrypto_core_message()
|
||||
? signed_response.oemcrypto_core_message()
|
||||
: std::string();
|
||||
const std::string& signature = signed_response.signature();
|
||||
|
||||
License license;
|
||||
if (!license.ParseFromString(signed_response.msg())) {
|
||||
if (!license.ParseFromString(signed_message)) {
|
||||
LOGE("Unable to parse license response");
|
||||
return LICENSE_RESPONSE_PARSE_ERROR_1;
|
||||
}
|
||||
@@ -581,6 +609,11 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
}
|
||||
}
|
||||
|
||||
// A license may contain several types of keys (content, entitlement,
|
||||
// signing, key control and operator sessions); however, it should not
|
||||
// contain both entitlement keys and content keys. To determine the
|
||||
// overall type of the license, we check for the existence of either
|
||||
// type of keys. If both are present, we default to entitlement keys.
|
||||
CdmLicenseKeyType key_type = kLicenseKeyTypeEntitlement;
|
||||
std::vector<CryptoKey> key_array = ExtractEntitlementKeys(license);
|
||||
if (key_array.empty()) {
|
||||
@@ -629,13 +662,12 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
|
||||
CdmResponseType resp = NO_CONTENT_KEY;
|
||||
if (kLicenseKeyTypeEntitlement == key_type) {
|
||||
resp = HandleEntitlementKeyResponse(signed_response.msg(),
|
||||
signed_response.signature(), mac_key_iv,
|
||||
mac_keys, key_array, license);
|
||||
resp =
|
||||
HandleEntitlementKeyResponse(signed_message, core_message, signature,
|
||||
mac_key_iv, mac_keys, key_array, license);
|
||||
} else if (kLicenseKeyTypeContent == key_type) {
|
||||
resp = HandleContentKeyResponse(signed_response.msg(),
|
||||
signed_response.signature(), mac_key_iv,
|
||||
mac_keys, key_array, license);
|
||||
resp = HandleContentKeyResponse(signed_message, core_message, signature,
|
||||
mac_key_iv, mac_keys, key_array, license);
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
@@ -668,13 +700,29 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
return INVALID_LICENSE_TYPE;
|
||||
}
|
||||
|
||||
// At this point of the license life-cycle (handling a renewal or
|
||||
// release), we should already know if the license is v15 or not.
|
||||
// If license is v16, then there should be a |core_message|
|
||||
// present; otherwise there might have beeen some tampering with the
|
||||
// request or response.
|
||||
if (supports_core_messages() &&
|
||||
!signed_response.has_oemcrypto_core_message()) {
|
||||
LOGE("Renewal response is missing |core_message| field");
|
||||
return CORE_MESSAGE_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!signed_response.has_signature()) {
|
||||
LOGE("Update key response is missing signature");
|
||||
return SIGNATURE_NOT_FOUND;
|
||||
}
|
||||
const std::string& signed_message = signed_response.msg();
|
||||
const std::string core_message =
|
||||
supports_core_messages() ? signed_response.oemcrypto_core_message()
|
||||
: std::string();
|
||||
const std::string& signature = signed_response.signature();
|
||||
|
||||
License license;
|
||||
if (!license.ParseFromString(signed_response.msg())) {
|
||||
if (!license.ParseFromString(signed_message)) {
|
||||
LOGE("Unable to parse license from signed message");
|
||||
return LICENSE_RESPONSE_PARSE_ERROR_3;
|
||||
}
|
||||
@@ -690,12 +738,8 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
|
||||
if (!is_renewal) {
|
||||
if (!license.id().has_provider_session_token()) return KEY_ADDED;
|
||||
|
||||
provider_session_token_ = license.id().provider_session_token();
|
||||
CdmResponseType status = crypto_session_->ReleaseUsageInformation(
|
||||
signed_response.msg(), signed_response.signature(),
|
||||
provider_session_token_);
|
||||
return (NO_ERROR == status) ? KEY_ADDED : status;
|
||||
return KEY_ADDED;
|
||||
}
|
||||
|
||||
if (license.policy().has_renewal_server_url() &&
|
||||
@@ -703,11 +747,14 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
server_url_ = license.policy().renewal_server_url();
|
||||
}
|
||||
|
||||
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
|
||||
|
||||
CdmResponseType status = crypto_session_->RefreshKeys(
|
||||
signed_response.msg(), signed_response.signature(), key_array.size(),
|
||||
&key_array[0]);
|
||||
CdmResponseType status;
|
||||
if (supports_core_messages()) {
|
||||
status =
|
||||
crypto_session_->LoadRenewal(signed_message, core_message, signature);
|
||||
} else {
|
||||
std::vector<CryptoKey> key_array = ExtractContentKeys(license);
|
||||
status = crypto_session_->RefreshKeys(signed_message, signature, key_array);
|
||||
}
|
||||
|
||||
if (status == KEY_ADDED) {
|
||||
policy_engine_->UpdateLicense(license);
|
||||
@@ -750,6 +797,12 @@ CdmResponseType CdmLicense::RestoreOfflineLicense(
|
||||
return INVALID_LICENSE_REQUEST_TYPE_1;
|
||||
}
|
||||
|
||||
if (!signed_request.has_oemcrypto_core_message()) {
|
||||
// Pre V16 license did not include |core_message| components.
|
||||
// The license response is checked by HandleKeyResponse().
|
||||
supports_core_messages_ = false;
|
||||
}
|
||||
|
||||
key_request_ = signed_request.msg();
|
||||
CdmResponseType sts = HandleKeyResponse(license_response);
|
||||
|
||||
@@ -827,6 +880,11 @@ CdmResponseType CdmLicense::RestoreLicenseForRelease(
|
||||
return INVALID_LICENSE_REQUEST_TYPE_2;
|
||||
}
|
||||
|
||||
if (!signed_request.has_oemcrypto_core_message()) {
|
||||
// Pre V16 license did not include |core_message| components.
|
||||
supports_core_messages_ = false;
|
||||
}
|
||||
|
||||
key_request_ = signed_request.msg();
|
||||
|
||||
SignedMessage signed_response;
|
||||
@@ -847,6 +905,13 @@ CdmResponseType CdmLicense::RestoreLicenseForRelease(
|
||||
return SIGNATURE_NOT_FOUND_2;
|
||||
}
|
||||
|
||||
if (!signed_response.has_oemcrypto_core_message()) {
|
||||
// Possible that the request contains a |core_message|, but the
|
||||
// response does not. This would occur if the licensing server
|
||||
// is v15.
|
||||
supports_core_messages_ = false;
|
||||
}
|
||||
|
||||
License license;
|
||||
if (!license.ParseFromString(signed_response.msg())) {
|
||||
LOGE("Failed to parse license response");
|
||||
@@ -1016,17 +1081,22 @@ CdmResponseType CdmLicense::PrepareContentId(
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleContentKeyResponse(
|
||||
const std::string& msg, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const std::string& msg, const std::string& core_message,
|
||||
const std::string& signature, const std::string& mac_key_iv,
|
||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
||||
const video_widevine::License& license) {
|
||||
if (key_array.empty()) {
|
||||
LOGE("No content keys provided");
|
||||
return NO_CONTENT_KEY;
|
||||
}
|
||||
CdmResponseType resp = crypto_session_->LoadKeys(
|
||||
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
|
||||
license.srm_requirement(), kLicenseKeyTypeContent);
|
||||
CdmResponseType resp;
|
||||
if (supports_core_messages()) {
|
||||
resp = crypto_session_->LoadLicense(msg, core_message, signature);
|
||||
} else {
|
||||
resp = crypto_session_->LoadKeys(
|
||||
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
|
||||
license.srm_requirement(), kLicenseKeyTypeContent);
|
||||
}
|
||||
|
||||
if (KEY_ADDED == resp) {
|
||||
loaded_keys_.clear();
|
||||
@@ -1040,17 +1110,23 @@ CdmResponseType CdmLicense::HandleContentKeyResponse(
|
||||
}
|
||||
|
||||
CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
|
||||
const std::string& msg, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const std::string& msg, const std::string& core_message,
|
||||
const std::string& signature, const std::string& mac_key_iv,
|
||||
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
|
||||
const video_widevine::License& license) {
|
||||
if (key_array.empty()) {
|
||||
LOGE("No entitlement keys provided");
|
||||
return NO_CONTENT_KEY;
|
||||
}
|
||||
CdmResponseType resp = crypto_session_->LoadKeys(
|
||||
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
|
||||
license.srm_requirement(), kLicenseKeyTypeEntitlement);
|
||||
CdmResponseType resp;
|
||||
if (supports_core_messages()) {
|
||||
resp = crypto_session_->LoadLicense(msg, core_message, signature);
|
||||
} else {
|
||||
resp = crypto_session_->LoadKeys(
|
||||
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
|
||||
license.srm_requirement(), kLicenseKeyTypeEntitlement);
|
||||
}
|
||||
|
||||
if (KEY_ADDED != resp) {
|
||||
return resp;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user