Source release 19.4.0

This commit is contained in:
Vicky Min
2024-11-27 00:07:23 +00:00
parent 11c108a8da
commit 22759672a8
72 changed files with 5321 additions and 2622 deletions

View File

@@ -903,6 +903,46 @@ CdmResponseType CdmEngine::QueryStatus(RequestedSecurityLevel security_level,
LOGE("Failed to extract BCC: status = %d", status.ToInt());
return status;
}
if (query_token == QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN_SIGNATURE) {
std::string bcc_unused;
std::string signature;
const CdmResponseType status = crypto_session->GetBootCertificateChain(
security_level, &bcc_unused, &signature);
if (status == NO_ERROR) {
LOGV("BCC signature length: %zu", signature.size());
*query_response = std::move(signature);
return CdmResponseType(NO_ERROR);
}
if (status == NOT_IMPLEMENTED_ERROR ||
status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) {
LOGD("BCC signature not available: %s", status.ToString().c_str());
*query_response = QUERY_VALUE_NONE;
return CdmResponseType(NO_ERROR);
}
LOGE("Failed to extract BCC signature: status = %s",
status.ToString().c_str());
return status;
}
if (query_token == QUERY_KEY_DEBUG_BOOT_CERTIFICATE_CHAIN_SIGNATURE_TYPE) {
OEMCrypto_BCCSignatureType bcc_signature_type =
OEMCrypto_BCCSigType_Unknown;
const CdmResponseType status =
crypto_session->GetBootCertificateChainSignatureType(
security_level, &bcc_signature_type);
if (status == NO_ERROR) {
*query_response = OemCryptoBccSignatureTypeToString(bcc_signature_type);
return CdmResponseType(NO_ERROR);
}
if (status == NOT_IMPLEMENTED_ERROR ||
status == PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR) {
LOGD("BCC signature type not available: %s", status.ToString().c_str());
*query_response = QUERY_VALUE_NONE;
return CdmResponseType(NO_ERROR);
}
LOGE("Failed to extract BCC signature type: status = %s",
status.ToString().c_str());
return status;
}
if (query_token == QUERY_KEY_DEVICE_INFORMATION) {
std::string device_info;
const CdmResponseType status =

View File

@@ -570,8 +570,7 @@ CdmResponseType CdmSession::AddKeyInternal(const CdmKeyResponse& key_response) {
if (sts != NO_ERROR) return sts;
}
}
sts =
license_parser_->HandleKeyResponse(/* is restore */ false, key_response);
sts = license_parser_->HandleKeyResponse(key_response);
// Update the license sdk and service versions.
const video_widevine::VersionInfo& version_info =
@@ -779,8 +778,7 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
return CdmResponseType(NOT_INITIALIZED_ERROR);
}
CdmResponseType sts = license_parser_->HandleKeyUpdateResponse(
/* is renewal */ true,
/* is restore */ false, key_response);
/* is renewal */ true, key_response);
// Record the timing on success.
UpdateRequestLatencyTiming(sts);
@@ -844,8 +842,7 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
return CdmResponseType(NOT_INITIALIZED_ERROR);
}
CdmResponseType sts = license_parser_->HandleKeyUpdateResponse(
/* is renewal */ false,
/* is restore */ false, key_response);
/* is renewal */ false, key_response);
// Record the timing on success.
UpdateRequestLatencyTiming(sts);

View File

