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:
Fred Gylys-Colwell
2020-01-18 10:11:24 -08:00
parent 7e2619e379
commit 7665614b2e
132 changed files with 12331 additions and 9341 deletions

View File

@@ -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;
}