|
|
|
|
@@ -50,6 +50,9 @@ constexpr char kNoSandboxId[] = "";
|
|
|
|
|
const int64_t kPolicyTimerDurationMilliseconds = 5000;
|
|
|
|
|
void* const kPolicyTimerContext = nullptr;
|
|
|
|
|
|
|
|
|
|
const std::string kEmptyAuthority;
|
|
|
|
|
const std::string kCastAuthority = "cast.google.com";
|
|
|
|
|
|
|
|
|
|
struct HostType {
|
|
|
|
|
Cdm::IStorage* storage;
|
|
|
|
|
Cdm::IClock* clock;
|
|
|
|
|
@@ -228,6 +231,10 @@ class CdmImpl final : public Cdm, public WvCdmEventListener {
|
|
|
|
|
Status getStatusForHdcpVersion(HdcpVersion hdcp,
|
|
|
|
|
KeyStatus* key_status) override;
|
|
|
|
|
|
|
|
|
|
Status initDataContainsEmbeddedKeys(InitDataType init_data_type,
|
|
|
|
|
const std::string& init_data,
|
|
|
|
|
bool* contains_keys) override;
|
|
|
|
|
|
|
|
|
|
Status createSession(SessionType session_type,
|
|
|
|
|
std::string* session_id) override;
|
|
|
|
|
|
|
|
|
|
@@ -301,6 +308,15 @@ class CdmImpl final : public Cdm, public WvCdmEventListener {
|
|
|
|
|
|
|
|
|
|
Status getMetrics(std::string* serialized_metrics) override;
|
|
|
|
|
|
|
|
|
|
Status getCastProvisioningRequest(std::string* request) override;
|
|
|
|
|
|
|
|
|
|
Status handleCastProvisioningResponse(const std::string& response,
|
|
|
|
|
std::string* cert,
|
|
|
|
|
std::string* wrapped_key) override;
|
|
|
|
|
|
|
|
|
|
Status castSign(const std::string& wrapped_key, const std::string& message,
|
|
|
|
|
std::string* signature) override;
|
|
|
|
|
|
|
|
|
|
// ITimerClient:
|
|
|
|
|
void onTimerExpired(void* context) override;
|
|
|
|
|
|
|
|
|
|
@@ -322,6 +338,14 @@ class CdmImpl final : public Cdm, public WvCdmEventListener {
|
|
|
|
|
GenericSigningAlgorithmType algorithm);
|
|
|
|
|
Cdm::Status ConvertHdcpLevel(const std::string& query_value,
|
|
|
|
|
Cdm::HdcpVersion* result);
|
|
|
|
|
Status getProvisioningRequest(CdmCertificateType cert_type,
|
|
|
|
|
const std::string& authority,
|
|
|
|
|
std::string* request);
|
|
|
|
|
Status handleProvisioningResponse(const std::string& response,
|
|
|
|
|
std::string* cert,
|
|
|
|
|
std::string* wrapped_key);
|
|
|
|
|
|
|
|
|
|
Cdm::Status ConvertStatusCode(CdmResponseType inner_error) const;
|
|
|
|
|
|
|
|
|
|
IEventListener* listener_;
|
|
|
|
|
bool policy_timer_enabled_;
|
|
|
|
|
@@ -430,15 +454,9 @@ Cdm::Status CdmImpl::getRobustnessLevel(RobustnessLevel* level) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string level_string;
|
|
|
|
|
const CdmResponseType result = cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_SECURITY_LEVEL, &level_string);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_SECURITY_LEVEL, &level_string));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
if (level_string == QUERY_VALUE_SECURITY_LEVEL_L1) {
|
|
|
|
|
*level = kL1;
|
|
|
|
|
@@ -461,15 +479,9 @@ Cdm::Status CdmImpl::getSystemId(uint32_t* id) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string id_string;
|
|
|
|
|
const CdmResponseType result =
|
|
|
|
|
cdm_engine_->QueryStatus(kLevelDefault, QUERY_KEY_SYSTEM_ID, &id_string);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_SYSTEM_ID, &id_string));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
*id = static_cast<uint32_t>(std::stoul(id_string));
|
|
|
|
|
return kSuccess;
|
|
|
|
|
@@ -482,15 +494,9 @@ Cdm::Status CdmImpl::getResourceRatingTier(uint32_t* tier) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string tier_string;
|
|
|
|
|
const CdmResponseType result = cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_RESOURCE_RATING_TIER, &tier_string);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_RESOURCE_RATING_TIER, &tier_string));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
const uint32_t parsed_tier = static_cast<uint32_t>(std::stoul(tier_string));
|
|
|
|
|
if (parsed_tier <= 0) {
|
|
|
|
|
@@ -507,18 +513,8 @@ Cdm::Status CdmImpl::getOemCryptoBuildInfo(std::string* build_info) {
|
|
|
|
|
LOGE("Missing build_info parameter to receive build info.");
|
|
|
|
|
return kTypeError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmResponseType result = cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, build_info);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, build_info));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::ProvisioningStatus CdmImpl::getProvisioningStatus() {
|
|
|
|
|
@@ -540,51 +536,18 @@ Cdm::ProvisioningStatus CdmImpl::getProvisioningStatus() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::getProvisioningRequest(std::string* request) {
|
|
|
|
|
std::string empty_authority;
|
|
|
|
|
std::string ignored_base_url;
|
|
|
|
|
CdmResponseType result = cdm_engine_->GetProvisioningRequest(
|
|
|
|
|
kCertificateWidevine, empty_authority, provisioning_service_certificate_,
|
|
|
|
|
kLevelDefault, request, &ignored_base_url);
|
|
|
|
|
if (result == CERT_PROVISIONING_NONCE_GENERATION_ERROR) {
|
|
|
|
|
LOGE("Nonce quota exceeded");
|
|
|
|
|
return kResourceContention;
|
|
|
|
|
} else if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return getProvisioningRequest(kCertificateWidevine, kEmptyAuthority, request);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::handleProvisioningResponse(const std::string& response) {
|
|
|
|
|
std::string ignored_cert;
|
|
|
|
|
std::string ignored_wrapped_key;
|
|
|
|
|
|
|
|
|
|
CdmResponseType result = cdm_engine_->HandleProvisioningResponse(
|
|
|
|
|
response, kLevelDefault, &ignored_cert, &ignored_wrapped_key);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return handleProvisioningResponse(response, &ignored_cert,
|
|
|
|
|
&ignored_wrapped_key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::removeProvisioning() {
|
|
|
|
|
CdmResponseType result = cdm_engine_->Unprovision(kSecurityLevelL1);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->Unprovision(kSecurityLevelL1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::listStoredLicenses(std::vector<std::string>* key_set_ids) {
|
|
|
|
|
@@ -592,16 +555,8 @@ Cdm::Status CdmImpl::listStoredLicenses(std::vector<std::string>* key_set_ids) {
|
|
|
|
|
LOGE("Missing vector parameter to receive key_set_ids.");
|
|
|
|
|
return kTypeError;
|
|
|
|
|
}
|
|
|
|
|
CdmResponseType result =
|
|
|
|
|
cdm_engine_->ListStoredLicenses(kSecurityLevelL1, key_set_ids);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->ListStoredLicenses(
|
|
|
|
|
kSecurityLevelL1, key_set_ids));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::listUsageRecords(std::vector<std::string>* ksids) {
|
|
|
|
|
@@ -609,51 +564,26 @@ Cdm::Status CdmImpl::listUsageRecords(std::vector<std::string>* ksids) {
|
|
|
|
|
LOGE("Missing vector parameter to receive KSIDs.");
|
|
|
|
|
return kTypeError;
|
|
|
|
|
}
|
|
|
|
|
CdmResponseType result = cdm_engine_->ListUsageIds(
|
|
|
|
|
property_set_.app_id(), kSecurityLevelL1, ksids, nullptr);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->ListUsageIds(
|
|
|
|
|
property_set_.app_id(), kSecurityLevelL1, ksids, nullptr));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::deleteUsageRecord(const std::string& key_set_id) {
|
|
|
|
|
CdmResponseType result = cdm_engine_->DeleteUsageRecord(
|
|
|
|
|
property_set_.app_id(), kSecurityLevelL1, key_set_id);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->DeleteUsageRecord(
|
|
|
|
|
property_set_.app_id(), kSecurityLevelL1, key_set_id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::deleteAllUsageRecords() {
|
|
|
|
|
CdmResponseType result =
|
|
|
|
|
cdm_engine_->RemoveAllUsageInfo(property_set_.app_id(), kSecurityLevelL1);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->RemoveAllUsageInfo(
|
|
|
|
|
property_set_.app_id(), kSecurityLevelL1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::getStatusForHdcpVersion(Cdm::HdcpVersion hdcp,
|
|
|
|
|
Cdm::KeyStatus* key_status) {
|
|
|
|
|
std::string query_value;
|
|
|
|
|
if (cdm_engine_->QueryStatus(kLevelDefault, QUERY_KEY_MAX_HDCP_LEVEL,
|
|
|
|
|
&query_value) != NO_ERROR) {
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
auto result = ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
kLevelDefault, QUERY_KEY_MAX_HDCP_LEVEL, &query_value));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
if (query_value == QUERY_VALUE_HDCP_NONE ||
|
|
|
|
|
query_value == QUERY_VALUE_HDCP_LEVEL_UNKNOWN) {
|
|
|
|
|
@@ -662,15 +592,46 @@ Cdm::Status CdmImpl::getStatusForHdcpVersion(Cdm::HdcpVersion hdcp,
|
|
|
|
|
*key_status = Cdm::kUsable;
|
|
|
|
|
} else {
|
|
|
|
|
Cdm::HdcpVersion max_hdcp;
|
|
|
|
|
if (ConvertHdcpLevel(query_value, &max_hdcp) != kSuccess) {
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
result = ConvertHdcpLevel(query_value, &max_hdcp);
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
*key_status = (hdcp <= max_hdcp ? Cdm::kUsable : Cdm::kOutputRestricted);
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::initDataContainsEmbeddedKeys(InitDataType init_data_type,
|
|
|
|
|
const std::string& init_data,
|
|
|
|
|
bool* contains_keys) {
|
|
|
|
|
if (contains_keys == nullptr) {
|
|
|
|
|
LOGE("Missing pointer to result variable.");
|
|
|
|
|
return kTypeError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (init_data_type != kCenc) {
|
|
|
|
|
// Only PSSHs can contain embedded keys.
|
|
|
|
|
*contains_keys = false;
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string oec_version;
|
|
|
|
|
auto result = ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
wvcdm::kLevelDefault, QUERY_KEY_OEMCRYPTO_API_VERSION, &oec_version));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
InitializationData init_data_obj(CENC_INIT_DATA_FORMAT, init_data,
|
|
|
|
|
oec_version);
|
|
|
|
|
if (init_data_obj.IsEmpty()) {
|
|
|
|
|
// Note that InitializationData's idea of "empty" includes "failed to find
|
|
|
|
|
// and parse a Widevine PSSH".
|
|
|
|
|
LOGE("Failed to parse init data. It may not contain a Widevine PSSH.");
|
|
|
|
|
return kNotSupported;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*contains_keys = init_data_obj.contains_entitled_keys();
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::createSession(SessionType session_type,
|
|
|
|
|
std::string* session_id) {
|
|
|
|
|
if (session_id == nullptr) {
|
|
|
|
|
@@ -691,25 +652,18 @@ Cdm::Status CdmImpl::createSession(SessionType session_type,
|
|
|
|
|
return kNotSupported;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmResponseType result = cdm_engine_->OpenSession(
|
|
|
|
|
"com.widevine.alpha", &property_set_, this, session_id);
|
|
|
|
|
switch (result) {
|
|
|
|
|
case NO_ERROR:
|
|
|
|
|
sessions_[*session_id].type = session_type;
|
|
|
|
|
return kSuccess;
|
|
|
|
|
case NEED_PROVISIONING:
|
|
|
|
|
// The Session ID may have been set by the CDM Engine despite this
|
|
|
|
|
// failure. We clear the ID here to ensure that we don't communicate a
|
|
|
|
|
// misleading ID to the application.
|
|
|
|
|
session_id->clear();
|
|
|
|
|
return kNeedsDeviceCertificate;
|
|
|
|
|
case SYSTEM_INVALIDATED_ERROR:
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
default:
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->OpenSession(
|
|
|
|
|
"com.widevine.alpha", &property_set_, this, session_id));
|
|
|
|
|
if (result != kSuccess) {
|
|
|
|
|
// The Session ID may have been set by the CDM Engine despite this
|
|
|
|
|
// failure. We clear the ID here to ensure that we don't communicate a
|
|
|
|
|
// misleading ID to the application.
|
|
|
|
|
session_id->clear();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sessions_[*session_id].type = session_type;
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
|
|
|
|
@@ -767,11 +721,10 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string oec_version;
|
|
|
|
|
if (cdm_engine_->QueryStatus(wvcdm::kLevelDefault,
|
|
|
|
|
QUERY_KEY_OEMCRYPTO_API_VERSION,
|
|
|
|
|
&oec_version) != NO_ERROR) {
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
auto result = ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
wvcdm::kLevelDefault, QUERY_KEY_OEMCRYPTO_API_VERSION, &oec_version));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
InitializationData init_data_obj(init_data_type_name, init_data, oec_version);
|
|
|
|
|
if (init_data_obj.IsEmpty()) {
|
|
|
|
|
// Note that InitializationData's idea of "empty" includes "failed to find
|
|
|
|
|
@@ -782,31 +735,10 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmKeyRequest key_request;
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result = cdm_engine_->GenerateKeyRequest(
|
|
|
|
|
result = ConvertStatusCode(cdm_engine_->GenerateKeyRequest(
|
|
|
|
|
session_id, session_id, init_data_obj, license_type, app_parameters_,
|
|
|
|
|
&key_request);
|
|
|
|
|
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
} else if (result == LICENSE_REQUEST_NONCE_GENERATION_ERROR) {
|
|
|
|
|
LOGE("Nonce quota exceeded");
|
|
|
|
|
return kResourceContention;
|
|
|
|
|
} else if (result == NEED_PROVISIONING) {
|
|
|
|
|
LOGE("Device not provisioned");
|
|
|
|
|
return kNeedsDeviceCertificate;
|
|
|
|
|
} else if (result == PRIVACY_MODE_ERROR_1 || result == PRIVACY_MODE_ERROR_2 ||
|
|
|
|
|
result == PRIVACY_MODE_ERROR_3) {
|
|
|
|
|
LOGE("No licensing service certificate installed");
|
|
|
|
|
return kNeedsServiceCertificate;
|
|
|
|
|
} else if (result != KEY_MESSAGE) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
&key_request));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
sessions_[session_id].callable = true;
|
|
|
|
|
assert(key_request.type == kKeyRequestTypeInitial);
|
|
|
|
|
@@ -827,20 +759,9 @@ Cdm::Status CdmImpl::load(const std::string& session_id) {
|
|
|
|
|
return kQuotaExceeded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmResponseType result = cdm_engine_->OpenSession(
|
|
|
|
|
"com.widevine.alpha", &property_set_, session_id, this);
|
|
|
|
|
switch (result) {
|
|
|
|
|
case NO_ERROR:
|
|
|
|
|
break;
|
|
|
|
|
case SYSTEM_INVALIDATED_ERROR:
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
case NEED_PROVISIONING:
|
|
|
|
|
return kNeedsDeviceCertificate;
|
|
|
|
|
default:
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
auto result = ConvertStatusCode(cdm_engine_->OpenSession(
|
|
|
|
|
"com.widevine.alpha", &property_set_, session_id, this));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
DeviceFiles f(&file_system_);
|
|
|
|
|
if (!f.Init(kSecurityLevelUnknown)) {
|
|
|
|
|
@@ -851,20 +772,11 @@ Cdm::Status CdmImpl::load(const std::string& session_id) {
|
|
|
|
|
if (!f.LicenseExists(session_id)) {
|
|
|
|
|
// This might be a usage record session which needs to be loaded.
|
|
|
|
|
CdmKeyMessage ignored_release_message;
|
|
|
|
|
result =
|
|
|
|
|
cdm_engine_->LoadUsageSession(session_id, &ignored_release_message);
|
|
|
|
|
if (result != KEY_MESSAGE) {
|
|
|
|
|
result = ConvertStatusCode(cdm_engine_->LoadUsageSession(
|
|
|
|
|
session_id, &ignored_release_message));
|
|
|
|
|
if (result != kSuccess) {
|
|
|
|
|
cdm_engine_->CloseSession(session_id);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == LOAD_USAGE_INFO_MISSING) {
|
|
|
|
|
LOGE("Unable to load license: %s", session_id.c_str());
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
} else {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sessions_[session_id].type = kPersistentUsageRecord;
|
|
|
|
|
@@ -872,17 +784,8 @@ Cdm::Status CdmImpl::load(const std::string& session_id) {
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = cdm_engine_->RestoreKey(session_id, session_id);
|
|
|
|
|
if (result == GET_RELEASED_LICENSE_ERROR) {
|
|
|
|
|
// This was partially removed already.
|
|
|
|
|
// The EME spec states that we should be able to load it, but not use it.
|
|
|
|
|
} else if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != KEY_ADDED) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
result = ConvertStatusCode(cdm_engine_->RestoreKey(session_id, session_id));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
if (!policy_timer_enabled_) {
|
|
|
|
|
policy_timer_enabled_ = true;
|
|
|
|
|
@@ -916,31 +819,14 @@ Cdm::Status CdmImpl::update(const std::string& session_id,
|
|
|
|
|
// AddKey(), it will internally delegate to RenewKey().
|
|
|
|
|
CdmKeySetId key_set_id = session_id;
|
|
|
|
|
CdmLicenseType license_type = {}; // Required for AddKey. Unused otherwise.
|
|
|
|
|
const CdmResponseType result =
|
|
|
|
|
const CdmResponseType inner_error =
|
|
|
|
|
cdm_engine_->AddKey(session_id, response, &license_type, &key_set_id);
|
|
|
|
|
|
|
|
|
|
// result should only be NEED_KEY after server certificate provisioning, which
|
|
|
|
|
// should no longer happen in this version of the CDM.
|
|
|
|
|
assert(result != NEED_KEY);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
} else if (result == OFFLINE_LICENSE_PROHIBITED) {
|
|
|
|
|
LOGE("A temporary session cannot be used for a persistent license.");
|
|
|
|
|
return kRangeError;
|
|
|
|
|
} else if (result == STORAGE_PROHIBITED) {
|
|
|
|
|
LOGE("A temporary session cannot be used for a persistent usage records.");
|
|
|
|
|
return kRangeError;
|
|
|
|
|
} else if (result == NEED_PROVISIONING) {
|
|
|
|
|
LOGE("The device needs to reprovision.");
|
|
|
|
|
return kNeedsDeviceCertificate;
|
|
|
|
|
} else if (result != KEY_ADDED) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
assert(inner_error != NEED_KEY);
|
|
|
|
|
const auto result = ConvertStatusCode(inner_error);
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
if (!policy_timer_enabled_) {
|
|
|
|
|
policy_timer_enabled_ = true;
|
|
|
|
|
@@ -970,11 +856,10 @@ Cdm::Status CdmImpl::loadEmbeddedKeys(const std::string& session_id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string oec_version;
|
|
|
|
|
if (cdm_engine_->QueryStatus(wvcdm::kLevelDefault,
|
|
|
|
|
QUERY_KEY_OEMCRYPTO_API_VERSION,
|
|
|
|
|
&oec_version) != NO_ERROR) {
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
auto result = ConvertStatusCode(cdm_engine_->QueryStatus(
|
|
|
|
|
wvcdm::kLevelDefault, QUERY_KEY_OEMCRYPTO_API_VERSION, &oec_version));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
InitializationData init_data_obj(CENC_INIT_DATA_FORMAT, init_data,
|
|
|
|
|
oec_version);
|
|
|
|
|
if (init_data_obj.IsEmpty()) {
|
|
|
|
|
@@ -986,25 +871,9 @@ Cdm::Status CdmImpl::loadEmbeddedKeys(const std::string& session_id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmKeyRequest key_request;
|
|
|
|
|
const CdmResponseType result = cdm_engine_->GenerateKeyRequest(
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->GenerateKeyRequest(
|
|
|
|
|
session_id, session_id, init_data_obj, kLicenseTypeEmbeddedKeyData,
|
|
|
|
|
app_parameters_, &key_request);
|
|
|
|
|
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
} else if (result == LICENSE_REQUEST_NONCE_GENERATION_ERROR) {
|
|
|
|
|
LOGE("Nonce quota exceeded");
|
|
|
|
|
return kResourceContention;
|
|
|
|
|
} else if (result != KEY_ADDED) {
|
|
|
|
|
LOGE("Unexpected Failure: GenerateKeyRequest() returned %d",
|
|
|
|
|
static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
return kSuccess;
|
|
|
|
|
app_parameters_, &key_request));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::getExpiration(const std::string& session_id,
|
|
|
|
|
@@ -1050,24 +919,9 @@ Cdm::Status CdmImpl::getKeyAllowedUsages(const std::string& session_id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmKeyAllowedUsage usage_for_key;
|
|
|
|
|
CdmResponseType result =
|
|
|
|
|
cdm_engine_->QueryKeyAllowedUsage(session_id, key_id, &usage_for_key);
|
|
|
|
|
if (result != NO_ERROR) {
|
|
|
|
|
// TODO(b/114435278): There are multiple KEY_NOT_FOUND_* errors that should
|
|
|
|
|
// probably all turn into kNoKey. Here, and below, and everywhere.
|
|
|
|
|
if (result == KEY_NOT_FOUND_1) {
|
|
|
|
|
return kNoKey;
|
|
|
|
|
} else if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
} else {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->QueryKeyAllowedUsage(
|
|
|
|
|
session_id, key_id, &usage_for_key));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
*usage_flags = KeyAllowedFlags(usage_for_key);
|
|
|
|
|
return kSuccess;
|
|
|
|
|
@@ -1081,24 +935,9 @@ Cdm::Status CdmImpl::getKeyAllowedUsages(const std::string& key_id,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmKeyAllowedUsage usage_for_key;
|
|
|
|
|
const CdmResponseType result =
|
|
|
|
|
cdm_engine_->QueryKeyAllowedUsage(key_id, &usage_for_key);
|
|
|
|
|
if (result != NO_ERROR) {
|
|
|
|
|
if (result == KEY_NOT_FOUND_1 || result == KEY_NOT_FOUND_2) {
|
|
|
|
|
return kNoKey;
|
|
|
|
|
} else if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
} else if (result == KEY_CONFLICT_1) {
|
|
|
|
|
return kTypeError;
|
|
|
|
|
} else {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->QueryKeyAllowedUsage(
|
|
|
|
|
key_id, &usage_for_key));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
*usage_flags = KeyAllowedFlags(usage_for_key);
|
|
|
|
|
return kSuccess;
|
|
|
|
|
@@ -1146,16 +985,11 @@ Cdm::Status CdmImpl::close(const std::string& session_id) {
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result = cdm_engine_->CloseSession(session_id);
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->CloseSession(session_id));
|
|
|
|
|
if (result == kSuccess) {
|
|
|
|
|
sessions_.erase(session_id);
|
|
|
|
|
}
|
|
|
|
|
sessions_.erase(session_id);
|
|
|
|
|
return kSuccess;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::remove(const std::string& session_id) {
|
|
|
|
|
@@ -1185,23 +1019,12 @@ Cdm::Status CdmImpl::remove(const std::string& session_id) {
|
|
|
|
|
it->second = kReleased;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result = cdm_engine_->GenerateKeyRequest(
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->GenerateKeyRequest(
|
|
|
|
|
session_id, session_id, empty_initialization_data, kLicenseTypeRelease,
|
|
|
|
|
app_parameters_, &key_request);
|
|
|
|
|
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
} else if (result == LICENSE_REQUEST_NONCE_GENERATION_ERROR) {
|
|
|
|
|
LOGE("Nonce quota exceeded");
|
|
|
|
|
return kResourceContention;
|
|
|
|
|
} else if (result != KEY_MESSAGE) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
app_parameters_, &key_request));
|
|
|
|
|
if (result != kSuccess) {
|
|
|
|
|
cdm_engine_->CloseSession(session_id);
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOGI("A license release has been generated.");
|
|
|
|
|
@@ -1226,18 +1049,8 @@ Cdm::Status CdmImpl::forceRemove(const std::string& session_id) {
|
|
|
|
|
return kRangeError;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result = cdm_engine_->RemoveLicense(session_id);
|
|
|
|
|
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
} else if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
} else if (result != NO_ERROR) {
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
const auto result = ConvertStatusCode(cdm_engine_->RemoveLicense(session_id));
|
|
|
|
|
if (result != kSuccess) return result;
|
|
|
|
|
|
|
|
|
|
sessions_.erase(session_id);
|
|
|
|
|
cdm_engine_->CloseSession(session_id);
|
|
|
|
|
@@ -1330,41 +1143,10 @@ Cdm::Status CdmImpl::decrypt(const std::string& session_id,
|
|
|
|
|
return cdm_sample;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result =
|
|
|
|
|
cdm_engine_->DecryptV16(session_id, parameters);
|
|
|
|
|
|
|
|
|
|
if (result == NO_ERROR) {
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result == OUTPUT_TOO_LARGE_ERROR) {
|
|
|
|
|
LOGE("Output too large");
|
|
|
|
|
return kOutputTooLarge;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result == NEED_KEY || result == KEY_NOT_FOUND_3 ||
|
|
|
|
|
result == SESSION_NOT_FOUND_FOR_DECRYPT) {
|
|
|
|
|
LOGE("Key not available.");
|
|
|
|
|
return kNoKey;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result == INSUFFICIENT_OUTPUT_PROTECTION) {
|
|
|
|
|
LOGE("Key usage blocked due to HDCP or display resolution constraints.");
|
|
|
|
|
return kKeyUsageBlockedByPolicy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LOGE("Decrypt error: %d", static_cast<int>(result));
|
|
|
|
|
return kDecryptError;
|
|
|
|
|
const auto result =
|
|
|
|
|
ConvertStatusCode(cdm_engine_->DecryptV16(session_id, parameters));
|
|
|
|
|
if (result == kUnexpectedError) return kDecryptError;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::genericEncrypt(const std::string& session_id,
|
|
|
|
|
@@ -1381,33 +1163,8 @@ Cdm::Status CdmImpl::genericEncrypt(const std::string& session_id,
|
|
|
|
|
return kNotSupported;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CdmResponseType result = cdm_engine_->GenericEncrypt(
|
|
|
|
|
session_id, in_buffer, key_id, iv, cdm_algorithm, out_buffer);
|
|
|
|
|
if (result == NO_ERROR) {
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == OUTPUT_TOO_LARGE_ERROR) {
|
|
|
|
|
LOGE("Output too large");
|
|
|
|
|
return kOutputTooLarge;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_NOT_FOUND_13) {
|
|
|
|
|
LOGE("No such session: %s", session_id.c_str());
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
}
|
|
|
|
|
if (result == KEY_NOT_FOUND_3 || result == NEED_KEY) {
|
|
|
|
|
LOGE("Key Error: %s", session_id.c_str());
|
|
|
|
|
return kNoKey;
|
|
|
|
|
}
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->GenericEncrypt(
|
|
|
|
|
session_id, in_buffer, key_id, iv, cdm_algorithm, out_buffer));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::genericDecrypt(const std::string& session_id,
|
|
|
|
|
@@ -1424,33 +1181,8 @@ Cdm::Status CdmImpl::genericDecrypt(const std::string& session_id,
|
|
|
|
|
return kNotSupported;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result = cdm_engine_->GenericDecrypt(
|
|
|
|
|
session_id, in_buffer, key_id, iv, cdm_algorithm, out_buffer);
|
|
|
|
|
if (result == NO_ERROR) {
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == OUTPUT_TOO_LARGE_ERROR) {
|
|
|
|
|
LOGE("Output too large");
|
|
|
|
|
return kOutputTooLarge;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_NOT_FOUND_14) {
|
|
|
|
|
LOGE("No such session: %s", session_id.c_str());
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
}
|
|
|
|
|
if (result == KEY_NOT_FOUND_4 || result == NEED_KEY) {
|
|
|
|
|
LOGE("Key Error: %s", session_id.c_str());
|
|
|
|
|
return kNoKey;
|
|
|
|
|
}
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->GenericDecrypt(
|
|
|
|
|
session_id, in_buffer, key_id, iv, cdm_algorithm, out_buffer));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::genericSign(const std::string& session_id,
|
|
|
|
|
@@ -1464,29 +1196,8 @@ Cdm::Status CdmImpl::genericSign(const std::string& session_id,
|
|
|
|
|
return kNotSupported;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result = cdm_engine_->GenericSign(
|
|
|
|
|
session_id, message, key_id, cdm_algorithm, signature);
|
|
|
|
|
if (result == NO_ERROR) {
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_NOT_FOUND_15) {
|
|
|
|
|
LOGE("No such session: %s", session_id.c_str());
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
}
|
|
|
|
|
if (result == KEY_NOT_FOUND_5 || result == NEED_KEY) {
|
|
|
|
|
LOGE("Key Error: %s", session_id.c_str());
|
|
|
|
|
return kNoKey;
|
|
|
|
|
}
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->GenericSign(
|
|
|
|
|
session_id, message, key_id, cdm_algorithm, signature));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::genericVerify(const std::string& session_id,
|
|
|
|
|
@@ -1500,29 +1211,8 @@ Cdm::Status CdmImpl::genericVerify(const std::string& session_id,
|
|
|
|
|
return kNotSupported;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const CdmResponseType result = cdm_engine_->GenericVerify(
|
|
|
|
|
session_id, message, key_id, cdm_algorithm, signature);
|
|
|
|
|
if (result == NO_ERROR) {
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
if (result == SYSTEM_INVALIDATED_ERROR) {
|
|
|
|
|
LOGE("System invalidated");
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_LOST_STATE_ERROR) {
|
|
|
|
|
LOGE("Session invalidated");
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
}
|
|
|
|
|
if (result == SESSION_NOT_FOUND_16) {
|
|
|
|
|
LOGE("No such session: %s", session_id.c_str());
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
}
|
|
|
|
|
if (result == KEY_NOT_FOUND_6 || result == NEED_KEY) {
|
|
|
|
|
LOGE("Key Error: %s", session_id.c_str());
|
|
|
|
|
return kNoKey;
|
|
|
|
|
}
|
|
|
|
|
LOGE("Unexpected error %d", static_cast<int>(result));
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->GenericVerify(
|
|
|
|
|
session_id, message, key_id, cdm_algorithm, signature));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::setVideoResolution(const std::string& session_id,
|
|
|
|
|
@@ -1555,6 +1245,23 @@ Cdm::Status CdmImpl::getMetrics(std::string* serialized_metrics) {
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::getCastProvisioningRequest(std::string* request) {
|
|
|
|
|
return getProvisioningRequest(kCertificateX509, kCastAuthority, request);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::handleCastProvisioningResponse(const std::string& response,
|
|
|
|
|
std::string* cert,
|
|
|
|
|
std::string* wrapped_key) {
|
|
|
|
|
return handleProvisioningResponse(response, cert, wrapped_key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::castSign(const std::string& wrapped_key,
|
|
|
|
|
const std::string& message,
|
|
|
|
|
std::string* signature) {
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->SignRsa(wrapped_key, message, signature,
|
|
|
|
|
kSign_PKCS1_Block1));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CdmImpl::onTimerExpired(void* context) {
|
|
|
|
|
if (context == kPolicyTimerContext) {
|
|
|
|
|
if (policy_timer_enabled_) {
|
|
|
|
|
@@ -1693,6 +1400,116 @@ Cdm::Status CdmImpl::ConvertHdcpLevel(const std::string& query_value,
|
|
|
|
|
return kSuccess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::getProvisioningRequest(CdmCertificateType cert_type,
|
|
|
|
|
const std::string& authority,
|
|
|
|
|
std::string* request) {
|
|
|
|
|
std::string ignored_base_url;
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->GetProvisioningRequest(
|
|
|
|
|
cert_type, authority, provisioning_service_certificate_, kLevelDefault,
|
|
|
|
|
request, &ignored_base_url));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::handleProvisioningResponse(const std::string& response,
|
|
|
|
|
std::string* cert,
|
|
|
|
|
std::string* wrapped_key) {
|
|
|
|
|
return ConvertStatusCode(cdm_engine_->HandleProvisioningResponse(
|
|
|
|
|
response, kLevelDefault, cert, wrapped_key));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Cdm::Status CdmImpl::ConvertStatusCode(CdmResponseType inner_error) const {
|
|
|
|
|
switch (inner_error) {
|
|
|
|
|
case GET_RELEASED_LICENSE_ERROR:
|
|
|
|
|
// This was partially removed already.
|
|
|
|
|
// The EME spec states that we should be able to load it, but not use it.
|
|
|
|
|
case KEY_ADDED:
|
|
|
|
|
case KEY_MESSAGE:
|
|
|
|
|
case NO_ERROR:
|
|
|
|
|
return kSuccess;
|
|
|
|
|
|
|
|
|
|
case KEY_CONFLICT_1:
|
|
|
|
|
LOGE("Multiple sessions contain given key (inner_error=%d)", inner_error);
|
|
|
|
|
return kTypeError;
|
|
|
|
|
|
|
|
|
|
case NEED_PROVISIONING:
|
|
|
|
|
LOGE("Device not provisioned (inner_error=%d)", inner_error);
|
|
|
|
|
return kNeedsDeviceCertificate;
|
|
|
|
|
case LOAD_USAGE_INFO_MISSING:
|
|
|
|
|
LOGE("Unable to load license (inner_error=%d)", inner_error);
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
case SESSION_NOT_FOUND_1:
|
|
|
|
|
case SESSION_NOT_FOUND_2:
|
|
|
|
|
case SESSION_NOT_FOUND_3:
|
|
|
|
|
case SESSION_NOT_FOUND_4:
|
|
|
|
|
case SESSION_NOT_FOUND_5:
|
|
|
|
|
case SESSION_NOT_FOUND_6:
|
|
|
|
|
case SESSION_NOT_FOUND_7:
|
|
|
|
|
case SESSION_NOT_FOUND_8:
|
|
|
|
|
case SESSION_NOT_FOUND_9:
|
|
|
|
|
case SESSION_NOT_FOUND_10:
|
|
|
|
|
case SESSION_NOT_FOUND_11:
|
|
|
|
|
case SESSION_NOT_FOUND_12:
|
|
|
|
|
case SESSION_NOT_FOUND_13:
|
|
|
|
|
case SESSION_NOT_FOUND_14:
|
|
|
|
|
case SESSION_NOT_FOUND_15:
|
|
|
|
|
case SESSION_NOT_FOUND_16:
|
|
|
|
|
//case SESSION_NOT_FOUND_17: // undefined
|
|
|
|
|
case SESSION_NOT_FOUND_18:
|
|
|
|
|
case SESSION_NOT_FOUND_19:
|
|
|
|
|
case SESSION_NOT_FOUND_20:
|
|
|
|
|
case SESSION_NOT_FOUND_21:
|
|
|
|
|
case SESSION_NOT_FOUND_22:
|
|
|
|
|
case SESSION_NOT_FOUND_23:
|
|
|
|
|
LOGE("Session not found (inner_error=%d)", inner_error);
|
|
|
|
|
return kSessionNotFound;
|
|
|
|
|
case KEY_NOT_FOUND_1:
|
|
|
|
|
case KEY_NOT_FOUND_2:
|
|
|
|
|
case KEY_NOT_FOUND_3:
|
|
|
|
|
case KEY_NOT_FOUND_4:
|
|
|
|
|
case KEY_NOT_FOUND_5:
|
|
|
|
|
case KEY_NOT_FOUND_6:
|
|
|
|
|
case NEED_KEY:
|
|
|
|
|
case NO_CONTENT_KEY:
|
|
|
|
|
case NO_CONTENT_KEY_2:
|
|
|
|
|
case NO_CONTENT_KEY_3:
|
|
|
|
|
case SESSION_NOT_FOUND_FOR_DECRYPT:
|
|
|
|
|
LOGE("Key not found (inner_error=%d)", inner_error);
|
|
|
|
|
return kNoKey;
|
|
|
|
|
case INSUFFICIENT_OUTPUT_PROTECTION:
|
|
|
|
|
LOGE("Key usage blocked due to HDCP or display resolution constraints.");
|
|
|
|
|
return kKeyUsageBlockedByPolicy;
|
|
|
|
|
case OFFLINE_LICENSE_PROHIBITED:
|
|
|
|
|
LOGE("A temporary session cannot be used for a persistent license.");
|
|
|
|
|
return kRangeError;
|
|
|
|
|
case STORAGE_PROHIBITED:
|
|
|
|
|
LOGE(
|
|
|
|
|
"A temporary session cannot be used for a persistent usage records.");
|
|
|
|
|
return kRangeError;
|
|
|
|
|
|
|
|
|
|
case CERT_PROVISIONING_NONCE_GENERATION_ERROR:
|
|
|
|
|
case LICENSE_REQUEST_NONCE_GENERATION_ERROR:
|
|
|
|
|
LOGE("Nonce quota exceeded (inner_error=%d)", inner_error);
|
|
|
|
|
return kResourceContention;
|
|
|
|
|
case SESSION_LOST_STATE_ERROR:
|
|
|
|
|
LOGE("Session invalidated (inner_error=%d)", inner_error);
|
|
|
|
|
return kSessionStateLost;
|
|
|
|
|
case SYSTEM_INVALIDATED_ERROR:
|
|
|
|
|
LOGE("System invalidated (inner_error=%d)", inner_error);
|
|
|
|
|
return kSystemStateLost;
|
|
|
|
|
case OUTPUT_TOO_LARGE_ERROR:
|
|
|
|
|
LOGE("Output too large (inner_error=%d)", inner_error);
|
|
|
|
|
return kOutputTooLarge;
|
|
|
|
|
case PRIVACY_MODE_ERROR_1:
|
|
|
|
|
case PRIVACY_MODE_ERROR_2:
|
|
|
|
|
case PRIVACY_MODE_ERROR_3:
|
|
|
|
|
LOGE("No service certificate installed (inner_error=%d)", inner_error);
|
|
|
|
|
return kNeedsServiceCertificate;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
LOGE("Unknown error: %d", inner_error);
|
|
|
|
|
return kUnexpectedError;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
|
|
|