@@ -60,6 +60,8 @@ bool IsPropertyKeyReserved(const std::string& prop_name) {
// Protobuf generated classes.
using ClientCapabilities =
video_widevine::ClientIdentification::ClientCapabilities;
using ClientCredentials =
video_widevine::ClientIdentification::ClientCredentials;
using AnalogOutputCapabilities = ClientCapabilities::AnalogOutputCapabilities;
using video_widevine::ClientIdentification_NameValue;
@@ -141,7 +143,17 @@ CdmResponseType ClientIdentification::Prepare(
}
client_id->set_token(token);
if (!additional_token.empty()) {
// additional_token is only available for Provisioning 4.0 request, it
// holds the BCC signature.
client_id->mutable_device_credentials()->set_token(additional_token);
ClientCredentials::CredentialType token_signature_type;
if (!GetProvisioning40TokenSignatureType(&token_signature_type)) {
client_id->mutable_device_credentials()->set_credential_type(
ClientCredentials::CREDENTIAL_TYPE_UNKNOWN);
} else {
client_id->mutable_device_credentials()->set_credential_type(
token_signature_type);
}
}
}
@@ -416,4 +428,32 @@ bool ClientIdentification::GetProvisioningTokenType(
}
}
bool ClientIdentification::GetProvisioning40TokenSignatureType(
video_widevine::ClientIdentification::ClientCredentials::CredentialType*
token_signature_type) {
OEMCrypto_BCCSignatureType bcc_signature_type = OEMCrypto_BCCSigType_Unknown;
const CdmResponseType status =
crypto_session_->GetProvisioning40TokenSignatureType(&bcc_signature_type);
if (status != NO_ERROR) {
LOGE("Failed to get provisioning token signature type: status = %s",
status.ToString().c_str());
return false;
}
switch (bcc_signature_type) {
case OEMCrypto_BCCSigType_CBOR:
*token_signature_type =
ClientCredentials::CREDENTIAL_TYPE_BCC_SIGNATURE_CBOR;
return true;
case OEMCrypto_BCCSigType_PKCS7:
*token_signature_type =
ClientCredentials::CREDENTIAL_TYPE_BCC_SIGNATURE_PKCS7;
return true;
default:
// shouldn't happen
LOGE("Unexpected provisioning token signature type: %d",
static_cast<int>(bcc_signature_type));
return false;
}
}
} // namespace wvcdm

View File

@@ -151,6 +151,7 @@ void AdvanceDestBuffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
switch (dest_buffer->type) {
case OEMCrypto_BufferType_Clear:
dest_buffer->buffer.clear.clear_buffer += bytes;
dest_buffer->buffer.clear.clear_buffer_length -= bytes;
return;
case OEMCrypto_BufferType_Secure:
@@ -681,6 +682,26 @@ CdmResponseType CryptoSession::GetProvisioning40TokenType(
"GetProvisioning40TokenType");
}
CdmResponseType CryptoSession::GetProvisioning40TokenSignatureType(
OEMCrypto_BCCSignatureType* bcc_signature_type) {
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
return GetProvisioning40TokenSignatureType(requested_security_level_,
bcc_signature_type);
}
CdmResponseType CryptoSession::GetProvisioning40TokenSignatureType(
RequestedSecurityLevel requested_security_level,
OEMCrypto_BCCSignatureType* bcc_signature_type) {
RETURN_IF_NULL(bcc_signature_type, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
const OEMCryptoResult result = WithOecReadLock("GetBCCSignatureType", [&] {
return OEMCrypto_GetBCCSignatureType(requested_security_level,
bcc_signature_type);
});
return MapOEMCryptoResult(result, GET_BCC_SIGNATURE_TYPE_ERROR,
"GetProvisioning40TokenSignatureType");
}
CdmSecurityLevel CryptoSession::GetSecurityLevel() {
LOGV("Getting security level");
RETURN_IF_NOT_OPEN(kSecurityLevelUninitialized);
@@ -1444,6 +1465,41 @@ CdmResponseType CryptoSession::GetBootCertificateChain(
return CdmResponseType(NO_ERROR);
}
CdmResponseType CryptoSession::GetBootCertificateChainSignatureType(
OEMCrypto_BCCSignatureType* bcc_signature_type) {
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
return GetBootCertificateChainSignatureType(requested_security_level_,
bcc_signature_type);
}
CdmResponseType CryptoSession::GetBootCertificateChainSignatureType(
RequestedSecurityLevel requested_security_level,
OEMCrypto_BCCSignatureType* bcc_signature_type) {
RETURN_IF_NULL(bcc_signature_type, PARAMETER_NULL);
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
if (GetSecurityLevel(requested_security_level) != kSecurityLevelL1) {
LOGE("CDM only supports L1 provisioning40 token type");
return CdmResponseType(NOT_IMPLEMENTED_ERROR);
}
CdmClientTokenType token_type = kClientTokenUninitialized;
const CdmResponseType status =
GetProvisioningMethod(requested_security_level, &token_type);
if (status != NO_ERROR) {
LOGE("Failed to get token type");
return status;
}
if (token_type != kClientTokenBootCertChain) {
return CdmResponseType(
PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR);
}
const OEMCryptoResult result = WithOecReadLock("GetBCCSignatureType", [&] {
return OEMCrypto_GetBCCSignatureType(requested_security_level,
bcc_signature_type);
});
return MapOEMCryptoResult(result, UNKNOWN_CLIENT_TOKEN_TYPE,
"GetBootCertificateChainSignatureType");
}
CdmResponseType CryptoSession::GetTokenFromEmbeddedCertificate(
RequestedSecurityLevel requested_security_level, std::string* token) {
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
@@ -3263,11 +3319,6 @@ OEMCryptoResult CryptoSession::DecryptSample(
}
fake_sample.buffers.input_data_length = length;
if (fake_sample.buffers.output_descriptor.type ==
OEMCrypto_BufferType_Clear) {
fake_sample.buffers.output_descriptor.buffer.clear
.clear_buffer_length = length;
}
fake_sample.subsamples = &clear_subsample;
fake_sample.subsamples_length = 1;
@@ -3295,11 +3346,6 @@ OEMCryptoResult CryptoSession::DecryptSample(
}
fake_sample.buffers.input_data_length = length;
if (fake_sample.buffers.output_descriptor.type ==
OEMCrypto_BufferType_Clear) {
fake_sample.buffers.output_descriptor.buffer.clear
.clear_buffer_length = length;
}
fake_sample.subsamples = &encrypted_subsample;
fake_sample.subsamples_length = 1;
@@ -3392,10 +3438,6 @@ OEMCryptoResult CryptoSession::LegacyCopyBufferInChunks(
// Calculate the size of the next chunk.
const size_t chunk_size = std::min(remaining_input_data, max_chunk_size);
if (output_descriptor.type == OEMCrypto_BufferType_Clear) {
output_descriptor.buffer.clear.clear_buffer_length = chunk_size;
}
// Re-add "last subsample" flag if this is the last subsample.
if (chunk_size == remaining_input_data) {
subsample_flags |= OEMCrypto_LastSubsample;
@@ -3443,11 +3485,6 @@ OEMCryptoResult CryptoSession::LegacyDecryptInChunks(
// Calculate the size of the next chunk.
const size_t chunk_size = std::min(remaining_input_data, max_chunk_size);
fake_sample.buffers.input_data_length = chunk_size;
if (fake_sample.buffers.output_descriptor.type ==
OEMCrypto_BufferType_Clear) {
fake_sample.buffers.output_descriptor.buffer.clear.clear_buffer_length =
chunk_size;
}
if (is_protected) {
fake_subsample.num_bytes_encrypted = chunk_size;
} else {
@@ -3573,40 +3610,40 @@ CdmResponseType CryptoSession::LoadOtaProvisioning(
}
template <class Func>
auto CryptoSession::WithStaticFieldWriteLock(const char* tag,
Func body) -> decltype(body()) {
auto CryptoSession::WithStaticFieldWriteLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("Static field write lock: %s", tag);
std::unique_lock<wvutil::shared_mutex> auto_lock(static_field_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithStaticFieldReadLock(const char* tag,
Func body) -> decltype(body()) {
auto CryptoSession::WithStaticFieldReadLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("Static field read lock: %s", tag);
wvutil::shared_lock<wvutil::shared_mutex> auto_lock(static_field_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithOecWriteLock(const char* tag,
Func body) -> decltype(body()) {
auto CryptoSession::WithOecWriteLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto write lock: %s", tag);
std::unique_lock<wvutil::shared_mutex> auto_lock(oem_crypto_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithOecReadLock(const char* tag,
Func body) -> decltype(body()) {
auto CryptoSession::WithOecReadLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto read lock: %s", tag);
wvutil::shared_lock<wvutil::shared_mutex> auto_lock(oem_crypto_mutex_);
return body();
}
template <class Func>
auto CryptoSession::WithOecSessionLock(const char* tag,
Func body) -> decltype(body()) {
auto CryptoSession::WithOecSessionLock(const char* tag, Func body)
-> decltype(body()) {
LOGV("OEMCrypto session lock: %s", tag);
wvutil::shared_lock<wvutil::shared_mutex> oec_auto_lock(oem_crypto_mutex_);
std::unique_lock<std::mutex> session_auto_lock(oem_crypto_session_mutex_);

View File

@@ -454,8 +454,7 @@ bool InitializationData::ConstructWidevineInitData(
LOGV("Base64 decode of json data failed");
return false;
}
std::string json_string((const char*)(&json_init_data[0]),
json_init_data.size());
const std::string json_string(json_init_data.begin(), json_init_data.end());
// Parse the Json string using jsmn
jsmn_parser parser;
@@ -513,12 +512,13 @@ bool InitializationData::ConstructWidevineInitData(
break;
case kContentIdState:
if (tokens[i].type == JSMN_STRING) {
std::string base64_content_id(json_string, tokens[i].start,
tokens[i].end - tokens[i].start);
std::vector<uint8_t> content_id_data =
const std::string base64_content_id = json_string.substr(
tokens[i].start, tokens[i].end - tokens[i].start);
const std::vector<uint8_t> content_id_data =
wvutil::Base64Decode(base64_content_id);
content_id.assign(reinterpret_cast<const char*>(&content_id_data[0]),
content_id_data.size());
if (!content_id_data.empty()) {
content_id.assign(content_id_data.begin(), content_id_data.end());
}
}
state = kParseState;
break;

View File

@@ -43,7 +43,6 @@ using ContentIdentification =
using video_widevine::HashAlgorithmProto;
using video_widevine::License;
using video_widevine::LicenseError;
using video_widevine::LicenseIdentification;
using video_widevine::LicenseRequest;
using KeyContainer = video_widevine::License::KeyContainer;
using video_widevine::SignedMessage;
@@ -259,7 +258,12 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
}
client_token_ = client_token;
if (init_data.IsEmpty() && stored_init_data_) {
InitializationData restored_init_data = *stored_init_data_;
// In the event that the first call the PrepareKeyRequest()
// was a service certificate request, |stored_init_data_|
// was set. App may not provide the init data on the second
// call.
const InitializationData restored_init_data(std::move(*stored_init_data_));
// Clear to prevent re-use.
stored_init_data_.reset();
return PrepareKeyRequest(restored_init_data, client_token, license_type,
app_parameters, signed_request, server_url);
@@ -306,10 +310,9 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
const std::string& request_id = crypto_session_->request_id();
LicenseRequest license_request;
CdmResponseType status;
status = PrepareClientId(app_parameters,
/* provider_client_token = */ kEmptyString,
&license_request);
CdmResponseType status = PrepareClientId(
app_parameters,
/* provider_client_token = */ kEmptyString, &license_request);
if (NO_ERROR != status) return status;
status =
@@ -322,7 +325,6 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
// Get/set the nonce. This value will be reflected in the Key Control Block
// of the license response.
status = crypto_session_->GenerateNonce(&license_nonce_);
switch (status.code()) {
case NO_ERROR:
break;
@@ -416,7 +418,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
LOGE("Output parameter |server_url| not provided");
return CdmResponseType(INVALID_PARAMETERS_LIC_2);
}
// If |is_renewal| is false, then this is a release request.
if (is_renewal && !policy_engine_->CanRenew()) {
LOGE("License renewal prohibited");
return CdmResponseType(LICENSE_RENEWAL_PROHIBITED);
@@ -430,24 +432,20 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
}
LicenseRequest license_request;
if (is_renewal)
license_request.set_type(LicenseRequest::RENEWAL);
else
license_request.set_type(LicenseRequest::RELEASE);
license_request.set_type(is_renewal ? LicenseRequest::RENEWAL
: LicenseRequest::RELEASE);
license_request.set_request_time(clock_->GetCurrentTime());
license_request.set_protocol_version(protocol_version_);
if (renew_with_client_id_) {
CdmResponseType status = PrepareClientId(
const CdmResponseType status = PrepareClientId(
app_parameters, provider_client_token_, &license_request);
if (NO_ERROR != status) return status;
}
ContentIdentification::ExistingLicense* current_license =
license_request.mutable_content_id()->mutable_existing_license();
const LicenseIdentification& license_id = policy_engine_->license_id();
current_license->mutable_license_id()->CopyFrom(license_id);
current_license->mutable_license_id()->CopyFrom(policy_engine_->license_id());
int64_t seconds_since_started = 0;
int64_t seconds_since_last_played = 0;
@@ -455,6 +453,8 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
CryptoSession::kUsageDurationsInvalid;
if (!provider_session_token_.empty()) {
if (!is_renewal) {
// On release, must deactivate the usage entry
// to prevent further playback.
const CdmResponseType status =
crypto_session_->DeactivateUsageInformation(provider_session_token_);
if (NO_ERROR != status) return status;
@@ -470,23 +470,31 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
const CdmResponseType status = crypto_session_->GenerateUsageReport(
provider_session_token_, &usage_report, &usage_duration_status,
&seconds_since_started, &seconds_since_last_played);
if (!is_renewal) {
if (NO_ERROR == status)
current_license->set_session_usage_table_entry(usage_report);
else
return CdmResponseType(GENERATE_USAGE_REPORT_ERROR);
if (status == NO_ERROR && !is_renewal) {
current_license->set_session_usage_table_entry(usage_report);
} else if (status != NO_ERROR && !is_renewal) {
// Usage report is required for license release.
return CdmResponseType(GENERATE_USAGE_REPORT_ERROR);
} else if (status != NO_ERROR) { // && is_renewal
// For renewals, failing to generate the usage report is
// not a serious issue.
LOGW("Failed to generate usage report, continuing without: status = %s",
status.ToString().c_str());
}
}
if (CryptoSession::kUsageDurationsValid != usage_duration_status) {
if (policy_engine_->GetSecondsSinceStarted(&seconds_since_started) &&
policy_engine_->GetSecondsSinceLastPlayed(&seconds_since_last_played))
usage_duration_status = CryptoSession::kUsageDurationsValid;
}
if (CryptoSession::kUsageDurationsValid == usage_duration_status) {
// Set timers from usage report.
current_license->set_seconds_since_started(seconds_since_started);
current_license->set_seconds_since_last_played(seconds_since_last_played);
} else if (policy_engine_->GetSecondsSinceStarted(&seconds_since_started) &&
policy_engine_->GetSecondsSinceLastPlayed(
&seconds_since_last_played)) {
// Set timers from license policy engine.
current_license->set_seconds_since_started(seconds_since_started);
current_license->set_seconds_since_last_played(seconds_since_last_played);
} else {
LOGW("Failed to obtain license durations");
}
// License request is complete. Serialize it.
@@ -517,7 +525,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
return CdmResponseType(KEY_MESSAGE);
}
CdmResponseType CdmLicense::HandleKeyResponse(
CdmResponseType CdmLicense::HandleKeyResponseInternal(
bool is_restore, const CdmKeyResponse& license_response) {
if (!initialized_) {
LOGE("CdmLicense not initialized");
@@ -580,27 +588,26 @@ CdmResponseType CdmLicense::HandleKeyResponse(
return CdmResponseType(SESSION_KEYS_NOT_FOUND);
}
// Extract mac key
std::string mac_key_iv;
std::string mac_keys;
for (int i = 0; i < license.key_size(); ++i) {
if (license.key(i).type() == KeyContainer::SIGNING) {
mac_key_iv.assign(license.key(i).iv());
// Strip off PKCS#5 padding
mac_keys.assign(
license.key(i).key().data(),
std::min(kLicenseMacKeySize, license.key(i).key().size()));
}
// Verify signing key data and IV length.
size_t signing_key_data_length = 0;
size_t signing_key_iv_length = 0;
for (const auto& key_container : license.key()) {
if (key_container.type() != KeyContainer::SIGNING) continue;
// To maintain backwards compatibility, in the case of multiple
// signing keys, use the last one found.
signing_key_data_length =
std::min(kLicenseMacKeySize, key_container.key().size());
signing_key_iv_length = key_container.iv().size();
}
if (license.policy().can_renew() ||
(!mac_key_iv.empty() || !mac_keys.empty())) {
if (mac_key_iv.size() != KEY_IV_SIZE ||
mac_keys.size() != kLicenseMacKeySize) {
(signing_key_data_length != 0 || signing_key_iv_length != 0)) {
if (signing_key_iv_length != KEY_IV_SIZE ||
signing_key_data_length != kLicenseMacKeySize) {
LOGE(
"MAC key/IV size error: expected = %zu/%zu, "
"actual = %zu/%zu (key/iv)",
kLicenseMacKeySize, KEY_IV_SIZE, mac_keys.size(), mac_key_iv.size());
kLicenseMacKeySize, KEY_IV_SIZE, signing_key_data_length,
signing_key_iv_length);
return CdmResponseType(KEY_SIZE_ERROR_1);
}
}
@@ -651,20 +658,17 @@ CdmResponseType CdmLicense::HandleKeyResponse(
crypto_session_->UseSecondaryKey(signed_response.using_secondary_key());
if (status != NO_ERROR) return status;
CdmResponseType resp(NO_CONTENT_KEY);
if (kLicenseKeyTypeEntitlement == key_type) {
resp = HandleEntitlementKeyResponse(
return HandleEntitlementKeyResponse(
is_restore, signed_response.session_key(), signed_message, core_message,
signature, license_keys, license);
} else if (kLicenseKeyTypeContent == key_type) {
resp = HandleContentKeyResponse(is_restore, signed_response.session_key(),
signed_message, core_message, signature,
license_keys, license);
}
return resp;
return HandleContentKeyResponse(is_restore, signed_response.session_key(),
signed_message, core_message, signature,
license_keys, license);
}
CdmResponseType CdmLicense::HandleKeyUpdateResponse(
CdmResponseType CdmLicense::HandleKeyUpdateResponseInternal(
bool is_renewal, bool is_restore, const CdmKeyResponse& license_response) {
if (!initialized_) {
LOGE("CdmLicense not initialized");
@@ -681,15 +685,13 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
return CdmResponseType(LICENSE_RESPONSE_PARSE_ERROR_2);
}
switch (signed_response.type()) {
case SignedMessage::LICENSE:
break;
case SignedMessage::ERROR_RESPONSE:
return HandleKeyErrorResponse(signed_response);
default:
LOGE("Unrecognized signed message type: type = %d",
static_cast<int>(signed_response.type()));
return CdmResponseType(INVALID_LICENSE_TYPE);
if (signed_response.type() == SignedMessage::ERROR_RESPONSE) {
return HandleKeyErrorResponse(signed_response);
}
if (signed_response.type() != SignedMessage::LICENSE) {
LOGE("Unrecognized signed message type: type = %d",
static_cast<int>(signed_response.type()));
return CdmResponseType(INVALID_LICENSE_TYPE);
}
const std::string& signed_message = signed_response.msg();
@@ -722,35 +724,35 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
}
if (!is_renewal) {
if (!license.id().has_provider_session_token())
return CdmResponseType(KEY_ADDED);
provider_session_token_ = license.id().provider_session_token();
// For non-renewals, the response is assumed to be a release
// response.
if (license.id().has_provider_session_token()) {
provider_session_token_ = license.id().provider_session_token();
}
return CdmResponseType(KEY_ADDED);
}
if (license.policy().has_renewal_server_url() &&
license.policy().renewal_server_url().size() > 0) {
!license.policy().renewal_server_url().empty()) {
renewal_server_url_ = license.policy().renewal_server_url();
}
// If the field is not set, it will default to false.
// If |using_secondary_key| is not set, it will default to false.
CdmResponseType status =
crypto_session_->UseSecondaryKey(signed_response.using_secondary_key());
if (status != NO_ERROR) return status;
status =
crypto_session_->LoadRenewal(signed_message, core_message, signature);
if (status != KEY_ADDED) return status;
if (status == KEY_ADDED) {
policy_engine_->UpdateLicense(license, is_restore);
}
return status;
policy_engine_->UpdateLicense(license, is_restore);
return CdmResponseType(KEY_ADDED);
}
CdmResponseType CdmLicense::HandleEmbeddedKeyData(
const InitializationData& init_data) {
return HandleNewEntitledKeys(init_data.ExtractWrappedKeys());
return HandleNewEntitledKeysInternal(init_data.ExtractWrappedKeys());
}
CdmResponseType CdmLicense::RestoreOfflineLicense(
@@ -794,16 +796,16 @@ CdmResponseType CdmLicense::RestoreOfflineLicense(
}
CdmResponseType status =
HandleKeyResponse(/* is_restore = */ true, license_response);
HandleKeyResponseInternal(/* is_restore = */ true, license_response);
if (status != KEY_ADDED) return status;
if (!license_renewal_response.empty()) {
status = PrepareKeyUpdateReload(cdm_session);
if (status != KEY_MESSAGE && status != NO_ERROR) return status;
status = HandleKeyUpdateResponse(/* is_renewal = */ true,
/* is_restore = */ true,
license_renewal_response);
status = HandleKeyUpdateResponseInternal(/* is_renewal = */ true,
/* is_restore = */ true,
license_renewal_response);
if (status != KEY_ADDED) return status;
}
@@ -926,7 +928,7 @@ CdmResponseType CdmLicense::RestoreLicenseForRelease(
if (!license.id().has_provider_session_token()) {
const CdmResponseType result =
HandleKeyResponse(/* is_restore = */ false, license_response);
HandleKeyResponseInternal(/* is_restore = */ false, license_response);
return result == KEY_ADDED ? CdmResponseType(NO_ERROR) : result;
}
@@ -1095,19 +1097,21 @@ CdmResponseType CdmLicense::HandleContentKeyResponse(
LOGE("No content keys provided");
return CdmResponseType(NO_CONTENT_KEY);
}
const CdmResponseType resp = crypto_session_->LoadLicense(
const CdmResponseType status = crypto_session_->LoadLicense(
protocol_version_ <= video_widevine::VERSION_2_1
? license_request_
: Sha512Hash(license_request_),
session_key, msg, core_message, signature, kLicenseKeyTypeContent);
if (KEY_ADDED == resp) {
content_key_ids_.clear();
for (const CryptoKey& key : license_keys) {
content_key_ids_.insert(key.key_id());
}
policy_engine_->SetLicense(license, is_restore);
if (status != KEY_ADDED) return status;
content_key_ids_.clear();
for (const CryptoKey& key : license_keys) {
// The CdmLicense handles content and operator session keys
// the same.
content_key_ids_.insert(key.key_id());
}
return resp;
policy_engine_->SetLicense(license, is_restore);
return CdmResponseType(KEY_ADDED);
}
CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
@@ -1119,27 +1123,26 @@ CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
LOGE("No entitlement keys provided");
return CdmResponseType(NO_CONTENT_KEY);
}
const CdmResponseType resp = crypto_session_->LoadLicense(
const CdmResponseType status = crypto_session_->LoadLicense(
protocol_version_ <= video_widevine::VERSION_2_1
? license_request_
: Sha512Hash(license_request_),
session_key, msg, core_message, signature, kLicenseKeyTypeEntitlement);
if (KEY_ADDED != resp) {
return resp;
}
if (status != KEY_ADDED) return status;
// Save the entitlement keys for future use to handle key changes,
// and for call to HandleNewEntitledKeys().
// and for call to HandleNewEntitledKeysInternal().
for (const auto& key_container : license.key()) {
if (key_container.type() != KeyContainer::ENTITLEMENT) continue;
entitlement_key_ids_.insert(key_container.id());
}
policy_engine_->SetLicense(license, is_restore);
return HandleNewEntitledKeys(request_entitled_keys_);
// Now load any entitled keys that were in the PSSH provided
// when generated the license request.
return HandleNewEntitledKeysInternal(request_entitled_keys_);
}
CdmResponseType CdmLicense::HandleNewEntitledKeys(
CdmResponseType CdmLicense::HandleNewEntitledKeysInternal(
const std::vector<PsshEntitledKey>& packaged_entitled_keys) {
std::vector<CryptoKey> entitled_keys;
entitled_keys.reserve(packaged_entitled_keys.size());
@@ -1169,9 +1172,9 @@ CdmResponseType CdmLicense::HandleNewEntitledKeys(
entitled_keys.push_back(std::move(entitled_key));
}
const CdmResponseType resp =
const CdmResponseType status =
crypto_session_->LoadEntitledContentKeys(entitled_keys);
if (resp != KEY_ADDED) return resp;
if (status != KEY_ADDED) return status;
// Loaded entitled keys can be accessed like regular content keys
// by the license.
@@ -1201,5 +1204,4 @@ bool CdmLicense::SetTypeAndId(CdmLicenseType license_type,
content_id->set_request_id(request_id);
return true;
}
} // namespace wvcdm

View File

@@ -1192,8 +1192,22 @@ message ClientIdentification {
}
message ClientCredentials {
// Deprecated. Use credential_type instead.
optional TokenType type = 1 [default = KEYBOX];
optional bytes token = 2;
// Additional types of credentials that may be present in the client
// identification.
enum CredentialType {
CREDENTIAL_TYPE_UNKNOWN = 0;
// CBOR format used by the Provisioning 4.0 phase 3 uploading model.
CREDENTIAL_TYPE_BCC_SIGNATURE_CBOR = 1;
// PKCS7 format, used by Provisioning 4.0 signing model.
CREDENTIAL_TYPE_BCC_SIGNATURE_PKCS7 = 2;
}
// The type of the token.
optional CredentialType credential_type = 3;
}
// Type of factory-provisioned device root of trust. Optional.

View File

@@ -224,6 +224,13 @@ OEMCryptoResult OEMCrypto_GetBCCType(RequestedSecurityLevel level,
(void)level;
return ::OEMCrypto_GetBCCType(bcc_type);
}
OEMCryptoResult OEMCrypto_GetBCCSignatureType(
RequestedSecurityLevel level,
OEMCrypto_BCCSignatureType* bcc_signature_type) {
(void)level;
return ::OEMCrypto_GetBCCSignatureType(bcc_signature_type);
}
} // namespace wvcdm
// Provide default implementation of L3-only functions. WEAK allows them to be

View File

@@ -889,6 +889,8 @@ const char* CdmResponseEnumToString(CdmResponseEnum cdm_response_enum) {
return "SESSION_NOT_FOUND_GENERIC_CRYPTO";
case SESSION_NOT_FOUND_24:
return "SESSION_NOT_FOUND_24";
case GET_BCC_SIGNATURE_TYPE_ERROR:
return "GET_BCC_SIGNATURE_TYPE_ERROR";
}
return UnknownValueRep(cdm_response_enum);
}
@@ -1075,4 +1077,18 @@ const char* OemCryptoResultToString(OEMCryptoResult result) {
return UnknownValueRep(result);
}
const char* OemCryptoBccSignatureTypeToString(OEMCrypto_BCCSignatureType type) {
switch (type) {
case OEMCrypto_BCCSigType_Unknown:
return "Unknown";
case OEMCrypto_BCCSigType_CBOR:
return "CBOR";
case OEMCrypto_BCCSigType_PKCS7:
return "PKCS7";
case OEMCrypto_BCCSigType_Keybox:
return "Keybox";
}
return UnknownValueRep(type);
}
} // namespace wvcdm