Merge latest oemcrypto-v17 change
No-Typo-Check: Not related to this change. Bug: 161477208 Change-Id: I99e4780f6855b7045aa0cd5a49c13d2d0d51ed64
This commit is contained in:
committed by
Fred Gylys-Colwell
parent
c924960962
commit
642965c678
@@ -61,7 +61,7 @@ class UsagePropertySet : public CdmClientPropertySet {
|
||||
const std::string empty_;
|
||||
};
|
||||
|
||||
CdmEngine::CdmEngine(FileSystem* file_system,
|
||||
CdmEngine::CdmEngine(wvutil::FileSystem* file_system,
|
||||
std::shared_ptr<metrics::EngineMetrics> metrics)
|
||||
: metrics_(metrics),
|
||||
cert_provisioning_(),
|
||||
@@ -182,11 +182,6 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
}
|
||||
return sts;
|
||||
}
|
||||
if (sts != NO_ERROR) {
|
||||
LOGE("Bad session init: status = %d", static_cast<int>(sts));
|
||||
return sts;
|
||||
}
|
||||
|
||||
const CdmSessionId id = new_session->session_id();
|
||||
LOGI("New session: session_id = %s", IdToString(id));
|
||||
|
||||
@@ -344,7 +339,7 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
}
|
||||
|
||||
LOGD("key_request = (%zu) %s", key_request->message.size(),
|
||||
wvcdm::Base64SafeEncode(key_request->message).c_str());
|
||||
wvutil::Base64SafeEncode(key_request->message).c_str());
|
||||
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
@@ -382,7 +377,7 @@ CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id,
|
||||
id = iter->second.first;
|
||||
} else {
|
||||
LOGD("key_data = (%zu) %s", key_data.size(),
|
||||
wvcdm::Base64SafeEncode(key_data).c_str());
|
||||
wvutil::Base64SafeEncode(key_data).c_str());
|
||||
}
|
||||
|
||||
std::shared_ptr<CdmSession> session;
|
||||
@@ -678,9 +673,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
return status;
|
||||
}
|
||||
if (query_token == QUERY_KEY_SRM_UPDATE_SUPPORT) {
|
||||
const bool is_srm_update_supported = crypto_session->IsSrmUpdateSupported();
|
||||
*query_response =
|
||||
is_srm_update_supported ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
*query_response = QUERY_VALUE_FALSE;
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (query_token == QUERY_KEY_WVCDM_VERSION) {
|
||||
@@ -737,6 +730,9 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
case kClientTokenOemCert:
|
||||
*query_response = QUERY_VALUE_OEM_CERTIFICATE;
|
||||
break;
|
||||
case kClientTokenBootCertChain:
|
||||
*query_response = QUERY_VALUE_BOOT_CERTIFICATE_CHAIN;
|
||||
break;
|
||||
case kClientTokenUninitialized:
|
||||
default:
|
||||
LOGW("GetProvisioningMethod returned invalid method: token_type = %d",
|
||||
@@ -1030,7 +1026,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
if (status != NO_ERROR) return status;
|
||||
}
|
||||
const CdmResponseType status = cert_provisioning_->GetProvisioningRequest(
|
||||
requested_security_level, cert_type, cert_authority,
|
||||
file_system_, requested_security_level, cert_type, cert_authority,
|
||||
file_system_->origin(), spoid_, request, default_url);
|
||||
if (status != NO_ERROR) {
|
||||
cert_provisioning_.reset(); // Release resources.
|
||||
@@ -1135,13 +1131,37 @@ bool CdmEngine::IsProvisioned(CdmSecurityLevel security_level) {
|
||||
UsagePropertySet property_set;
|
||||
property_set.set_security_level(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
return GetProvisioningStatus(security_level) == kProvisioned;
|
||||
}
|
||||
|
||||
CdmSession session(file_system_, metrics_->AddSession());
|
||||
const CdmResponseType status = session.Init(&property_set);
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("Init failed: status = %d", static_cast<int>(status));
|
||||
CdmProvisioningStatus CdmEngine::GetProvisioningStatus(
|
||||
CdmSecurityLevel security_level) {
|
||||
std::unique_ptr<CryptoSession> crypto_session(
|
||||
CryptoSession::MakeCryptoSession(metrics_->GetCryptoMetrics()));
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to open crypto session: status = %d",
|
||||
static_cast<int>(status));
|
||||
return kUnknownProvisionStatus;
|
||||
}
|
||||
return status == NO_ERROR;
|
||||
const CdmSecurityLevel cdm_security_level =
|
||||
crypto_session->GetSecurityLevel();
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(cdm_security_level)) {
|
||||
LOGE("Failed to initialize device files.");
|
||||
return kUnknownProvisionStatus;
|
||||
}
|
||||
|
||||
UsagePropertySet property_set;
|
||||
if (handle.HasCertificate(property_set.use_atsc_mode())) {
|
||||
return kProvisioned;
|
||||
}
|
||||
if (crypto_session->GetPreProvisionTokenType() == kClientTokenBootCertChain &&
|
||||
!handle.HasOemCertificate()) {
|
||||
return kNeedsOemCertProvisioning;
|
||||
}
|
||||
return kNeedsDrmCertProvisioning;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
@@ -1173,7 +1193,7 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
|
||||
// TODO(b/141705730): Remove usage entries during unprovisioning.
|
||||
if (!file_system_->IsGlobal()) {
|
||||
if (!handle.RemoveCertificate()) {
|
||||
if (!handle.RemoveCertificate() || !handle.RemoveOemCertificate()) {
|
||||
LOGE("Unable to delete certificate");
|
||||
return UNPROVISION_ERROR_2;
|
||||
}
|
||||
@@ -1421,7 +1441,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
}
|
||||
// Return a random usage report from a random security level
|
||||
SecurityLevel security_level =
|
||||
CdmRandom::RandomBool() ? kLevelDefault : kLevel3;
|
||||
wvutil::CdmRandom::RandomBool() ? kLevelDefault : kLevel3;
|
||||
CdmResponseType status = UNKNOWN_ERROR;
|
||||
do {
|
||||
status = GetUsageInfo(app_id, security_level, error_detail, usage_info);
|
||||
@@ -1486,7 +1506,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
const size_t index = CdmRandom::RandomInRange(usage_data.size() - 1);
|
||||
const size_t index = wvutil::CdmRandom::RandomInRange(usage_data.size() - 1);
|
||||
status = usage_session_->RestoreUsageSession(usage_data[index], error_detail);
|
||||
if (KEY_ADDED != status) {
|
||||
// TODO(b/141704872): Make multiple attempts.
|
||||
@@ -1897,7 +1917,7 @@ CdmResponseType CdmEngine::ParseDecryptHashString(
|
||||
return INVALID_DECRYPT_HASH_FORMAT;
|
||||
}
|
||||
|
||||
*hash = wvcdm::a2bs_hex(tokens[2]);
|
||||
*hash = wvutil::a2bs_hex(tokens[2]);
|
||||
if (hash->empty()) {
|
||||
LOGE("Malformed hash: %s", hash_string.c_str());
|
||||
return INVALID_DECRYPT_HASH_FORMAT;
|
||||
@@ -1990,7 +2010,7 @@ bool CdmEngine::ValidateKeySystem(const CdmKeySystem& key_system) {
|
||||
}
|
||||
|
||||
void CdmEngine::OnTimerEvent() {
|
||||
Clock clock;
|
||||
wvutil::Clock clock;
|
||||
const uint64_t current_time = clock.GetCurrentTime();
|
||||
bool usage_update_period_expired = false;
|
||||
if (current_time - last_usage_information_update_time_ >
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
CdmEngine* CdmEngineFactory::CreateCdmEngine(FileSystem* file_system) {
|
||||
CdmEngine* CdmEngineFactory::CreateCdmEngine(wvutil::FileSystem* file_system) {
|
||||
std::unique_ptr<metrics::EngineMetrics> engine_metrics(
|
||||
new metrics::EngineMetrics());
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
// Stringify turns macro arguments into static C strings.
|
||||
// Example: STRINGIFY(this_argument) -> "this_argument"
|
||||
#define STRINGIFY(PARAM...) #PARAM
|
||||
#define STRINGIFY(PARAM) #PARAM
|
||||
|
||||
#define RETURN_STATUS_IF_NULL(PARAM) \
|
||||
if ((PARAM) == nullptr) { \
|
||||
@@ -66,7 +66,7 @@ int DrmKeyTypeToMetricValue(CryptoWrappedKey::Type type) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CdmSession::CdmSession(FileSystem* file_system,
|
||||
CdmSession::CdmSession(wvutil::FileSystem* file_system,
|
||||
std::shared_ptr<metrics::SessionMetrics> metrics)
|
||||
: metrics_(metrics),
|
||||
initialized_(false),
|
||||
@@ -705,7 +705,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParametersV16& params) {
|
||||
is_usage_update_needed_ = has_provider_session_token();
|
||||
}
|
||||
} else {
|
||||
Clock clock;
|
||||
wvutil::Clock clock;
|
||||
int64_t current_time = clock.GetCurrentTime();
|
||||
if (policy_engine_->HasLicenseOrRentalOrPlaybackDurationExpired(
|
||||
current_time)) {
|
||||
@@ -887,9 +887,9 @@ bool CdmSession::GenerateKeySetId(bool atsc_mode_enabled,
|
||||
}
|
||||
|
||||
if (atsc_mode_enabled)
|
||||
*key_set_id = ATSC_KEY_SET_ID_PREFIX + b2a_hex(random_data);
|
||||
*key_set_id = ATSC_KEY_SET_ID_PREFIX + wvutil::b2a_hex(random_data);
|
||||
else
|
||||
*key_set_id = KEY_SET_ID_PREFIX + b2a_hex(random_data);
|
||||
*key_set_id = KEY_SET_ID_PREFIX + wvutil::b2a_hex(random_data);
|
||||
|
||||
// key set collision
|
||||
if (file_handle_->LicenseExists(*key_set_id)) {
|
||||
|
||||
@@ -28,7 +28,7 @@ const std::string kProvisioningServerUrl =
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
|
||||
// NOTE: Provider ID = widevine.com
|
||||
const std::string kCpProductionServiceCertificate = wvcdm::a2bs_hex(
|
||||
const std::string kCpProductionServiceCertificate = wvutil::a2bs_hex(
|
||||
"0ab9020803121051434fe2a44c763bcc2c826a2d6ef9a718f7d793d005228e02"
|
||||
"3082010a02820101009e27088659dbd9126bc6ed594caf652b0eaab82abb9862"
|
||||
"ada1ee6d2cb5247e94b28973fef5a3e11b57d0b0872c930f351b5694354a8c77"
|
||||
@@ -51,6 +51,30 @@ const std::string kCpProductionServiceCertificate = wvcdm::a2bs_hex(
|
||||
"26e0c050f3fd3ebe68cef9903ef6405b25fc6e31f93559fcff05657662b3653a"
|
||||
"8598ed5751b38694419242a875d9e00d5a5832933024b934859ec8be78adccbb"
|
||||
"1ec7127ae9afeef9c5cd2e15bd3048e8ce652f7d8c5d595a0323238c598a28");
|
||||
|
||||
// Retrieves |stored_oem_cert| from |file_handle|, and load the OEM private key
|
||||
// to |crypto_session|. Returns true if all operations are successful.
|
||||
bool RetrieveOemCertificateAndLoadPrivateKey(CryptoSession& crypto_session,
|
||||
DeviceFiles& file_handle,
|
||||
std::string& stored_oem_cert) {
|
||||
stored_oem_cert.clear();
|
||||
CryptoWrappedKey wrapped_private_key;
|
||||
if (file_handle.RetrieveOemCertificate(&stored_oem_cert,
|
||||
&wrapped_private_key) !=
|
||||
DeviceFiles::kCertificateValid) {
|
||||
LOGE("An invalid stored OEM certificated is retrieved");
|
||||
stored_oem_cert.clear();
|
||||
return false;
|
||||
}
|
||||
if (crypto_session.LoadOemCertificatePrivateKey(wrapped_private_key) !=
|
||||
NO_ERROR) {
|
||||
LOGE("Can not load the OEM private key");
|
||||
stored_oem_cert.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
// Protobuf generated classes.
|
||||
using video_widevine::ClientIdentification_ClientCapabilities;
|
||||
@@ -60,6 +84,7 @@ using video_widevine::EncryptedClientIdentification;
|
||||
using video_widevine::ProvisioningOptions;
|
||||
using video_widevine::ProvisioningRequest;
|
||||
using video_widevine::ProvisioningResponse;
|
||||
using video_widevine::PublicKeyToCertify;
|
||||
using video_widevine::SignedDrmCertificate;
|
||||
using video_widevine::SignedProvisioningMessage;
|
||||
using video_widevine::
|
||||
@@ -130,10 +155,14 @@ CdmResponseType CertificateProvisioning::SetSpoidParameter(
|
||||
*/
|
||||
SignedProvisioningMessage::ProvisioningType
|
||||
CertificateProvisioning::GetProvisioningType() {
|
||||
if (crypto_session_->GetPreProvisionTokenType() == kClientTokenOemCert)
|
||||
return SignedProvisioningMessage::PROVISIONING_30;
|
||||
else
|
||||
return SignedProvisioningMessage::PROVISIONING_20;
|
||||
switch (crypto_session_->GetPreProvisionTokenType()) {
|
||||
case kClientTokenBootCertChain:
|
||||
return SignedProvisioningMessage::PROVISIONING_40;
|
||||
case kClientTokenOemCert:
|
||||
return SignedProvisioningMessage::PROVISIONING_30;
|
||||
default:
|
||||
return SignedProvisioningMessage::PROVISIONING_20;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -144,20 +173,20 @@ CertificateProvisioning::GetProvisioningType() {
|
||||
* Returns NO_ERROR for success and CERT_PROVISIONING_REQUEST_ERROR_? if fails.
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
SecurityLevel requested_security_level, CdmCertificateType cert_type,
|
||||
const std::string& cert_authority, const std::string& origin,
|
||||
const std::string& spoid, CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
wvutil::FileSystem* file_system, SecurityLevel requested_security_level,
|
||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||
const std::string& origin, const std::string& spoid,
|
||||
CdmProvisioningRequest* request, std::string* default_url) {
|
||||
return CloseSessionOnError(GetProvisioningRequestInternal(
|
||||
requested_security_level, cert_type, cert_authority, origin, spoid,
|
||||
request, default_url));
|
||||
file_system, requested_security_level, cert_type, cert_authority, origin,
|
||||
spoid, request, default_url));
|
||||
}
|
||||
|
||||
CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
SecurityLevel requested_security_level, CdmCertificateType cert_type,
|
||||
const std::string& cert_authority, const std::string& origin,
|
||||
const std::string& spoid, CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
wvutil::FileSystem* file_system, SecurityLevel requested_security_level,
|
||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||
const std::string& origin, const std::string& spoid,
|
||||
CdmProvisioningRequest* request, std::string* default_url) {
|
||||
if (!request || !default_url) {
|
||||
LOGE("Output parameter |%s| is not provided",
|
||||
request ? "default_url" : "request");
|
||||
@@ -174,30 +203,17 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
return status;
|
||||
}
|
||||
|
||||
if (crypto_session_->GetPreProvisionTokenType() ==
|
||||
kClientTokenBootCertChain) {
|
||||
return GetProvisioning40RequestInternal(file_system, request);
|
||||
}
|
||||
|
||||
// Prepare device provisioning request.
|
||||
ProvisioningRequest provisioning_request;
|
||||
|
||||
wvcdm::ClientIdentification id;
|
||||
status = id.InitForProvisioning(crypto_session_.get());
|
||||
status = FillEncryptedClientId(/*client_token=*/"", provisioning_request);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
video_widevine::ClientIdentification client_id;
|
||||
|
||||
CdmAppParameterMap app_parameter;
|
||||
status = id.Prepare(app_parameter, kEmptyString, &client_id);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
if (!service_certificate_->has_certificate()) {
|
||||
LOGE("Service certificate not staged");
|
||||
return CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE;
|
||||
}
|
||||
|
||||
// Encrypt client identification
|
||||
EncryptedClientIdentification* encrypted_client_id =
|
||||
provisioning_request.mutable_encrypted_client_id();
|
||||
status = service_certificate_->EncryptClientId(
|
||||
crypto_session_.get(), &client_id, encrypted_client_id);
|
||||
|
||||
uint32_t nonce;
|
||||
status = crypto_session_->GenerateNonce(&nonce);
|
||||
|
||||
@@ -272,13 +288,184 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
|
||||
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
|
||||
// Return request as web-safe base64 string
|
||||
*request = Base64SafeEncodeNoPad(serialized_request);
|
||||
*request = wvutil::Base64SafeEncodeNoPad(serialized_request);
|
||||
} else {
|
||||
*request = std::move(serialized_request);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
|
||||
wvutil::FileSystem* file_system, CdmProvisioningRequest* request) {
|
||||
if (!crypto_session_->IsOpen()) {
|
||||
LOGE("Crypto session is not open");
|
||||
return PROVISIONING_4_CRYPTO_SESSION_NOT_OPEN;
|
||||
}
|
||||
|
||||
if (file_system == nullptr) {
|
||||
LOGE("file_system is nullptr but is required in provisioning 4");
|
||||
return PROVISIONING_4_FILE_SYSTEM_IS_NULL;
|
||||
}
|
||||
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
|
||||
DeviceFiles file_handle(file_system);
|
||||
if (!file_handle.Init(security_level)) {
|
||||
LOGE("Failed to initialize DeviceFiles");
|
||||
return PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES;
|
||||
}
|
||||
|
||||
ProvisioningRequest provisioning_request;
|
||||
// Determine the current stage by checking if OEM cert exists.
|
||||
std::string stored_oem_cert;
|
||||
if (file_handle.HasOemCertificate()) {
|
||||
// This is second stage requesting for DRM cert. We try to use the stored
|
||||
// OEM cert. In case of error, we just fall back to the first stage
|
||||
// provisioning (request for an OEM cert).
|
||||
if (!RetrieveOemCertificateAndLoadPrivateKey(*crypto_session_, file_handle,
|
||||
stored_oem_cert)) {
|
||||
stored_oem_cert.clear();
|
||||
LOGD("Deleting the stored OEM certificate due to unsuccessful read");
|
||||
if (!file_handle.RemoveOemCertificate()) {
|
||||
// This should not happen.
|
||||
LOGE("Failed to delete the OEM certificate certificate");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the first stage, |stored_oem_cert| remains empty. In this case,
|
||||
// the client identification token will be retrieved from OEMCrypto, which is
|
||||
// the BCC in this case.
|
||||
// If this is the second stage, |stored_oem_cert| is non-empty and will be
|
||||
// used as the client identification token.
|
||||
CdmResponseType status =
|
||||
FillEncryptedClientId(stored_oem_cert, provisioning_request);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
std::string public_key;
|
||||
std::string public_key_signature;
|
||||
provisioning_40_wrapped_private_key_.clear();
|
||||
provisioning_40_key_type_ = CryptoWrappedKey::kUninitialized;
|
||||
status = crypto_session_->GenerateCertificateKeyPair(
|
||||
&public_key, &public_key_signature, &provisioning_40_wrapped_private_key_,
|
||||
&provisioning_40_key_type_);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
PublicKeyToCertify* key_to_certify =
|
||||
provisioning_request.mutable_certificate_public_key();
|
||||
key_to_certify->set_public_key(public_key);
|
||||
key_to_certify->set_signature(public_key_signature);
|
||||
key_to_certify->set_key_type(provisioning_40_key_type_ ==
|
||||
CryptoWrappedKey::kRsa
|
||||
? PublicKeyToCertify::RSA
|
||||
: PublicKeyToCertify::ECC);
|
||||
|
||||
// In provisioning 4, the message is not signed.
|
||||
SignedProvisioningMessage signed_provisioning_msg;
|
||||
provisioning_request.SerializeToString(
|
||||
signed_provisioning_msg.mutable_message());
|
||||
signed_provisioning_msg.set_provisioning_type(GetProvisioningType());
|
||||
signed_provisioning_msg.set_protocol_version(
|
||||
SignedProvisioningMessage_ProvisioningProtocolVersion_VERSION_1_1);
|
||||
|
||||
std::string serialized_request;
|
||||
signed_provisioning_msg.SerializeToString(&serialized_request);
|
||||
|
||||
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
|
||||
// Return request as web-safe base64 string
|
||||
*request = wvutil::Base64SafeEncodeNoPad(serialized_request);
|
||||
} else {
|
||||
*request = std::move(serialized_request);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CertificateProvisioning::FillEncryptedClientId(
|
||||
const std::string& client_token,
|
||||
ProvisioningRequest& provisioning_request) {
|
||||
if (!crypto_session_->IsOpen()) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
wvcdm::ClientIdentification id;
|
||||
CdmResponseType status =
|
||||
id.InitForProvisioningRequest(client_token, crypto_session_.get());
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
video_widevine::ClientIdentification client_id;
|
||||
CdmAppParameterMap app_parameter;
|
||||
status = id.Prepare(app_parameter, kEmptyString, &client_id);
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
if (!service_certificate_->has_certificate()) {
|
||||
LOGE("Service certificate not staged");
|
||||
return CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE;
|
||||
}
|
||||
|
||||
// Encrypt client identification
|
||||
return service_certificate_->EncryptClientId(
|
||||
crypto_session_.get(), &client_id,
|
||||
provisioning_request.mutable_encrypted_client_id());
|
||||
}
|
||||
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioning40Response(
|
||||
wvutil::FileSystem* file_system, const std::string& response_message) {
|
||||
ProvisioningResponse provisioning_response;
|
||||
if (response_message.empty() ||
|
||||
!provisioning_response.ParseFromString(response_message)) {
|
||||
return PROVISIONING_4_RESPONSE_FAILED_TO_PARSE_MESSAGE;
|
||||
}
|
||||
if (provisioning_response.has_status() &&
|
||||
provisioning_response.status() != ProvisioningResponse::NO_ERROR) {
|
||||
LOGE("Provisioning Response status: %d", provisioning_response.status());
|
||||
switch (provisioning_response.status()) {
|
||||
case ProvisioningResponse::REVOKED_DEVICE_CREDENTIALS:
|
||||
case ProvisioningResponse::REVOKED_DEVICE_SERIES:
|
||||
return DEVICE_REVOKED;
|
||||
default:
|
||||
return PROVISIONING_4_RESPONSE_HAS_ERROR_STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& device_certificate =
|
||||
provisioning_response.device_certificate();
|
||||
if (device_certificate.empty()) {
|
||||
LOGE("Provisioning response has no certificate");
|
||||
return PROVISIONING_4_RESPONSE_HAS_NO_CERTIFICATE;
|
||||
}
|
||||
|
||||
if (provisioning_40_wrapped_private_key_.empty()) {
|
||||
LOGE("No private key was generated");
|
||||
return PROVISIONING_4_NO_PRIVATE_KEY;
|
||||
}
|
||||
const CryptoWrappedKey private_key(provisioning_40_key_type_,
|
||||
provisioning_40_wrapped_private_key_);
|
||||
|
||||
const CdmSecurityLevel security_level = crypto_session_->GetSecurityLevel();
|
||||
CloseSession();
|
||||
DeviceFiles file_handle(file_system);
|
||||
if (!file_handle.Init(security_level)) {
|
||||
LOGE("Failed to initialize DeviceFiles");
|
||||
return PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_2;
|
||||
}
|
||||
|
||||
// Check the stage of the provisioning by checking if an OEM cert is already
|
||||
// stored in the file system.
|
||||
if (!file_handle.HasOemCertificate()) {
|
||||
// No OEM cert already stored => the response is expected to be an OEM cert.
|
||||
if (!file_handle.StoreOemCertificate(device_certificate, private_key)) {
|
||||
LOGE("Failed to store provisioning 4 OEM certificate");
|
||||
return PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE;
|
||||
}
|
||||
} else {
|
||||
// The response is assumed to be an DRM cert.
|
||||
if (!file_handle.StoreCertificate(device_certificate, private_key)) {
|
||||
LOGE("Failed to store provisioning 4 DRM certificate");
|
||||
return PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE;
|
||||
}
|
||||
}
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* The response message consists of a device certificate and the device RSA key.
|
||||
* The device RSA key is stored in the T.E.E. The device certificate is stored
|
||||
@@ -287,8 +474,9 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequestInternal(
|
||||
* Returns NO_ERROR for success and CERT_PROVISIONING_RESPONSE_ERROR_? if fails.
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
FileSystem* file_system, const CdmProvisioningResponse& response_message,
|
||||
std::string* cert, std::string* wrapped_key) {
|
||||
wvutil::FileSystem* file_system,
|
||||
const CdmProvisioningResponse& response_message, std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
if (response_message.empty()) {
|
||||
LOGE("Provisioning response message is empty");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_1;
|
||||
@@ -317,6 +505,11 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_2;
|
||||
}
|
||||
|
||||
if (signed_response.provisioning_type() ==
|
||||
SignedProvisioningMessage::PROVISIONING_40) {
|
||||
return HandleProvisioning40Response(file_system, signed_response.message());
|
||||
}
|
||||
|
||||
bool error = false;
|
||||
if (!signed_response.has_signature()) {
|
||||
LOGE("Signed response does not have signature");
|
||||
@@ -491,7 +684,7 @@ bool CertificateProvisioning::ExtractAndDecodeSignedMessage(
|
||||
|
||||
// Decode the base64-encoded message.
|
||||
const std::vector<uint8_t> decoded_message =
|
||||
wvcdm::Base64SafeDecode(message_string);
|
||||
wvutil::Base64SafeDecode(message_string);
|
||||
result->assign(decoded_message.begin(), decoded_message.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -68,13 +68,14 @@ using video_widevine::ProvisioningRequest;
|
||||
using video_widevine::ProvisioningResponse;
|
||||
using video_widevine::SignedProvisioningMessage;
|
||||
|
||||
CdmResponseType ClientIdentification::InitForProvisioning(
|
||||
CryptoSession* crypto_session) {
|
||||
CdmResponseType ClientIdentification::InitForProvisioningRequest(
|
||||
const std::string& client_token, CryptoSession* crypto_session) {
|
||||
if (crypto_session == nullptr) {
|
||||
LOGE("Crypto session not provided");
|
||||
return PARAMETER_NULL;
|
||||
}
|
||||
is_license_request_ = false;
|
||||
client_token_ = client_token;
|
||||
crypto_session_ = crypto_session;
|
||||
return NO_ERROR;
|
||||
}
|
||||
@@ -118,7 +119,15 @@ CdmResponseType ClientIdentification::Prepare(
|
||||
client_id->set_type(
|
||||
video_widevine::ClientIdentification::DRM_DEVICE_CERTIFICATE);
|
||||
client_id->set_token(client_token_);
|
||||
} else if (!client_token_.empty()) {
|
||||
// A token has been provided via InitForProvisioningRequest. This can only
|
||||
// happen in provisioning 4 (second stage) where an OEM cert is provided.
|
||||
client_id->set_type(
|
||||
video_widevine::ClientIdentification::OEM_DEVICE_CERTIFICATE);
|
||||
client_id->set_token(client_token_);
|
||||
} else if (!is_okp_request_) {
|
||||
// An OTA Keybox Provisioning request does not have a client id.
|
||||
// Otherwise this is a regular provisioning request.
|
||||
video_widevine::ClientIdentification::TokenType token_type;
|
||||
if (!GetProvisioningTokenType(&token_type)) {
|
||||
LOGE("Failed to get provisioning token type");
|
||||
@@ -127,13 +136,18 @@ CdmResponseType ClientIdentification::Prepare(
|
||||
client_id->set_type(token_type);
|
||||
|
||||
std::string token;
|
||||
CdmResponseType status = crypto_session_->GetProvisioningToken(&token);
|
||||
std::string additional_token;
|
||||
CdmResponseType status =
|
||||
crypto_session_->GetProvisioningToken(&token, &additional_token);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Failed to get provisioning token: status = %d",
|
||||
static_cast<int>(status));
|
||||
return status;
|
||||
}
|
||||
client_id->set_token(token);
|
||||
if (!additional_token.empty()) {
|
||||
client_id->mutable_device_credentials()->set_token(additional_token);
|
||||
}
|
||||
}
|
||||
|
||||
ClientIdentification_NameValue* client_info;
|
||||
@@ -295,8 +309,7 @@ CdmResponseType ClientIdentification::Prepare(
|
||||
}
|
||||
|
||||
if (is_license_request_) {
|
||||
client_capabilities->set_can_update_srm(
|
||||
crypto_session_->IsSrmUpdateSupported());
|
||||
client_capabilities->set_can_update_srm(false);
|
||||
uint16_t srm_version;
|
||||
if (crypto_session_->GetSrmVersion(&srm_version) == NO_ERROR)
|
||||
client_capabilities->set_srm_version(srm_version);
|
||||
@@ -344,6 +357,10 @@ bool ClientIdentification::GetProvisioningTokenType(
|
||||
*token_type =
|
||||
video_widevine::ClientIdentification::OEM_DEVICE_CERTIFICATE;
|
||||
return true;
|
||||
case kClientTokenBootCertChain:
|
||||
*token_type =
|
||||
video_widevine::ClientIdentification::BOOT_CERTIFICATE_CHAIN;
|
||||
return true;
|
||||
case kClientTokenDrmCert:
|
||||
default:
|
||||
// shouldn't happen
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
|
||||
// Stringify turns macro arguments into static C strings.
|
||||
// Example: STRINGIFY(this_argument) -> "this_argument"
|
||||
#define STRINGIFY(PARAM...) #PARAM
|
||||
#define STRINGIFY(PARAM) #PARAM
|
||||
|
||||
#define RETURN_IF_NULL(PARAM, ret_value) \
|
||||
if ((PARAM) == nullptr) { \
|
||||
@@ -51,6 +51,16 @@
|
||||
return ret_value; \
|
||||
}
|
||||
|
||||
#ifdef HAS_DUAL_KEY
|
||||
/**
|
||||
* Internal only OEMCrypto method. This is called before parsing the license
|
||||
* response to indicate the response uses dual keys. If this isn't called,
|
||||
* it is using single keys.
|
||||
*/
|
||||
extern "C" OEMCryptoResult OEMCrypto_UseSecondaryKey(OEMCrypto_SESSION session,
|
||||
bool dual_key);
|
||||
#endif
|
||||
|
||||
namespace wvcdm {
|
||||
namespace {
|
||||
using UsageTableLock = std::unique_lock<std::recursive_mutex>;
|
||||
@@ -83,7 +93,7 @@ constexpr size_t kMaxSubsampleRegionSizes[] = {
|
||||
};
|
||||
// The +1 in this calculation is because the bounds RESOURCE_RATING_TIER_MAX and
|
||||
// RESOURCE_RATING_TIER_MIN are inclusive.
|
||||
static_assert(ArraySize(kMaxSubsampleRegionSizes) ==
|
||||
static_assert(wvutil::ArraySize(kMaxSubsampleRegionSizes) ==
|
||||
RESOURCE_RATING_TIER_MAX - RESOURCE_RATING_TIER_MIN + 1,
|
||||
"The kMaxSubsampleRegionSizes table needs to be updated to "
|
||||
"reflect the supported range of resource rating tiers");
|
||||
@@ -128,8 +138,8 @@ CdmResponseType MapOEMCryptoResult(OEMCryptoResult result,
|
||||
void AdvanceDestBuffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) {
|
||||
switch (dest_buffer->type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
dest_buffer->buffer.clear.address += bytes;
|
||||
dest_buffer->buffer.clear.address_length -= bytes;
|
||||
dest_buffer->buffer.clear.clear_buffer += bytes;
|
||||
dest_buffer->buffer.clear.clear_buffer_length -= bytes;
|
||||
return;
|
||||
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
@@ -176,8 +186,8 @@ size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm) {
|
||||
} // namespace
|
||||
|
||||
// CryptoSession variables allocation.
|
||||
shared_mutex CryptoSession::static_field_mutex_;
|
||||
shared_mutex CryptoSession::oem_crypto_mutex_;
|
||||
wvutil::shared_mutex CryptoSession::static_field_mutex_;
|
||||
wvutil::shared_mutex CryptoSession::oem_crypto_mutex_;
|
||||
bool CryptoSession::initialized_ = false;
|
||||
bool CryptoSession::needs_keybox_provisioning_ = false;
|
||||
int CryptoSession::session_count_ = 0;
|
||||
@@ -233,7 +243,7 @@ void GenerateMacContext(const std::string& input_context,
|
||||
deriv_context->assign(kSigningKeyLabel);
|
||||
deriv_context->append(1, '\0');
|
||||
deriv_context->append(input_context);
|
||||
deriv_context->append(EncodeUint32(kSigningKeySizeBits * 2));
|
||||
deriv_context->append(wvutil::EncodeUint32(kSigningKeySizeBits * 2));
|
||||
}
|
||||
|
||||
void GenerateEncryptContext(const std::string& input_context,
|
||||
@@ -249,12 +259,12 @@ void GenerateEncryptContext(const std::string& input_context,
|
||||
deriv_context->assign(kEncryptionKeyLabel);
|
||||
deriv_context->append(1, '\0');
|
||||
deriv_context->append(input_context);
|
||||
deriv_context->append(EncodeUint32(kEncryptionKeySizeBits));
|
||||
deriv_context->append(wvutil::EncodeUint32(kEncryptionKeySizeBits));
|
||||
}
|
||||
|
||||
OEMCryptoCipherMode ToOEMCryptoCipherMode(CdmCipherMode cipher_mode) {
|
||||
return cipher_mode == kCipherModeCtr ? OEMCrypto_CipherMode_CTR
|
||||
: OEMCrypto_CipherMode_CBC;
|
||||
return cipher_mode == kCipherModeCtr ? OEMCrypto_CipherMode_CENC
|
||||
: OEMCrypto_CipherMode_CBCS;
|
||||
}
|
||||
|
||||
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
|
||||
@@ -306,6 +316,9 @@ CdmResponseType CryptoSession::GetProvisioningMethod(
|
||||
case OEMCrypto_DrmCertificate:
|
||||
type = kClientTokenDrmCert;
|
||||
break;
|
||||
case OEMCrypto_BootCertificateChain:
|
||||
type = kClientTokenBootCertChain;
|
||||
break;
|
||||
case OEMCrypto_ProvisioningError:
|
||||
default:
|
||||
if (static_cast<int>(method) == 0 && needs_keybox_provisioning_) {
|
||||
@@ -361,10 +374,18 @@ void CryptoSession::Init() {
|
||||
void CryptoSession::ReinitializeForTest() {
|
||||
if (initialized_) {
|
||||
initialized_ = false;
|
||||
if (OEMCrypto_SUCCESS != OEMCrypto_Terminate()) return;
|
||||
OEMCryptoResult status = OEMCrypto_Terminate();
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
LOGE("OEMCrypto_Terminate failed: %d", status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Give up if we cannot initialize at all.
|
||||
if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) return;
|
||||
OEMCryptoResult status = OEMCrypto_Initialize();
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
LOGE("OEMCrypto_Initialize failed: %d", status);
|
||||
return;
|
||||
}
|
||||
initialized_ = true;
|
||||
// For integration and unit tests we will install a test keybox and do not
|
||||
// need to do keybox provisioning.
|
||||
@@ -562,10 +583,12 @@ CdmResponseType CryptoSession::GetTokenFromOemCert(std::string* token) {
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GetProvisioningToken(std::string* token) {
|
||||
if (token == nullptr) {
|
||||
CdmResponseType CryptoSession::GetProvisioningToken(
|
||||
std::string* token, std::string* additional_token) {
|
||||
if (token == nullptr || additional_token == nullptr) {
|
||||
metrics_->crypto_session_get_token_.Increment(PARAMETER_NULL);
|
||||
RETURN_IF_NULL(token, PARAMETER_NULL);
|
||||
RETURN_IF_NULL(additional_token, PARAMETER_NULL);
|
||||
}
|
||||
|
||||
if (!IsInitialized()) {
|
||||
@@ -579,6 +602,8 @@ CdmResponseType CryptoSession::GetProvisioningToken(std::string* token) {
|
||||
status = GetTokenFromKeybox(token);
|
||||
} else if (pre_provision_token_type_ == kClientTokenOemCert) {
|
||||
status = GetTokenFromOemCert(token);
|
||||
} else if (pre_provision_token_type_ == kClientTokenBootCertChain) {
|
||||
status = GetBootCertificateChain(token, additional_token);
|
||||
}
|
||||
metrics_->crypto_session_get_token_.Increment(status);
|
||||
return status;
|
||||
@@ -595,41 +620,28 @@ CdmSecurityLevel CryptoSession::GetSecurityLevel(
|
||||
LOGV("Getting security level: requested_security_level = %s",
|
||||
SecurityLevelToString(requested_security_level));
|
||||
RETURN_IF_UNINITIALIZED(kSecurityLevelUninitialized);
|
||||
const char* const level = WithOecReadLock("GetSecurityLevel", [&] {
|
||||
return OEMCrypto_SecurityLevel(requested_security_level);
|
||||
});
|
||||
if (level == nullptr) {
|
||||
LOGE("Security level is null: requested_security_level = %d",
|
||||
const OEMCrypto_Security_Level level = WithOecReadLock(
|
||||
"GetSecurityLevel",
|
||||
[&] { return OEMCrypto_SecurityLevel(requested_security_level); });
|
||||
if (level == 0) {
|
||||
LOGE("Security level is unknown: requested_security_level = %d",
|
||||
static_cast<int>(requested_security_level));
|
||||
return kSecurityLevelUnknown;
|
||||
}
|
||||
// Check length in the event of a bad pointer.
|
||||
// |kMaxSecurityLevelLength| is a value larger than expected to
|
||||
// be able to detect an overrun.
|
||||
constexpr size_t kMaxSecurityLevelLength = 5;
|
||||
const size_t length = strnlen(level, kMaxSecurityLevelLength);
|
||||
constexpr size_t kExpectedSecurityLevelLength = 2;
|
||||
if (length != kExpectedSecurityLevelLength) {
|
||||
LOGE(
|
||||
"Unexpected security level length: "
|
||||
"length = %zu, requested_security_level = %s",
|
||||
length, SecurityLevelToString(requested_security_level));
|
||||
return kSecurityLevelUnknown;
|
||||
}
|
||||
const std::string security_level(level);
|
||||
if (security_level == "L1") {
|
||||
if (level == OEMCrypto_Level1) {
|
||||
return kSecurityLevelL1;
|
||||
}
|
||||
if (security_level == "L2") {
|
||||
if (level == OEMCrypto_Level2) {
|
||||
return kSecurityLevelL2;
|
||||
}
|
||||
if (security_level == "L3") {
|
||||
if (level == OEMCrypto_Level3) {
|
||||
return kSecurityLevelL3;
|
||||
}
|
||||
LOGE(
|
||||
"Ill-formed security level: "
|
||||
"level = \"%s\", requested_security_level = %s",
|
||||
security_level.c_str(), SecurityLevelToString(requested_security_level));
|
||||
"level = \"L%u\", requested_security_level = %s",
|
||||
static_cast<unsigned int>(level),
|
||||
SecurityLevelToString(requested_security_level));
|
||||
return kSecurityLevelUnknown;
|
||||
}
|
||||
|
||||
@@ -815,6 +827,11 @@ CdmResponseType CryptoSession::GetSystemIdInternal(uint32_t* system_id) {
|
||||
// Drm certificate.
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (pre_provision_token_type_ == kClientTokenBootCertChain) {
|
||||
// A system id can not be inferred from BCC. If the provisioning process has
|
||||
// come to the second stage, we may read system id from the stored OEM cert.
|
||||
return NO_ERROR;
|
||||
}
|
||||
LOGE("Unsupported pre-provision token type: %d",
|
||||
static_cast<int>(pre_provision_token_type_));
|
||||
return UNKNOWN_CLIENT_TOKEN_TYPE;
|
||||
@@ -938,10 +955,10 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
metrics_->oemcrypto_get_random_.Increment(random_sts);
|
||||
uint64_t request_id_index =
|
||||
request_id_index_source_.fetch_add(1, std::memory_order_relaxed);
|
||||
request_id_ = HexEncode(reinterpret_cast<uint8_t*>(&request_id_base),
|
||||
sizeof(request_id_base)) +
|
||||
HexEncode(reinterpret_cast<uint8_t*>(&request_id_index),
|
||||
sizeof(request_id_index));
|
||||
request_id_ = wvutil::HexEncode(reinterpret_cast<uint8_t*>(&request_id_base),
|
||||
sizeof(request_id_base)) +
|
||||
wvutil::HexEncode(reinterpret_cast<uint8_t*>(&request_id_index),
|
||||
sizeof(request_id_index));
|
||||
|
||||
// Initialize key session
|
||||
WithOecSessionLock("Open() calling key_session_.reset()", [&] {
|
||||
@@ -1058,6 +1075,19 @@ CdmResponseType CryptoSession::PrepareAndSignLicenseRequest(
|
||||
"PrepareAndSignLicenseRequest");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::UseSecondaryKey(bool dual_key) {
|
||||
#ifdef HAS_DUAL_KEY
|
||||
OEMCryptoResult sts;
|
||||
WithOecSessionLock("UseSecondaryKey", [&] {
|
||||
sts = OEMCrypto_UseSecondaryKey(oec_session_id_, dual_key);
|
||||
});
|
||||
|
||||
return MapOEMCryptoResult(sts, LOAD_KEY_ERROR, "UseSecondaryKey");
|
||||
#else
|
||||
return NO_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::LoadKeys(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
@@ -1388,6 +1418,122 @@ CdmResponseType CryptoSession::LoadCertificatePrivateKey(
|
||||
"LoadCertificatePrivateKey");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GetBootCertificateChain(
|
||||
std::string* bcc, std::string* additional_signature) {
|
||||
RETURN_IF_NULL(bcc, PARAMETER_NULL);
|
||||
RETURN_IF_NULL(additional_signature, PARAMETER_NULL);
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
LOGV("GetBootCertificateChain");
|
||||
if (pre_provision_token_type_ != kClientTokenBootCertChain) {
|
||||
return PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR;
|
||||
}
|
||||
|
||||
size_t bcc_length = 0;
|
||||
size_t additional_signature_length = 0;
|
||||
OEMCryptoResult sts;
|
||||
WithOecReadLock("GetBootCertificateChain Attempt 1", [&] {
|
||||
sts = OEMCrypto_GetBootCertificateChain(nullptr, &bcc_length, nullptr,
|
||||
&additional_signature_length);
|
||||
});
|
||||
if (sts == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
bcc->resize(bcc_length);
|
||||
additional_signature->resize(additional_signature_length);
|
||||
WithOecReadLock("GetBootCertificateChain Attempt 2", [&] {
|
||||
sts = OEMCrypto_GetBootCertificateChain(
|
||||
reinterpret_cast<uint8_t*>(&bcc->front()), &bcc_length,
|
||||
reinterpret_cast<uint8_t*>(&additional_signature->front()),
|
||||
&additional_signature_length);
|
||||
});
|
||||
}
|
||||
return MapOEMCryptoResult(sts, GET_BOOT_CERTIFICATE_CHAIN_ERROR,
|
||||
"GetBootCertificateChain");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenerateCertificateKeyPair(
|
||||
std::string* public_key, std::string* public_key_signature,
|
||||
std::string* wrapped_private_key, CryptoWrappedKey::Type* key_type) {
|
||||
LOGV("Generating certificate key pair: id = %u", oec_session_id_);
|
||||
RETURN_IF_NULL(public_key, PARAMETER_NULL);
|
||||
RETURN_IF_NULL(public_key_signature, PARAMETER_NULL);
|
||||
RETURN_IF_NULL(wrapped_private_key, PARAMETER_NULL);
|
||||
RETURN_IF_NULL(key_type, PARAMETER_NULL);
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
|
||||
// Round 1, get the size of all the fields.
|
||||
size_t public_key_length = 0;
|
||||
size_t public_key_signature_length = 0;
|
||||
size_t wrapped_private_key_length = 0;
|
||||
OEMCrypto_PrivateKeyType oemcrypto_key_type;
|
||||
OEMCryptoResult status;
|
||||
WithOecSessionLock("GenerateCertificateKeyPair Attempt 1", [&] {
|
||||
M_TIME(status = OEMCrypto_GenerateCertificateKeyPair(
|
||||
oec_session_id_, nullptr, &public_key_length, nullptr,
|
||||
&public_key_signature_length, nullptr,
|
||||
&wrapped_private_key_length, &oemcrypto_key_type),
|
||||
metrics_, oemcrypto_generate_certificate_key_pair_, status);
|
||||
});
|
||||
|
||||
if (status != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
return MapOEMCryptoResult(status, GENERATE_CERTIFICATE_KEY_PAIR_ERROR,
|
||||
"GenerateCertificateKeyPair");
|
||||
}
|
||||
|
||||
public_key->resize(public_key_length);
|
||||
public_key_signature->resize(public_key_signature_length);
|
||||
wrapped_private_key->resize(wrapped_private_key_length);
|
||||
WithOecSessionLock("GenerateCertificateKeyPair Attempt 2", [&] {
|
||||
M_TIME(
|
||||
status = OEMCrypto_GenerateCertificateKeyPair(
|
||||
oec_session_id_, reinterpret_cast<uint8_t*>(&public_key->front()),
|
||||
&public_key_length,
|
||||
reinterpret_cast<uint8_t*>(&public_key_signature->front()),
|
||||
&public_key_signature_length,
|
||||
reinterpret_cast<uint8_t*>(&wrapped_private_key->front()),
|
||||
&wrapped_private_key_length, &oemcrypto_key_type),
|
||||
metrics_, oemcrypto_generate_certificate_key_pair_, status);
|
||||
});
|
||||
public_key->resize(public_key_length);
|
||||
public_key_signature->resize(public_key_signature_length);
|
||||
wrapped_private_key->resize(wrapped_private_key_length);
|
||||
|
||||
if (oemcrypto_key_type == OEMCrypto_RSA_Private_Key) {
|
||||
*key_type = CryptoWrappedKey::kRsa;
|
||||
} else if (oemcrypto_key_type == OEMCrypto_ECC_Private_Key) {
|
||||
*key_type = CryptoWrappedKey::kEcc;
|
||||
} else {
|
||||
LOGE("Unexpected key type returned from GenerateCertificateKeyPair: %d",
|
||||
static_cast<int>(oemcrypto_key_type));
|
||||
return MapOEMCryptoResult(status,
|
||||
GENERATE_CERTIFICATE_KEY_PAIR_UNKNOWN_TYPE_ERROR,
|
||||
"GenerateCertificateKeyPair");
|
||||
}
|
||||
|
||||
return MapOEMCryptoResult(status, GENERATE_CERTIFICATE_KEY_PAIR_ERROR,
|
||||
"GenerateCertificateKeyPair");
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::LoadOemCertificatePrivateKey(
|
||||
const CryptoWrappedKey& private_key) {
|
||||
LOGV("Load OEM cert and private key: id = %u", oec_session_id_);
|
||||
const OEMCrypto_PrivateKeyType key_type =
|
||||
(private_key.type() == CryptoWrappedKey::kEcc)
|
||||
? OEMCrypto_ECC_Private_Key
|
||||
: OEMCrypto_RSA_Private_Key;
|
||||
const std::string& wrapped_private_key = private_key.key();
|
||||
|
||||
OEMCryptoResult status;
|
||||
WithOecSessionLock("InstallOemPrivateKey", [&] {
|
||||
M_TIME(status = OEMCrypto_InstallOemPrivateKey(
|
||||
oec_session_id_, key_type,
|
||||
reinterpret_cast<const uint8_t*>(wrapped_private_key.data()),
|
||||
wrapped_private_key.size()),
|
||||
metrics_, oemcrypto_install_oem_private_key_, status);
|
||||
});
|
||||
|
||||
return MapOEMCryptoResult(status, LOAD_OEM_CERTIFICATE_PRIVATE_KEY_ERROR,
|
||||
"InstallOemPrivateKey");
|
||||
}
|
||||
|
||||
// Private.
|
||||
CdmResponseType CryptoSession::SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) {
|
||||
@@ -1502,7 +1648,7 @@ size_t CryptoSession::GetMaxSubsampleRegionSize() {
|
||||
// Subtract RESOURCE_RATING_TIER_MIN to get a 0-based index into the
|
||||
// table.
|
||||
const uint32_t index = tier - RESOURCE_RATING_TIER_MIN;
|
||||
if (index < ArraySize(kMaxSubsampleRegionSizes)) {
|
||||
if (index < wvutil::ArraySize(kMaxSubsampleRegionSizes)) {
|
||||
max_subsample_region_size_ = kMaxSubsampleRegionSizes[index];
|
||||
}
|
||||
}
|
||||
@@ -1563,16 +1709,16 @@ CdmResponseType CryptoSession::Decrypt(
|
||||
output_descriptor.type = output_descriptor_type;
|
||||
switch (output_descriptor.type) {
|
||||
case OEMCrypto_BufferType_Clear:
|
||||
output_descriptor.buffer.clear.address =
|
||||
output_descriptor.buffer.clear.clear_buffer =
|
||||
static_cast<uint8_t*>(sample.decrypt_buffer) +
|
||||
sample.decrypt_buffer_offset;
|
||||
output_descriptor.buffer.clear.address_length =
|
||||
output_descriptor.buffer.clear.clear_buffer_length =
|
||||
sample.decrypt_buffer_size - sample.decrypt_buffer_offset;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Secure:
|
||||
output_descriptor.buffer.secure.handle = sample.decrypt_buffer;
|
||||
output_descriptor.buffer.secure.secure_buffer = sample.decrypt_buffer;
|
||||
output_descriptor.buffer.secure.offset = sample.decrypt_buffer_offset;
|
||||
output_descriptor.buffer.secure.handle_length =
|
||||
output_descriptor.buffer.secure.secure_buffer_length =
|
||||
sample.decrypt_buffer_size;
|
||||
break;
|
||||
case OEMCrypto_BufferType_Direct:
|
||||
@@ -1824,7 +1970,7 @@ CdmResponseType CryptoSession::GenerateUsageReport(
|
||||
(*usage_report) =
|
||||
std::string(reinterpret_cast<const char*>(&buffer[0]), buffer.size());
|
||||
|
||||
Unpacked_PST_Report pst_report(&buffer[0]);
|
||||
wvutil::Unpacked_PST_Report pst_report(&buffer[0]);
|
||||
*usage_duration_status = kUsageDurationsInvalid;
|
||||
if (usage_length < pst_report.report_size()) {
|
||||
LOGE(
|
||||
@@ -1852,7 +1998,7 @@ CdmResponseType CryptoSession::GenerateUsageReport(
|
||||
pst_report.seconds_since_first_decrypt());
|
||||
LOGV("OEMCrypto_PST_Report.seconds_since_last_decrypt: %" PRId64 "\n",
|
||||
pst_report.seconds_since_last_decrypt());
|
||||
LOGV("OEMCrypto_PST_Report: %s\n", b2a_hex(*usage_report).c_str());
|
||||
LOGV("OEMCrypto_PST_Report: %s\n", wvutil::b2a_hex(*usage_report).c_str());
|
||||
|
||||
if (kInactiveUnused == pst_report.status()) {
|
||||
*usage_duration_status = kUsageDurationPlaybackNotBegun;
|
||||
@@ -2096,29 +2242,6 @@ CdmResponseType CryptoSession::GetSrmVersion(uint16_t* srm_version) {
|
||||
}
|
||||
}
|
||||
|
||||
bool CryptoSession::IsSrmUpdateSupported() {
|
||||
LOGV("Checking if SRM update is supported");
|
||||
RETURN_IF_UNINITIALIZED(false);
|
||||
return WithOecReadLock("IsSrmUpdateSupported",
|
||||
[&] { return OEMCrypto_IsSRMUpdateSupported(); });
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::LoadSrm(const std::string& srm) {
|
||||
LOGV("Loading SRM");
|
||||
RETURN_IF_UNINITIALIZED(CRYPTO_SESSION_NOT_INITIALIZED);
|
||||
if (srm.empty()) {
|
||||
LOGE("SRM is empty");
|
||||
return INVALID_SRM_LIST;
|
||||
}
|
||||
|
||||
const OEMCryptoResult status = WithOecWriteLock("LoadSrm", [&] {
|
||||
return OEMCrypto_LoadSRM(reinterpret_cast<const uint8_t*>(srm.data()),
|
||||
srm.size());
|
||||
});
|
||||
|
||||
return MapOEMCryptoResult(status, LOAD_SRM_ERROR, "LoadSRM");
|
||||
}
|
||||
|
||||
bool CryptoSession::GetResourceRatingTier(uint32_t* tier) {
|
||||
LOGV("Getting resource rating tier");
|
||||
RETURN_IF_NOT_OPEN(false);
|
||||
@@ -2160,16 +2283,28 @@ bool CryptoSession::GetBuildInformation(SecurityLevel security_level,
|
||||
RETURN_IF_UNINITIALIZED(false);
|
||||
RETURN_IF_NULL(info, false);
|
||||
|
||||
const char* build_information;
|
||||
OEMCryptoResult build_information;
|
||||
std::string buf;
|
||||
size_t buf_length = 0;
|
||||
WithOecReadLock("GetBuildInformation", [&] {
|
||||
build_information = OEMCrypto_BuildInformation(security_level);
|
||||
build_information =
|
||||
OEMCrypto_BuildInformation(&buf[0], &buf_length, security_level);
|
||||
});
|
||||
if (build_information == nullptr) {
|
||||
LOGE("OEMCrypto_BuildInformation failed: Returned null");
|
||||
if (build_information == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
buf.resize(buf_length);
|
||||
WithOecReadLock("GetBuildInformation Attempt 2", [&] {
|
||||
build_information =
|
||||
OEMCrypto_BuildInformation(&buf[0], &buf_length, security_level);
|
||||
});
|
||||
}
|
||||
|
||||
if (build_information == OEMCrypto_SUCCESS) {
|
||||
*info = buf;
|
||||
} else {
|
||||
LOGE("Unexpected return value");
|
||||
return false;
|
||||
}
|
||||
|
||||
info->assign(build_information);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2892,9 +3027,9 @@ OEMCryptoResult CryptoSession::DecryptSample(
|
||||
fake_sample.buffers.input_data += length;
|
||||
AdvanceDestBuffer(&fake_sample.buffers.output_descriptor, length);
|
||||
if (cipher_mode == kCipherModeCtr) {
|
||||
AdvanceIvCtr(&fake_sample.iv,
|
||||
original_subsample.block_offset +
|
||||
original_subsample.num_bytes_encrypted);
|
||||
wvutil::AdvanceIvCtr(&fake_sample.iv,
|
||||
original_subsample.block_offset +
|
||||
original_subsample.num_bytes_encrypted);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3049,7 +3184,8 @@ OEMCryptoResult CryptoSession::LegacyDecryptInChunks(
|
||||
if (cipher_mode == kCipherModeCtr) {
|
||||
// For 'cenc', update the IV depending on how many encrypted blocks
|
||||
// we passed.
|
||||
AdvanceIvCtr(&fake_sample.iv, chunk_size + fake_subsample.block_offset);
|
||||
wvutil::AdvanceIvCtr(&fake_sample.iv,
|
||||
chunk_size + fake_subsample.block_offset);
|
||||
} else if (cipher_mode == kCipherModeCbc) {
|
||||
// For 'cbcs', use the last ciphertext block as the next IV. The last
|
||||
// block that was encrypted is probably not the last block of the
|
||||
@@ -3154,7 +3290,7 @@ template <class Func>
|
||||
auto CryptoSession::WithStaticFieldWriteLock(const char* tag, Func body)
|
||||
-> decltype(body()) {
|
||||
LOGV("Static field write lock: %s", tag);
|
||||
std::unique_lock<shared_mutex> auto_lock(static_field_mutex_);
|
||||
std::unique_lock<wvutil::shared_mutex> auto_lock(static_field_mutex_);
|
||||
return body();
|
||||
}
|
||||
|
||||
@@ -3162,7 +3298,7 @@ template <class Func>
|
||||
auto CryptoSession::WithStaticFieldReadLock(const char* tag, Func body)
|
||||
-> decltype(body()) {
|
||||
LOGV("Static field read lock: %s", tag);
|
||||
shared_lock<shared_mutex> auto_lock(static_field_mutex_);
|
||||
wvutil::shared_lock<wvutil::shared_mutex> auto_lock(static_field_mutex_);
|
||||
return body();
|
||||
}
|
||||
|
||||
@@ -3170,7 +3306,7 @@ template <class Func>
|
||||
auto CryptoSession::WithOecWriteLock(const char* tag, Func body)
|
||||
-> decltype(body()) {
|
||||
LOGV("OEMCrypto write lock: %s", tag);
|
||||
std::unique_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
|
||||
std::unique_lock<wvutil::shared_mutex> auto_lock(oem_crypto_mutex_);
|
||||
return body();
|
||||
}
|
||||
|
||||
@@ -3178,7 +3314,7 @@ template <class Func>
|
||||
auto CryptoSession::WithOecReadLock(const char* tag, Func body)
|
||||
-> decltype(body()) {
|
||||
LOGV("OEMCrypto read lock: %s", tag);
|
||||
shared_lock<shared_mutex> auto_lock(oem_crypto_mutex_);
|
||||
wvutil::shared_lock<wvutil::shared_mutex> auto_lock(oem_crypto_mutex_);
|
||||
return body();
|
||||
}
|
||||
|
||||
@@ -3186,7 +3322,7 @@ template <class Func>
|
||||
auto CryptoSession::WithOecSessionLock(const char* tag, Func body)
|
||||
-> decltype(body()) {
|
||||
LOGV("OEMCrypto session lock: %s", tag);
|
||||
shared_lock<shared_mutex> oec_auto_lock(oem_crypto_mutex_);
|
||||
wvutil::shared_lock<wvutil::shared_mutex> oec_auto_lock(oem_crypto_mutex_);
|
||||
std::unique_lock<std::mutex> session_auto_lock(oem_crypto_session_mutex_);
|
||||
return body();
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ using video_widevine_client::sdk::License;
|
||||
using video_widevine_client::sdk::License_LicenseState_ACTIVE;
|
||||
using video_widevine_client::sdk::License_LicenseState_RELEASING;
|
||||
using video_widevine_client::sdk::NameValue;
|
||||
using video_widevine_client::sdk::OemCertificate;
|
||||
using video_widevine_client::sdk::UsageInfo;
|
||||
using video_widevine_client::sdk::UsageInfo_DrmUsageCertificate;
|
||||
using video_widevine_client::sdk::UsageInfo_ProviderSession;
|
||||
@@ -45,7 +46,7 @@ using video_widevine_client::sdk::
|
||||
|
||||
// Stringify turns macro arguments into static C strings.
|
||||
// Example: STRINGIFY(this_argument) -> "this_argument"
|
||||
#define STRINGIFY(PARAM...) #PARAM
|
||||
#define STRINGIFY(PARAM) #PARAM
|
||||
|
||||
#define RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(PARAM) \
|
||||
if ((PARAM) == nullptr) { \
|
||||
@@ -129,8 +130,8 @@ bool ExtractFromDeviceCertificate(const DeviceCertificate& device_certificate,
|
||||
RETURN_FALSE_IF_NULL(certificate);
|
||||
RETURN_FALSE_IF_NULL(private_key);
|
||||
|
||||
const bool has_certificate = device_certificate.has_certificate();
|
||||
const bool has_key = device_certificate.has_wrapped_private_key();
|
||||
bool has_certificate = device_certificate.has_certificate();
|
||||
bool has_key = device_certificate.has_wrapped_private_key();
|
||||
|
||||
// If no certificate information, nothing to be done. DeviceCertificate
|
||||
// is a legacy DRM certificate
|
||||
@@ -364,7 +365,7 @@ const char* DeviceFiles::ResponseTypeToString(ResponseType type) {
|
||||
// static
|
||||
std::set<std::string> DeviceFiles::reserved_license_ids_;
|
||||
|
||||
DeviceFiles::DeviceFiles(FileSystem* file_system)
|
||||
DeviceFiles::DeviceFiles(wvutil::FileSystem* file_system)
|
||||
: file_system_(file_system),
|
||||
security_level_(kSecurityLevelUninitialized),
|
||||
initialized_(false) {}
|
||||
@@ -373,7 +374,7 @@ DeviceFiles::~DeviceFiles() {}
|
||||
|
||||
bool DeviceFiles::Init(CdmSecurityLevel security_level) {
|
||||
if (!file_system_) {
|
||||
LOGE("Invalid FileSystem given");
|
||||
LOGE("Invalid wvutil::FileSystem given");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -427,7 +428,7 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate,
|
||||
return false;
|
||||
|
||||
if (default_certificate) {
|
||||
Clock clock;
|
||||
wvutil::Clock clock;
|
||||
device_certificate->set_acquisition_time_seconds(clock.GetCurrentTime());
|
||||
}
|
||||
/* TODO(b/192430982): Renable expiration of legacy DRM certificates
|
||||
@@ -436,9 +437,9 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate,
|
||||
// stored, this is a certificate of type kCertificateLegacy.
|
||||
// The only time when a legacy certificate is stored is when it does not
|
||||
// have an expiration time. Set expiration time to 6 months +- 2 months.
|
||||
Clock clock;
|
||||
wvutil::Clock clock;
|
||||
const int64_t current_time = clock.GetCurrentTime();
|
||||
CdmRandomGenerator rng(current_time & 0xffffffff);
|
||||
wvutil::CdmRandomGenerator rng(current_time & 0xffffffff);
|
||||
|
||||
device_certificate->set_expiration_time_seconds(
|
||||
current_time + kFourMonthsInSeconds +
|
||||
@@ -537,7 +538,7 @@ DeviceFiles::CertificateState DeviceFiles::RetrieveCertificate(
|
||||
&creation_time_seconds, &expiration_time_seconds))
|
||||
return kCertificateInvalid;
|
||||
|
||||
Clock clock;
|
||||
wvutil::Clock clock;
|
||||
const int64_t current_time = clock.GetCurrentTime();
|
||||
|
||||
switch (certificate_type) {
|
||||
@@ -670,6 +671,126 @@ bool DeviceFiles::RemoveCertificate() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveOemCertificate() {
|
||||
RETURN_FALSE_IF_UNINITIALIZED()
|
||||
std::string certificate_file_name;
|
||||
if (GetOemCertificateFileName(&certificate_file_name)) {
|
||||
return RemoveFile(certificate_file_name);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreOemCertificate(const std::string& certificate,
|
||||
const CryptoWrappedKey& private_key) {
|
||||
RETURN_FALSE_IF_UNINITIALIZED();
|
||||
if (certificate.empty()) {
|
||||
LOGE("Missing certificate information");
|
||||
return false;
|
||||
}
|
||||
if (!private_key.IsValid()) {
|
||||
LOGE("Private key is invalid");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string certificate_file_name;
|
||||
if (!GetOemCertificateFileName(&certificate_file_name)) {
|
||||
LOGE("Unable to get certificate file name");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Fill in file information
|
||||
video_widevine_client::sdk::File file;
|
||||
file.set_type(video_widevine_client::sdk::File::OEM_CERTIFICATE);
|
||||
file.set_version(video_widevine_client::sdk::File::VERSION_1);
|
||||
OemCertificate* oem_certificate = file.mutable_oem_certificate();
|
||||
oem_certificate->set_certificate(certificate);
|
||||
oem_certificate->set_wrapped_private_key(private_key.key());
|
||||
switch (private_key.type()) {
|
||||
case wvcdm::CryptoWrappedKey::kRsa:
|
||||
oem_certificate->set_key_type(OemCertificate::RSA);
|
||||
break;
|
||||
case wvcdm::CryptoWrappedKey::kEcc:
|
||||
oem_certificate->set_key_type(OemCertificate::ECC);
|
||||
break;
|
||||
case wvcdm::CryptoWrappedKey::kUninitialized:
|
||||
default:
|
||||
LOGE("Unexpected key type: %d", private_key.type());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string serialized_file;
|
||||
file.SerializeToString(&serialized_file);
|
||||
return StoreFileWithHash(certificate_file_name, serialized_file) == kNoError;
|
||||
}
|
||||
|
||||
DeviceFiles::CertificateState DeviceFiles::RetrieveOemCertificate(
|
||||
std::string* certificate, CryptoWrappedKey* wrapped_private_key) {
|
||||
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_UNINITIALIZED();
|
||||
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(certificate);
|
||||
RETURN_CERTIFICATE_STATE_CANNOT_HANDLE_IF_NULL(wrapped_private_key);
|
||||
|
||||
std::string certificate_file_name;
|
||||
if (!GetOemCertificateFileName(&certificate_file_name)) {
|
||||
LOGW("Unable to find certificate file name");
|
||||
return kCannotHandle;
|
||||
}
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (RetrieveHashedFile(certificate_file_name, &file) != kNoError) {
|
||||
LOGW("Unable to retrieve certificate file");
|
||||
return kCertificateNotFound;
|
||||
}
|
||||
if (file.type() != video_widevine_client::sdk::File::OEM_CERTIFICATE) {
|
||||
LOGE("Certificate file is of incorrect file type: type = %d",
|
||||
static_cast<int>(file.type()));
|
||||
return kCertificateInvalid;
|
||||
}
|
||||
if (file.version() != video_widevine_client::sdk::File::VERSION_1) {
|
||||
LOGE("Certificate file is of incorrect file version: version = %d",
|
||||
static_cast<int>(file.version()));
|
||||
return kCertificateInvalid;
|
||||
}
|
||||
if (!file.has_oem_certificate()) {
|
||||
LOGE("Certificate not present");
|
||||
return kCertificateInvalid;
|
||||
}
|
||||
|
||||
const OemCertificate& oem_certificate = file.oem_certificate();
|
||||
if (oem_certificate.certificate().empty() ||
|
||||
oem_certificate.wrapped_private_key().empty()) {
|
||||
LOGE("Empty certificate or private key");
|
||||
return kCertificateInvalid;
|
||||
}
|
||||
|
||||
*certificate = oem_certificate.certificate();
|
||||
wrapped_private_key->Clear();
|
||||
wrapped_private_key->set_key(oem_certificate.wrapped_private_key());
|
||||
switch (oem_certificate.key_type()) {
|
||||
case OemCertificate::RSA:
|
||||
wrapped_private_key->set_type(wvcdm::CryptoWrappedKey::kRsa);
|
||||
break;
|
||||
case OemCertificate::ECC:
|
||||
wrapped_private_key->set_type(wvcdm::CryptoWrappedKey::kEcc);
|
||||
break;
|
||||
default:
|
||||
LOGW("Unknown key type, defaulting to RSA: type = %d",
|
||||
oem_certificate.key_type());
|
||||
wrapped_private_key->set_type(wvcdm::CryptoWrappedKey::kRsa);
|
||||
break;
|
||||
}
|
||||
return kCertificateValid;
|
||||
}
|
||||
|
||||
bool DeviceFiles::HasOemCertificate() {
|
||||
RETURN_FALSE_IF_UNINITIALIZED();
|
||||
|
||||
std::string certificate_file_name;
|
||||
if (!GetOemCertificateFileName(&certificate_file_name)) {
|
||||
return false;
|
||||
}
|
||||
return FileExists(certificate_file_name);
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreLicense(const CdmLicenseData& license_data,
|
||||
ResponseType* result) {
|
||||
RETURN_FALSE_IF_NULL(result);
|
||||
@@ -1015,7 +1136,7 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& usage_info_file_name,
|
||||
|
||||
if (!found) {
|
||||
LOGE("Unable to find provider session token: pst = %s",
|
||||
b2a_hex(provider_session_token).c_str());
|
||||
wvutil::b2a_hex(provider_session_token).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1812,8 +1933,8 @@ DeviceFiles::ResponseType DeviceFiles::StoreFileRaw(
|
||||
|
||||
path += name;
|
||||
|
||||
auto file =
|
||||
file_system_->Open(path, FileSystem::kCreate | FileSystem::kTruncate);
|
||||
auto file = file_system_->Open(
|
||||
path, wvutil::FileSystem::kCreate | wvutil::FileSystem::kTruncate);
|
||||
if (!file) {
|
||||
LOGE("Failed to open file: path = %s", path.c_str());
|
||||
return kFileOpenFailed;
|
||||
@@ -1871,7 +1992,7 @@ DeviceFiles::ResponseType DeviceFiles::RetrieveHashedFile(
|
||||
return kInvalidFileSize;
|
||||
}
|
||||
|
||||
auto file = file_system_->Open(path, FileSystem::kReadOnly);
|
||||
auto file = file_system_->Open(path, wvutil::FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
return kFileOpenFailed;
|
||||
}
|
||||
@@ -1970,23 +2091,30 @@ ssize_t DeviceFiles::GetFileSize(const std::string& name) {
|
||||
}
|
||||
|
||||
bool DeviceFiles::GetCertificateFileName(CertificateType certificate_type,
|
||||
std::string* file_name) {
|
||||
RETURN_FALSE_IF_NULL(file_name);
|
||||
std::string* certificate_file_name) {
|
||||
RETURN_FALSE_IF_NULL(certificate_file_name);
|
||||
switch (certificate_type) {
|
||||
case kCertificateDefault:
|
||||
*file_name = kCertificateFileName;
|
||||
*certificate_file_name = wvutil::kCertificateFileName;
|
||||
return true;
|
||||
case kCertificateLegacy:
|
||||
*file_name = kLegacyCertificateFileName;
|
||||
*certificate_file_name = wvutil::kLegacyCertificateFileName;
|
||||
return true;
|
||||
case kCertificateAtsc:
|
||||
*file_name = kAtscCertificateFileName;
|
||||
*certificate_file_name = wvutil::kAtscCertificateFileName;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceFiles::GetOemCertificateFileName(
|
||||
std::string* certificate_file_name) {
|
||||
RETURN_FALSE_IF_NULL(certificate_file_name);
|
||||
*certificate_file_name = wvutil::kOemCertificateFileName;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetUsageTableFileName() { return kUsageTableFileName; }
|
||||
|
||||
std::string DeviceFiles::GetHlsAttributesFileNameExtension() {
|
||||
@@ -2008,7 +2136,7 @@ std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) {
|
||||
std::string DeviceFiles::GetOkpInfoFileName() { return kOkpInfoFileName; }
|
||||
|
||||
std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) {
|
||||
return Base64SafeEncode(Md5Hash(input));
|
||||
return wvutil::Base64SafeEncode(Md5Hash(input));
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -20,6 +20,17 @@ message NameValue {
|
||||
optional string value = 2;
|
||||
}
|
||||
|
||||
message OemCertificate {
|
||||
enum PrivateKeyType {
|
||||
RSA = 0;
|
||||
ECC = 1;
|
||||
}
|
||||
optional bytes certificate = 1;
|
||||
optional bytes wrapped_private_key = 2;
|
||||
optional PrivateKeyType key_type = 3 [default = RSA];
|
||||
}
|
||||
|
||||
// DRM certificate.
|
||||
message DeviceCertificate {
|
||||
enum PrivateKeyType {
|
||||
RSA = 0;
|
||||
@@ -173,6 +184,7 @@ message File {
|
||||
HLS_ATTRIBUTES = 4;
|
||||
USAGE_TABLE_INFO = 5;
|
||||
OKP_INFO = 6;
|
||||
OEM_CERTIFICATE = 7;
|
||||
}
|
||||
|
||||
enum FileVersion { VERSION_1 = 1; }
|
||||
@@ -185,6 +197,7 @@ message File {
|
||||
optional HlsAttributes hls_attributes = 6;
|
||||
optional UsageTableInfo usage_table_info = 7;
|
||||
optional OtaKeyboxProvisioningInfo okp_info = 8;
|
||||
optional OemCertificate oem_certificate = 9;
|
||||
}
|
||||
|
||||
message HashedFile {
|
||||
|
||||
@@ -9,9 +9,25 @@
|
||||
#include "log.h"
|
||||
|
||||
namespace wvcdm {
|
||||
namespace {
|
||||
constexpr int kInvalidKeySessionId = 0;
|
||||
} // namespace
|
||||
|
||||
EntitlementKeySession::EntitlementKeySession(CryptoSessionId oec_session_id,
|
||||
metrics::CryptoMetrics* metrics)
|
||||
: ContentKeySession(oec_session_id, metrics), entitled_keys_() {}
|
||||
: ContentKeySession(oec_session_id, metrics),
|
||||
key_session_id_(kInvalidKeySessionId) {}
|
||||
|
||||
EntitlementKeySession::~EntitlementKeySession() {
|
||||
if (key_session_id_ != kInvalidKeySessionId) {
|
||||
OEMCryptoResult result =
|
||||
OEMCrypto_RemoveEntitledKeySession(key_session_id_);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
LOGW("OEMCrypto_RemoveEntitledKeySession failed: status = %d",
|
||||
static_cast<int>(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OEMCryptoResult EntitlementKeySession::LoadKeys(
|
||||
const std::string& message, const std::string& signature,
|
||||
@@ -49,6 +65,23 @@ OEMCryptoResult EntitlementKeySession::SelectKey(const std::string& key_id,
|
||||
return OEMCrypto_ERROR_NO_CONTENT_KEY;
|
||||
}
|
||||
|
||||
OEMCryptoResult result;
|
||||
// Entitled key session not created. Create one now.
|
||||
if (key_session_id_ == kInvalidKeySessionId) {
|
||||
result =
|
||||
OEMCrypto_CreateEntitledKeySession(oec_session_id_, &key_session_id_);
|
||||
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
LOGW("Entitled key session is not supported.");
|
||||
// Use oec session id as the key session id for backward compatibility.
|
||||
key_session_id_ = oec_session_id_;
|
||||
} else if (result != OEMCrypto_SUCCESS ||
|
||||
key_session_id_ == kInvalidKeySessionId) {
|
||||
LOGE("OEMCrypto_CreateEntitledKeySession failed: status = %d",
|
||||
static_cast<int>(result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
CryptoKey entitled_content_key = entitled_keys_[key_id];
|
||||
if (current_loaded_content_keys_[entitled_content_key.entitlement_key_id()] !=
|
||||
key_id) {
|
||||
@@ -61,10 +94,9 @@ OEMCryptoResult EntitlementKeySession::SelectKey(const std::string& key_id,
|
||||
std::string message;
|
||||
OEMCrypto_EntitledContentKeyObject entitled_key =
|
||||
MakeOecEntitledKey(entitled_content_key, message);
|
||||
OEMCryptoResult result = OEMCrypto_SUCCESS;
|
||||
M_TIME(
|
||||
result = OEMCrypto_LoadEntitledContentKeys(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
key_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), 1, &entitled_key),
|
||||
metrics_, oemcrypto_load_entitled_keys_, result);
|
||||
if (result != OEMCrypto_SUCCESS) {
|
||||
@@ -76,7 +108,28 @@ OEMCryptoResult EntitlementKeySession::SelectKey(const std::string& key_id,
|
||||
current_loaded_content_keys_[entitled_content_key.entitlement_key_id()] =
|
||||
key_id;
|
||||
}
|
||||
return ContentKeySession::SelectKey(key_id, cipher_mode);
|
||||
|
||||
M_TIME(result = OEMCrypto_SelectKey(
|
||||
key_session_id_, reinterpret_cast<const uint8_t*>(key_id.data()),
|
||||
key_id.size(), ToOEMCryptoCipherMode(cipher_mode)),
|
||||
metrics_, oemcrypto_select_key_, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult EntitlementKeySession::Decrypt(
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) {
|
||||
size_t total_size = 0;
|
||||
for (size_t i = 0; i < samples_length; ++i) {
|
||||
total_size += samples[i].buffers.input_data_length;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
M_TIME(sts = OEMCrypto_DecryptCENC(key_session_id_, samples, samples_length,
|
||||
&pattern),
|
||||
metrics_, oemcrypto_decrypt_cenc_, sts,
|
||||
metrics::Pow2Bucket(total_size));
|
||||
return sts;
|
||||
}
|
||||
|
||||
OEMCrypto_EntitledContentKeyObject EntitlementKeySession::MakeOecEntitledKey(
|
||||
|
||||
@@ -452,7 +452,7 @@ bool InitializationData::ConstructWidevineInitData(
|
||||
}
|
||||
|
||||
std::vector<uint8_t> json_init_data =
|
||||
Base64Decode(uri.substr(pos + kBase64String.size()));
|
||||
wvutil::Base64Decode(uri.substr(pos + kBase64String.size()));
|
||||
if (json_init_data.size() == 0) {
|
||||
LOGV("Base64 decode of json data failed");
|
||||
return false;
|
||||
@@ -519,7 +519,7 @@ bool InitializationData::ConstructWidevineInitData(
|
||||
std::string base64_content_id(json_string, tokens[i].start,
|
||||
tokens[i].end - tokens[i].start);
|
||||
std::vector<uint8_t> content_id_data =
|
||||
Base64Decode(base64_content_id);
|
||||
wvutil::Base64Decode(base64_content_id);
|
||||
content_id.assign(reinterpret_cast<const char*>(&content_id_data[0]),
|
||||
content_id_data.size());
|
||||
}
|
||||
@@ -529,7 +529,7 @@ bool InitializationData::ConstructWidevineInitData(
|
||||
if (tokens[i].type == JSMN_ARRAY) {
|
||||
number_of_key_ids = tokens[i].size;
|
||||
} else if (tokens[i].type == JSMN_STRING) {
|
||||
std::string key_id(a2bs_hex(json_string.substr(
|
||||
std::string key_id(wvutil::a2bs_hex(json_string.substr(
|
||||
tokens[i].start, tokens[i].end - tokens[i].start)));
|
||||
if (key_id.size() == 16) key_ids.push_back(key_id);
|
||||
--number_of_key_ids;
|
||||
@@ -600,7 +600,7 @@ bool InitializationData::ExtractHexAttribute(const std::string& attribute_list,
|
||||
for (size_t i = 2; i < val.size(); ++i) {
|
||||
if (!isxdigit(val[i])) return false;
|
||||
}
|
||||
*value = a2b_hex(val.substr(2, val.size() - 2));
|
||||
*value = wvutil::a2b_hex(val.substr(2, val.size() - 2));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -695,7 +695,7 @@ void InitializationData::DumpToLogs() const {
|
||||
|
||||
video_widevine::WidevinePsshData pssh;
|
||||
if (!pssh.ParseFromString(data())) {
|
||||
LOGD("InitData: invalid pssh: %s", b2a_hex(data()).c_str());
|
||||
LOGD("InitData: invalid pssh: %s", wvutil::b2a_hex(data()).c_str());
|
||||
return;
|
||||
}
|
||||
if (pssh.has_content_id()) {
|
||||
@@ -729,14 +729,15 @@ void InitializationData::DumpToLogs() const {
|
||||
LOGD("InitData: Key Sequence %u", pssh.key_sequence());
|
||||
|
||||
for (int i = 0; i < pssh.key_ids_size(); i++) {
|
||||
LOGD("InitData: key_id %d: %s", i, b2a_hex(pssh.key_ids(i)).c_str());
|
||||
LOGD("InitData: key_id %d: %s", i,
|
||||
wvutil::b2a_hex(pssh.key_ids(i)).c_str());
|
||||
}
|
||||
|
||||
for (int i = 0; i < pssh.entitled_keys_size(); i++) {
|
||||
video_widevine::WidevinePsshData_EntitledKey key = pssh.entitled_keys(i);
|
||||
LOGD("InitData: entitlement_key_id %d: %s -> %s", i,
|
||||
b2a_hex(key.entitlement_key_id()).c_str(),
|
||||
b2a_hex(key.key_id()).c_str());
|
||||
wvutil::b2a_hex(key.entitlement_key_id()).c_str(),
|
||||
wvutil::b2a_hex(key.key_id()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,10 +182,10 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
is_offline_(false),
|
||||
supports_core_messages_(true),
|
||||
use_privacy_mode_(false),
|
||||
clock_(new Clock()),
|
||||
clock_(new wvutil::Clock()),
|
||||
license_key_type_(kLicenseKeyTypeContent) {}
|
||||
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id, Clock* clock)
|
||||
CdmLicense::CdmLicense(const CdmSessionId& session_id, wvutil::Clock* clock)
|
||||
: crypto_session_(nullptr),
|
||||
policy_engine_(nullptr),
|
||||
session_id_(session_id),
|
||||
@@ -606,7 +606,9 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
mac_key_iv.assign(license.key(i).iv());
|
||||
|
||||
// Strip off PKCS#5 padding
|
||||
mac_keys.assign(license.key(i).key().data(), kLicenseMacKeySize);
|
||||
mac_keys.assign(
|
||||
license.key(i).key().data(),
|
||||
std::min(kLicenseMacKeySize, license.key(i).key().size()));
|
||||
}
|
||||
}
|
||||
if (license.policy().can_renew() ||
|
||||
@@ -641,18 +643,6 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
if (license.has_provider_client_token())
|
||||
provider_client_token_ = license.provider_client_token();
|
||||
|
||||
if (license.has_srm_update()) {
|
||||
status = crypto_session_->LoadSrm(license.srm_update());
|
||||
switch (status) {
|
||||
case NO_ERROR:
|
||||
break;
|
||||
case SYSTEM_INVALIDATED_ERROR:
|
||||
return status;
|
||||
default:
|
||||
break; // Ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (license.id().type() == video_widevine::OFFLINE &&
|
||||
license.policy().can_persist())
|
||||
is_offline_ = true;
|
||||
@@ -672,6 +662,11 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
renew_with_client_id_ = license.policy().always_include_client_id();
|
||||
}
|
||||
|
||||
// If the field is not set, it will default to false.
|
||||
status =
|
||||
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(is_restore, signed_message,
|
||||
@@ -764,6 +759,11 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
}
|
||||
|
||||
CdmResponseType status;
|
||||
// If the field is not set, it will default to false.
|
||||
status =
|
||||
crypto_session_->UseSecondaryKey(signed_response.using_secondary_key());
|
||||
if (status != NO_ERROR) return status;
|
||||
|
||||
if (supports_core_messages()) {
|
||||
status =
|
||||
crypto_session_->LoadRenewal(signed_message, core_message, signature);
|
||||
|
||||
@@ -117,6 +117,17 @@ message ProxyInfo {
|
||||
|
||||
message License {
|
||||
message Policy {
|
||||
// Client-side watermarking restrictions for the license.
|
||||
enum WatermarkingControl {
|
||||
// Watermarking may or may not be used, provider does not care.
|
||||
WATERMARKING_CONTROL_UNSPECIFIED = 0;
|
||||
// Watermarking must not be used. The device must disable watermarking
|
||||
// if it supports it.
|
||||
WATERMARKING_FORBIDDEN = 1;
|
||||
// Watermarking is required if the device supports it.
|
||||
WATERMARKING_REQUIRED = 2;
|
||||
}
|
||||
|
||||
// Indicates that playback of the content is allowed.
|
||||
optional bool can_play = 1 [default = false];
|
||||
|
||||
@@ -182,6 +193,10 @@ message License {
|
||||
// soft_enforce_playback_duration must be true. Otherwise, subsequent
|
||||
// playbacks will not be allowed once rental duration expires. Optional.
|
||||
optional bool soft_enforce_rental_duration = 15 [default = true];
|
||||
|
||||
// Optional requirement to indicate watermarking is allowed.
|
||||
optional WatermarkingControl watermarking_control = 16
|
||||
[default = WATERMARKING_CONTROL_UNSPECIFIED];
|
||||
}
|
||||
|
||||
message KeyContainer {
|
||||
@@ -644,6 +659,7 @@ message ProvisioningRequest {
|
||||
message AndroidAttestationOtaKeyboxRequest {
|
||||
// The request contains custom serialized and signed data for the
|
||||
// Android Attestation OTA request.
|
||||
// see: go/wv_android_ota
|
||||
optional bytes ota_request = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,10 @@ typedef OEMCryptoResult (*L1_LoadEntitledContentKeys_t)(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
size_t key_array_length,
|
||||
const OEMCrypto_EntitledContentKeyObject* key_array);
|
||||
typedef OEMCryptoResult (*L1_LoadEntitledContentKeys_V16_t)(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
size_t key_array_length,
|
||||
const OEMCrypto_EntitledContentKeyObject_V16* key_array);
|
||||
typedef OEMCryptoResult (*L1_LoadEntitledContentKeys_V14_t)(
|
||||
OEMCrypto_SESSION session, size_t num_keys,
|
||||
const OEMCrypto_EntitledContentKeyObject_V14* key_array);
|
||||
@@ -220,7 +224,7 @@ typedef OEMCryptoResult (*L1_DeriveKeysFromSessionKey_t)(
|
||||
size_t enc_key_context_length);
|
||||
typedef uint32_t (*L1_APIVersion_t)();
|
||||
typedef uint8_t (*L1_SecurityPatchLevel_t)();
|
||||
typedef const char* (*L1_SecurityLevel_t)();
|
||||
typedef const char* (*L1_SecurityLevel_V16_t)();
|
||||
typedef OEMCryptoResult (*L1_GetHDCPCapability_V9_t)(uint8_t* current,
|
||||
uint8_t* maximum);
|
||||
typedef OEMCryptoResult (*L1_GetHDCPCapability_t)(
|
||||
@@ -297,7 +301,7 @@ typedef OEMCryptoResult (*L1_ShrinkUsageTableHeader_t)(
|
||||
typedef OEMCryptoResult (*L1_MoveEntry_t)(OEMCrypto_SESSION session,
|
||||
uint32_t new_index);
|
||||
typedef uint32_t (*L1_GetAnalogOutputFlags_t)(void);
|
||||
typedef const char* (*L1_BuildInformation_t)(void);
|
||||
typedef const char* (*L1_BuildInformation_V16_t)(void);
|
||||
typedef uint32_t (*L1_ResourceRatingTier_t)(void);
|
||||
typedef uint32_t (*L1_SupportsDecryptHash_t)(void);
|
||||
typedef OEMCryptoResult (*L1_SetDecryptHash_t)(OEMCrypto_SESSION session,
|
||||
@@ -331,6 +335,40 @@ typedef OEMCryptoResult (*L1_ProcessOTAKeybox_t)(OEMCrypto_SESSION session,
|
||||
const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
uint32_t use_test_key);
|
||||
typedef OEMCryptoResult (*L1_CreateEntitledKeySession_t)(
|
||||
OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session);
|
||||
typedef OEMCryptoResult (*L1_RemoveEntitledKeySession_t)(
|
||||
OEMCrypto_SESSION key_session);
|
||||
typedef OEMCryptoResult (*L1_GetBootCertificateChain_t)(
|
||||
uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature,
|
||||
size_t* additional_signature_size);
|
||||
typedef OEMCryptoResult (*L1_GenerateCertificateKeyPair_t)(
|
||||
OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_size,
|
||||
uint8_t* public_key_signature, size_t* public_key_signature_size,
|
||||
uint8_t* wrapped_private_key, size_t* wrapped_private_key_size,
|
||||
OEMCrypto_PrivateKeyType* key_type);
|
||||
typedef OEMCryptoResult (*L1_InstallOemPrivateKey_t)(
|
||||
OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type,
|
||||
const uint8_t* wrapped_private_key, size_t wrapped_private_key_length);
|
||||
typedef OEMCryptoResult (*L1_ReassociateEntitledKeySession_t)(
|
||||
OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session);
|
||||
typedef OEMCryptoResult (*L1_LoadCasECMKeys_t)(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const OEMCrypto_EntitledContentKeyObject* even_key,
|
||||
const OEMCrypto_EntitledContentKeyObject* odd_key);
|
||||
typedef OEMCryptoResult (*L1_ProductionReady_t)();
|
||||
typedef OEMCryptoResult (*L1_Idle_t)(OEMCrypto_IdleState state,
|
||||
uint32_t os_specific_code);
|
||||
typedef OEMCryptoResult (*L1_Wake_t)();
|
||||
typedef OEMCryptoResult (*L1_BuildInformation_t)(char* buffer,
|
||||
size_t* buffer_length);
|
||||
typedef OEMCrypto_Security_Level (*L1_SecurityLevel_t)();
|
||||
typedef OEMCryptoResult (*L1_ReuseUsageEntry_t)(OEMCrypto_SESSION session,
|
||||
uint32_t usage_entry_number);
|
||||
typedef OEMCryptoResult (*L1_GetDTCP2Capability_t)(
|
||||
OEMCrypto_DTCP2_Capability* capability);
|
||||
typedef OEMCrypto_WatermarkingSupport (*L1_GetWatermarkingSupport_t)();
|
||||
|
||||
struct FunctionPointers {
|
||||
wvcdm::CdmSecurityLevel security_level;
|
||||
uint32_t version;
|
||||
@@ -349,6 +387,7 @@ struct FunctionPointers {
|
||||
L1_LoadLicense_t LoadLicense;
|
||||
L1_LoadKeys_t LoadKeys;
|
||||
L1_LoadEntitledContentKeys_t LoadEntitledContentKeys;
|
||||
L1_LoadEntitledContentKeys_V16_t LoadEntitledContentKeys_V16;
|
||||
L1_LoadEntitledContentKeys_V14_t LoadEntitledContentKeys_V14;
|
||||
L1_LoadRenewal_t LoadRenewal;
|
||||
L1_RefreshKeys_t RefreshKeys;
|
||||
@@ -374,7 +413,7 @@ struct FunctionPointers {
|
||||
L1_DeriveKeysFromSessionKey_t DeriveKeysFromSessionKey;
|
||||
L1_APIVersion_t APIVersion;
|
||||
L1_SecurityPatchLevel_t SecurityPatchLevel;
|
||||
L1_SecurityLevel_t SecurityLevel;
|
||||
L1_SecurityLevel_V16_t SecurityLevel_V16;
|
||||
L1_GetHDCPCapability_t GetHDCPCapability;
|
||||
L1_SupportsUsageTable_t SupportsUsageTable;
|
||||
L1_IsAntiRollbackHwPresent_t IsAntiRollbackHwPresent;
|
||||
@@ -405,7 +444,7 @@ struct FunctionPointers {
|
||||
L1_ShrinkUsageTableHeader_t ShrinkUsageTableHeader;
|
||||
L1_MoveEntry_t MoveEntry;
|
||||
L1_GetAnalogOutputFlags_t GetAnalogOutputFlags;
|
||||
L1_BuildInformation_t BuildInformation;
|
||||
L1_BuildInformation_V16_t BuildInformation_V16;
|
||||
L1_ResourceRatingTier_t ResourceRatingTier;
|
||||
L1_SupportsDecryptHash_t SupportsDecryptHash;
|
||||
L1_SetDecryptHash_t SetDecryptHash;
|
||||
@@ -416,6 +455,21 @@ struct FunctionPointers {
|
||||
L1_LoadProvisioning_t LoadProvisioning;
|
||||
L1_MinorAPIVersion_t MinorAPIVersion;
|
||||
L1_OPK_SerializationVersion_t OPK_SerializationVersion;
|
||||
L1_CreateEntitledKeySession_t CreateEntitledKeySession;
|
||||
L1_RemoveEntitledKeySession_t RemoveEntitledKeySession;
|
||||
L1_GetBootCertificateChain_t GetBootCertificateChain;
|
||||
L1_GenerateCertificateKeyPair_t GenerateCertificateKeyPair;
|
||||
L1_InstallOemPrivateKey_t InstallOemPrivateKey;
|
||||
L1_ReassociateEntitledKeySession_t ReassociateEntitledKeySession;
|
||||
L1_LoadCasECMKeys_t LoadCasECMKeys;
|
||||
L1_ProductionReady_t ProductionReady;
|
||||
L1_Idle_t Idle;
|
||||
L1_Wake_t Wake;
|
||||
L1_SecurityLevel_t SecurityLevel;
|
||||
L1_BuildInformation_t BuildInformation;
|
||||
L1_ReuseUsageEntry_t ReuseUsageEntry;
|
||||
L1_GetDTCP2Capability_t GetDTCP2Capability;
|
||||
L1_GetWatermarkingSupport_t GetWatermarkingSupport;
|
||||
|
||||
L1_LoadKeys_V8_t LoadKeys_V8;
|
||||
L1_GenerateRSASignature_V8_t GenerateRSASignature_V8;
|
||||
@@ -452,7 +506,7 @@ class WatchDog {
|
||||
status_ = OEMCrypto_SUCCESS;
|
||||
gave_up_ = false;
|
||||
sandbox_id_ = sandbox_id;
|
||||
uid_ = wvcdm::GetIpcCallingUid();
|
||||
uid_ = wvutil::GetIpcCallingUid();
|
||||
}
|
||||
|
||||
// Deleted by either thread.
|
||||
@@ -467,7 +521,7 @@ class WatchDog {
|
||||
// Function called by new worker thread.
|
||||
static void RunWatchDog(void* watcher) {
|
||||
WatchDog* dog = reinterpret_cast<WatchDog*>(watcher);
|
||||
wvcdm::SetLoggingUid(dog->uid_);
|
||||
wvutil::SetLoggingUid(dog->uid_);
|
||||
dog->DoInit();
|
||||
dog->SignalDoneAndCleanUp();
|
||||
}
|
||||
@@ -492,7 +546,7 @@ class WatchDog {
|
||||
// Check to see if the failure file was created before that last abort.
|
||||
void CheckForPreviousFailure(
|
||||
wvcdm::metrics::OemCryptoDynamicAdapterMetrics* metrics) {
|
||||
wvcdm::FileSystem file_system;
|
||||
wvutil::FileSystem file_system;
|
||||
std::string filename = FailureFilename();
|
||||
if (!file_system.Exists(filename)) return;
|
||||
auto file = file_system.Open(filename, file_system.kReadOnly);
|
||||
@@ -513,7 +567,7 @@ class WatchDog {
|
||||
|
||||
// Save the failure file before we abort.
|
||||
void SaveFailureInformation() {
|
||||
wvcdm::FileSystem file_system;
|
||||
wvutil::FileSystem file_system;
|
||||
std::string filename = FailureFilename();
|
||||
LOGD("failure filename = %s", filename.c_str());
|
||||
auto file =
|
||||
@@ -659,7 +713,7 @@ std::string GetAllowTestKeyboxFile() {
|
||||
|
||||
uint32_t GetDebugIgnoreKeyboxCount() {
|
||||
const std::string filename = GetIgnoreCountFile();
|
||||
wvcdm::FileSystem file_system;
|
||||
wvutil::FileSystem file_system;
|
||||
if (!file_system.Exists(filename)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -690,7 +744,7 @@ uint32_t GetDebugIgnoreKeyboxCount() {
|
||||
|
||||
OEMCryptoResult SetDebugIgnoreKeyboxCount(uint32_t count) {
|
||||
const std::string filename = GetIgnoreCountFile();
|
||||
wvcdm::FileSystem file_system;
|
||||
wvutil::FileSystem file_system;
|
||||
auto file =
|
||||
file_system.Open(filename, file_system.kCreate | file_system.kTruncate);
|
||||
if (!file) {
|
||||
@@ -711,7 +765,7 @@ OEMCryptoResult SetDebugIgnoreKeyboxCount(uint32_t count) {
|
||||
|
||||
bool GetAllowTestKeybox() {
|
||||
const std::string filename = GetAllowTestKeyboxFile();
|
||||
wvcdm::FileSystem file_system;
|
||||
wvutil::FileSystem file_system;
|
||||
if (!file_system.Exists(filename)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -733,7 +787,7 @@ bool GetAllowTestKeybox() {
|
||||
|
||||
OEMCryptoResult SetAllowTestKeybox(bool allow) {
|
||||
const std::string filename = GetAllowTestKeyboxFile();
|
||||
wvcdm::FileSystem file_system;
|
||||
wvutil::FileSystem file_system;
|
||||
auto file =
|
||||
file_system.Open(filename, file_system.kCreate | file_system.kTruncate);
|
||||
if (!file) {
|
||||
@@ -758,7 +812,7 @@ struct LevelSession {
|
||||
// For backwards compatibility, we need to remember the session's nonce
|
||||
// so that we can pass it to the ODK library.
|
||||
uint32_t nonce;
|
||||
LevelSession() : fcn(0), session(0), nonce(0) {}
|
||||
LevelSession() : fcn(nullptr), session(0), nonce(0) {}
|
||||
};
|
||||
|
||||
#define QUOTE_DEFINE(A) #A
|
||||
@@ -835,8 +889,15 @@ class Adapter {
|
||||
watcher->CheckForPreviousFailure(&metrics);
|
||||
watcher->StartThread();
|
||||
if (level3_.BuildInformation) {
|
||||
LOGI("Level 3 Build Info (v%d): %s", level3_.version,
|
||||
level3_.BuildInformation());
|
||||
OEMCryptoResult build_information;
|
||||
std::string buf;
|
||||
size_t buf_length = 0;
|
||||
build_information = level3_.BuildInformation(&buf[0], &buf_length);
|
||||
if (build_information == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
buf.resize(buf_length);
|
||||
build_information = level3_.BuildInformation(&buf[0], &buf_length);
|
||||
}
|
||||
LOGI("Level 3 Build Info (v%d): %s", level3_.version, buf.c_str());
|
||||
}
|
||||
OEMCryptoResult result = watcher->WaitForStatusAndCleanUp(&metrics);
|
||||
if (Level3_IsInApp()) {
|
||||
@@ -871,8 +932,15 @@ class Adapter {
|
||||
if (LoadLevel1(&metrics)) {
|
||||
LOGD("OEMCrypto_Initialize Level 1 success. I will use level 1.");
|
||||
if (level1_.BuildInformation) {
|
||||
LOGI("Level 1 Build Info (v%d): %s", level1_.version,
|
||||
level1_.BuildInformation());
|
||||
OEMCryptoResult build_information;
|
||||
std::string buf;
|
||||
size_t buf_length = 0;
|
||||
build_information = level1_.BuildInformation(&buf[0], &buf_length);
|
||||
if (build_information == OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
buf.resize(buf_length);
|
||||
build_information = level1_.BuildInformation(&buf[0], &buf_length);
|
||||
}
|
||||
LOGI("Level 1 Build Info (v%d): %s", level1_.version, buf.c_str());
|
||||
}
|
||||
} else {
|
||||
level1_failed_ = true;
|
||||
@@ -916,7 +984,7 @@ class Adapter {
|
||||
}
|
||||
level1_valid_ = true;
|
||||
const uint32_t kMinimumVersion = 8;
|
||||
const uint32_t kMaximumVersion = 16;
|
||||
const uint32_t kMaximumVersion = 17;
|
||||
level1_.version = kMinimumVersion;
|
||||
LOOKUP_ALL(8, Initialize, OEMCrypto_Initialize);
|
||||
LOOKUP_ALL(8, APIVersion, OEMCrypto_APIVersion);
|
||||
@@ -990,7 +1058,7 @@ class Adapter {
|
||||
LOOKUP( 9, 9, GetHDCPCapability_V9, OEMCrypto_GetHDCPCapability_V9);
|
||||
LOOKUP_ALL(10, GetHDCPCapability, OEMCrypto_GetHDCPCapability);
|
||||
LOOKUP_ALL(14, GetAnalogOutputFlags, OEMCrypto_GetAnalogOutputFlags);
|
||||
LOOKUP_ALL(15, BuildInformation, OEMCrypto_BuildInformation);
|
||||
LOOKUP_ALL(15, BuildInformation_V16, OEMCrypto_BuildInformation_V16);
|
||||
LOOKUP_ALL(15, ResourceRatingTier, OEMCrypto_ResourceRatingTier);
|
||||
LOOKUP_ALL( 8, GetKeyData, OEMCrypto_GetKeyData);
|
||||
LOOKUP_ALL(10, GetMaxNumberOfSessions, OEMCrypto_GetMaxNumberOfSessions);
|
||||
@@ -1003,7 +1071,7 @@ class Adapter {
|
||||
LOOKUP_ALL( 8, InstallKeyboxOrOEMCert, OEMCrypto_InstallKeyboxOrOEMCert);
|
||||
LOOKUP_ALL(10, IsAntiRollbackHwPresent, OEMCrypto_IsAntiRollbackHwPresent);
|
||||
LOOKUP_ALL( 8, IsKeyboxOrOEMCertValid, OEMCrypto_IsKeyboxOrOEMCertValid);
|
||||
LOOKUP_ALL(13, IsSRMUpdateSupported, OEMCrypto_IsSRMUpdateSupported);
|
||||
LOOKUP(13, 16, IsSRMUpdateSupported, OEMCrypto_IsSRMUpdateSupported);
|
||||
LOOKUP( 8, 15, LoadDeviceRSAKey, OEMCrypto_LoadDeviceRSAKey);
|
||||
LOOKUP_ALL(16, LoadDRMPrivateKey, OEMCrypto_LoadDRMPrivateKey);
|
||||
LOOKUP( 8, 8, LoadKeys_V8, OEMCrypto_LoadKeys_V8);
|
||||
@@ -1014,8 +1082,9 @@ class Adapter {
|
||||
LOOKUP_ALL(15, LoadKeys, OEMCrypto_LoadKeys);
|
||||
LOOKUP_ALL(16, LoadLicense, OEMCrypto_LoadLicense);
|
||||
LOOKUP(14, 14, LoadEntitledContentKeys_V14,OEMCrypto_LoadEntitledContentKeys_V14);
|
||||
LOOKUP_ALL(15, LoadEntitledContentKeys, OEMCrypto_LoadEntitledContentKeys);
|
||||
LOOKUP_ALL(13, LoadSRM, OEMCrypto_LoadSRM);
|
||||
LOOKUP(15, 16, LoadEntitledContentKeys_V16,OEMCrypto_LoadEntitledContentKeys_V16);
|
||||
LOOKUP_ALL(17, LoadEntitledContentKeys, OEMCrypto_LoadEntitledContentKeys);
|
||||
LOOKUP(13, 16, LoadSRM, OEMCrypto_LoadSRM);
|
||||
LOOKUP(10, 13, LoadTestKeybox_V13, OEMCrypto_LoadTestKeybox_V13);
|
||||
LOOKUP_ALL(14, LoadTestKeybox, OEMCrypto_LoadTestKeybox);
|
||||
LOOKUP_ALL(10, LoadTestRSAKey, OEMCrypto_LoadTestRSAKey);
|
||||
@@ -1031,7 +1100,7 @@ class Adapter {
|
||||
LOOKUP_ALL( 9, ReportUsage, OEMCrypto_ReportUsage);
|
||||
LOOKUP_ALL( 8, RewrapDeviceRSAKey, OEMCrypto_RewrapDeviceRSAKey);
|
||||
LOOKUP_ALL(12, RewrapDeviceRSAKey30, OEMCrypto_RewrapDeviceRSAKey30);
|
||||
LOOKUP_ALL( 8, SecurityLevel, OEMCrypto_SecurityLevel);
|
||||
LOOKUP_ALL( 8, SecurityLevel_V16, OEMCrypto_SecurityLevel_V16);
|
||||
LOOKUP_ALL(11, SecurityPatchLevel, OEMCrypto_Security_Patch_Level);
|
||||
LOOKUP( 8, 13, SelectKey_V13, OEMCrypto_SelectKey_V13);
|
||||
LOOKUP_ALL(14, SelectKey, OEMCrypto_SelectKey);
|
||||
@@ -1050,14 +1119,29 @@ class Adapter {
|
||||
LOOKUP_ALL(16, LoadProvisioning, OEMCrypto_LoadProvisioning);
|
||||
LOOKUP_ALL(16, MinorAPIVersion, OEMCrypto_MinorAPIVersion);
|
||||
LOOKUP_ALL(16, OPK_SerializationVersion, OEMCrypto_OPK_SerializationVersion);
|
||||
LOOKUP_ALL(17, CreateEntitledKeySession, OEMCrypto_CreateEntitledKeySession);
|
||||
LOOKUP_ALL(17, RemoveEntitledKeySession, OEMCrypto_RemoveEntitledKeySession);
|
||||
LOOKUP_ALL(17, GetBootCertificateChain, OEMCrypto_GetBootCertificateChain);
|
||||
LOOKUP_ALL(17, GenerateCertificateKeyPair, OEMCrypto_GenerateCertificateKeyPair);
|
||||
LOOKUP_ALL(17, InstallOemPrivateKey, OEMCrypto_InstallOemPrivateKey);
|
||||
LOOKUP_ALL(17, ReassociateEntitledKeySession, OEMCrypto_ReassociateEntitledKeySession);
|
||||
LOOKUP_ALL(17, LoadCasECMKeys, OEMCrypto_LoadCasECMKeys);
|
||||
LOOKUP_ALL(17, ProductionReady, OEMCrypto_ProductionReady);
|
||||
LOOKUP_ALL(16, GenerateOTARequest, OEMCrypto_GenerateOTARequest);
|
||||
LOOKUP_ALL(16, ProcessOTAKeybox, OEMCrypto_ProcessOTAKeybox);
|
||||
LOOKUP_ALL(17, Idle, OEMCrypto_Idle);
|
||||
LOOKUP_ALL(17, Wake, OEMCrypto_Wake);
|
||||
LOOKUP_ALL(17, SecurityLevel, OEMCrypto_SecurityLevel);
|
||||
LOOKUP_ALL(17, BuildInformation, OEMCrypto_BuildInformation);
|
||||
LOOKUP_ALL(17, ReuseUsageEntry, OEMCrypto_ReuseUsageEntry);
|
||||
LOOKUP_ALL(17, GetDTCP2Capability, OEMCrypto_GetDTCP2Capability);
|
||||
LOOKUP_ALL(17, GetWatermarkingSupport, OEMCrypto_GetWatermarkingSupport);
|
||||
// clang-format on
|
||||
|
||||
// There was a mistake in version 16.3 of the header that did not rename
|
||||
// OEMCrypto_AllocateSecureBuffer or OEMCrypto_FreeSecureBuffer
|
||||
if (level1_.AllocateSecureBuffer == NULL ||
|
||||
level1_.FreeSecureBuffer == NULL) {
|
||||
if (level1_.AllocateSecureBuffer == nullptr ||
|
||||
level1_.FreeSecureBuffer == nullptr) {
|
||||
level1_.AllocateSecureBuffer = (L1_AllocateSecureBuffer_t)dlsym(
|
||||
level1_library_, "OEMCrypto_AllocateSecureBuffer");
|
||||
level1_.FreeSecureBuffer = (L1_FreeSecureBuffer_t)dlsym(
|
||||
@@ -1065,17 +1149,17 @@ class Adapter {
|
||||
}
|
||||
|
||||
if (level1_.SecurityLevel) {
|
||||
const char* level = level1_.SecurityLevel();
|
||||
if (strncmp(level, "L1", 2) == 0) {
|
||||
OEMCrypto_Security_Level level = level1_.SecurityLevel();
|
||||
if (level == OEMCrypto_Level1) {
|
||||
level1_.security_level = wvcdm::kSecurityLevelL1;
|
||||
} else if (strncmp(level, "L3", 2) == 0) {
|
||||
} else if (level == OEMCrypto_Level3) {
|
||||
// It is possible that the dynamically loaded OEMCrypto is really L3.
|
||||
// We might want to use it if it has better performance than the built
|
||||
// in L3.
|
||||
LOGW("L1 OEMCrypto is really L3");
|
||||
level1_.security_level = wvcdm::kSecurityLevelL3;
|
||||
} else {
|
||||
LOGE("Unknown security level %.2s", level);
|
||||
LOGE("Unknown security level %d", level);
|
||||
level1_.security_level = wvcdm::kSecurityLevelUnknown;
|
||||
}
|
||||
}
|
||||
@@ -1153,6 +1237,19 @@ class Adapter {
|
||||
level3_.MaximumUsageTableHeaderSize = Level3_MaximumUsageTableHeaderSize;
|
||||
level3_.AllocateSecureBuffer = Level3_AllocateSecureBuffer;
|
||||
level3_.FreeSecureBuffer = Level3_FreeSecureBuffer;
|
||||
level3_.CreateEntitledKeySession = Level3_CreateEntitledKeySession;
|
||||
level3_.RemoveEntitledKeySession = Level3_RemoveEntitledKeySession;
|
||||
level3_.GetBootCertificateChain = Level3_GetBootCertificateChain;
|
||||
level3_.GenerateCertificateKeyPair = Level3_GenerateCertificateKeyPair;
|
||||
level3_.InstallOemPrivateKey = Level3_InstallOemPrivateKey;
|
||||
level3_.ReassociateEntitledKeySession = Level3_ReassociateEntitledKeySession;
|
||||
level3_.LoadCasECMKeys = Level3_LoadCasECMKeys;
|
||||
level3_.ProductionReady = Level3_ProductionReady;
|
||||
level3_.Idle = Level3_Idle;
|
||||
level3_.Wake = Level3_Wake;
|
||||
level3_.ReuseUsageEntry = Level3_ReuseUsageEntry;
|
||||
level3_.GetDTCP2Capability = Level3_GetDTCP2Capability;
|
||||
level3_.GetWatermarkingSupport = Level3_GetWatermarkingSupport;
|
||||
// clang-format on
|
||||
|
||||
level3_.version = Level3_APIVersion();
|
||||
@@ -1222,6 +1319,45 @@ class Adapter {
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult CreateEntitledKeySession(OEMCrypto_SESSION oec_session,
|
||||
OEMCrypto_SESSION* key_session) {
|
||||
LevelSession pair = GetSession(oec_session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (pair.fcn->version < 16) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (pair.fcn->CreateEntitledKeySession == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
OEMCryptoResult result =
|
||||
pair.fcn->CreateEntitledKeySession(pair.session, key_session);
|
||||
if (result == OEMCrypto_SUCCESS) {
|
||||
// Copy everything from |pair| except session field.
|
||||
LevelSession new_session;
|
||||
new_session.fcn = pair.fcn;
|
||||
new_session.nonce = pair.nonce;
|
||||
new_session.session = *key_session;
|
||||
std::unique_lock<std::mutex> auto_lock(session_map_lock_);
|
||||
// Make sure session is not already in my list of sessions.
|
||||
while (session_map_.find(*key_session) != session_map_.end()) {
|
||||
(*key_session)++;
|
||||
}
|
||||
session_map_[*key_session] = new_session;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OEMCryptoResult RemoveEntitledKeySession(OEMCrypto_SESSION key_session) {
|
||||
LevelSession pair = GetSession(key_session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (pair.fcn->version < 16) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (pair.fcn->CreateEntitledKeySession == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
OEMCryptoResult result = pair.fcn->RemoveEntitledKeySession(key_session);
|
||||
if (result == OEMCrypto_SUCCESS) {
|
||||
std::unique_lock<std::mutex> auto_lock(session_map_lock_);
|
||||
session_map_.erase(key_session);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check the system ID of the keybox. This should only be called if the device
|
||||
// uses provisioning 2.0.
|
||||
bool UsingTestKeybox() {
|
||||
@@ -1244,6 +1380,19 @@ class Adapter {
|
||||
// If level 1 not initialized, then return level 3's answer.
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
// Figure out provisioning method. Defaults to keybox.
|
||||
const OEMCrypto_ProvisioningMethod provisioning_method =
|
||||
level1_.GetProvisioningMethod ? level1_.GetProvisioningMethod()
|
||||
: OEMCrypto_Keybox;
|
||||
wvcdm::metrics::OemCryptoDynamicAdapterMetrics& metrics =
|
||||
wvcdm::metrics::GetDynamicAdapterMetricsInstance();
|
||||
// If it is provisioning 4.0, we do not need to install a keybox. We assume
|
||||
// the cert is always valid.
|
||||
if (provisioning_method == OEMCrypto_BootCertificateChain) {
|
||||
metrics.OemCryptoDynamicAdapterMetrics::SetInitializationMode(
|
||||
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_PROVISIONING_4_0);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
if (!level1_.IsKeyboxOrOEMCertValid) {
|
||||
// TODO(b/189989043): add metrics.
|
||||
LOGE("L1 invalid function pointers. Falling back to L3");
|
||||
@@ -1252,12 +1401,6 @@ class Adapter {
|
||||
// Check if the keybox or oem certificate is valid, if so, we are finished
|
||||
// with initialization. Record some metrics and return success.
|
||||
const OEMCryptoResult rot_valid = level1_.IsKeyboxOrOEMCertValid();
|
||||
wvcdm::metrics::OemCryptoDynamicAdapterMetrics& metrics =
|
||||
wvcdm::metrics::GetDynamicAdapterMetricsInstance();
|
||||
// Figure out provisioning method. Defaults to keybox.
|
||||
const OEMCrypto_ProvisioningMethod provisioning_method =
|
||||
level1_.GetProvisioningMethod ? level1_.GetProvisioningMethod()
|
||||
: OEMCrypto_Keybox;
|
||||
// For production systems, we do wish to use a test keybox. We do not force
|
||||
// a fallback to L3 at this point, because this can be overridden by test
|
||||
// code that requires a test keybox.
|
||||
@@ -1362,7 +1505,7 @@ class Adapter {
|
||||
// Try to install a keybox from the file system.
|
||||
OEMCryptoResult TryToInstallKeybox() {
|
||||
if (!level1_.InstallKeyboxOrOEMCert) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
wvcdm::FileSystem file_system;
|
||||
wvutil::FileSystem file_system;
|
||||
std::string filename;
|
||||
if (!wvcdm::Properties::GetFactoryKeyboxPath(&filename)) {
|
||||
// No keybox or cert file found. Give up.
|
||||
@@ -1526,20 +1669,25 @@ uint8_t OEMCrypto_Security_Patch_Level(SecurityLevel level) {
|
||||
return fcn->SecurityPatchLevel();
|
||||
}
|
||||
|
||||
const char* OEMCrypto_SecurityLevel(SecurityLevel level) {
|
||||
if (!gAdapter) return "";
|
||||
OEMCrypto_Security_Level OEMCrypto_SecurityLevel(SecurityLevel level) {
|
||||
if (!gAdapter) return OEMCrypto_Level_Unknown;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(level);
|
||||
if (!fcn) return "";
|
||||
switch (fcn->security_level) {
|
||||
case kSecurityLevelL1:
|
||||
return "L1";
|
||||
case kSecurityLevelL2:
|
||||
return "L2";
|
||||
case kSecurityLevelL3:
|
||||
return "L3";
|
||||
default:
|
||||
return "";
|
||||
if (!fcn) return OEMCrypto_Level_Unknown;
|
||||
if (fcn->SecurityLevel == nullptr) {
|
||||
if (fcn->SecurityLevel_V16 == nullptr) {
|
||||
return OEMCrypto_Level_Unknown;
|
||||
}
|
||||
if (!strncmp("L1", fcn->SecurityLevel_V16(), 2)) {
|
||||
return OEMCrypto_Level1;
|
||||
} else if (!strncmp("L2", fcn->SecurityLevel_V16(), 2)) {
|
||||
return OEMCrypto_Level2;
|
||||
} else if (!strncmp("L3", fcn->SecurityLevel_V16(), 2)) {
|
||||
return OEMCrypto_Level3;
|
||||
} else {
|
||||
return OEMCrypto_Level_Unknown;
|
||||
}
|
||||
}
|
||||
return fcn->SecurityLevel();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetHDCPCapability(
|
||||
@@ -1577,13 +1725,27 @@ uint32_t OEMCrypto_GetAnalogOutputFlags(SecurityLevel level) {
|
||||
return fcn->GetAnalogOutputFlags();
|
||||
}
|
||||
|
||||
const char* OEMCrypto_BuildInformation(SecurityLevel level) {
|
||||
if (!gAdapter) return "<not initialized>";
|
||||
OEMCryptoResult OEMCrypto_BuildInformation(char* buffer, size_t* buffer_length,
|
||||
SecurityLevel level) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(level);
|
||||
if (!fcn) return "<not initialized>";
|
||||
if (fcn->version < 14) return "pre v15";
|
||||
if (fcn->BuildInformation == nullptr) return "unknown";
|
||||
return fcn->BuildInformation();
|
||||
if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (fcn->version < 14) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->BuildInformation == nullptr) {
|
||||
if (fcn->BuildInformation_V16 == nullptr) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
const char* build_info = fcn->BuildInformation_V16();
|
||||
size_t max_length = strnlen(build_info, 128);
|
||||
if (*buffer_length < max_length) {
|
||||
*buffer_length = max_length;
|
||||
return OEMCrypto_ERROR_SHORT_BUFFER;
|
||||
}
|
||||
*buffer_length = max_length;
|
||||
memcpy(buffer, build_info, *buffer_length);
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
return fcn->BuildInformation(buffer, buffer_length);
|
||||
}
|
||||
|
||||
uint32_t OEMCrypto_ResourceRatingTier(SecurityLevel level) {
|
||||
@@ -1600,7 +1762,7 @@ uint32_t OEMCrypto_SupportsDecryptHash(SecurityLevel level) {
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(level);
|
||||
if (!fcn) return OEMCrypto_Hash_Not_Supported;
|
||||
if (fcn->version < 15) return OEMCrypto_Hash_Not_Supported;
|
||||
if (fcn->BuildInformation == nullptr) return OEMCrypto_Hash_Not_Supported;
|
||||
if (fcn->SupportsDecryptHash == nullptr) return OEMCrypto_Hash_Not_Supported;
|
||||
return fcn->SupportsDecryptHash();
|
||||
}
|
||||
|
||||
@@ -1886,8 +2048,9 @@ extern "C" uint32_t OEMCrypto_GetAnalogOutputFlags() {
|
||||
return OEMCrypto_GetAnalogOutputFlags(kLevelDefault);
|
||||
}
|
||||
|
||||
extern "C" const char* OEMCrypto_BuildInformation() {
|
||||
return OEMCrypto_BuildInformation(kLevelDefault);
|
||||
extern "C" OEMCryptoResult OEMCrypto_BuildInformation(char* buffer,
|
||||
size_t* buffer_length) {
|
||||
return OEMCrypto_BuildInformation(buffer, buffer_length, kLevelDefault);
|
||||
}
|
||||
|
||||
extern "C" uint32_t OEMCrypto_ResourceRatingTier() {
|
||||
@@ -1930,8 +2093,8 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys_Back_Compat(
|
||||
key_array_v10[i].key_control =
|
||||
PointerOrNull(message + key_array[i].key_control.offset,
|
||||
key_array[i].key_control.length);
|
||||
if (cipher_modes[i] == OEMCrypto_CipherMode_CBC) {
|
||||
LOGE("CBC Mode not supported.");
|
||||
if (cipher_modes[i] == OEMCrypto_CipherMode_CBCS) {
|
||||
LOGE("CBCS Mode not supported.");
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
@@ -2153,7 +2316,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
|
||||
key_array_v13[i].key_control =
|
||||
PointerOrNull(message + key_array[i].key_control.offset,
|
||||
key_array[i].key_control.length);
|
||||
key_array_v13[i].cipher_mode = OEMCrypto_CipherMode_CTR;
|
||||
key_array_v13[i].cipher_mode = OEMCrypto_CipherMode_CENC;
|
||||
}
|
||||
OEMCrypto_KeyObject_V13* key_array_v13_ptr = nullptr;
|
||||
if (num_keys > 0) key_array_v13_ptr = &key_array_v13[0];
|
||||
@@ -2231,7 +2394,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
|
||||
const OEMCrypto_EntitledContentKeyObject* key_array) {
|
||||
if (!gAdapter.get()) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
LevelSession pair = gAdapter->GetSession(session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION;
|
||||
if (pair.fcn->version < 14) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@@ -2265,6 +2428,22 @@ extern "C" OEMCryptoResult OEMCrypto_LoadEntitledContentKeys(
|
||||
return pair.fcn->LoadEntitledContentKeys_V14(pair.session, key_array_length,
|
||||
ecko_array_v14_ptr);
|
||||
}
|
||||
if (pair.fcn->version < 17) {
|
||||
if (key_array == nullptr) {
|
||||
return pair.fcn->LoadEntitledContentKeys_V16(
|
||||
session, message, message_length, key_array_length, nullptr);
|
||||
}
|
||||
std::vector<OEMCrypto_EntitledContentKeyObject_V16> key_array_v16(
|
||||
key_array_length);
|
||||
for (size_t i = 0; i < key_array_length; i++) {
|
||||
key_array_v16[i].entitlement_key_id = key_array[i].entitlement_key_id;
|
||||
key_array_v16[i].content_key_id = key_array[i].content_key_id;
|
||||
key_array_v16[i].content_key_data_iv = key_array[i].content_key_data_iv;
|
||||
key_array_v16[i].content_key_data = key_array[i].content_key_data;
|
||||
}
|
||||
return pair.fcn->LoadEntitledContentKeys_V16(
|
||||
session, message, message_length, key_array_length, &key_array_v16[0]);
|
||||
}
|
||||
if (pair.fcn->LoadEntitledContentKeys == nullptr) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
@@ -2693,7 +2872,7 @@ extern "C" uint8_t OEMCrypto_Security_Patch_Level() {
|
||||
return OEMCrypto_Security_Patch_Level(kLevelDefault);
|
||||
}
|
||||
|
||||
extern "C" const char* OEMCrypto_SecurityLevel() {
|
||||
extern "C" OEMCrypto_Security_Level OEMCrypto_SecurityLevel() {
|
||||
return OEMCrypto_SecurityLevel(kLevelDefault);
|
||||
}
|
||||
|
||||
@@ -3037,6 +3216,91 @@ extern "C" OEMCryptoResult OEMCrypto_FreeSecureBuffer(
|
||||
return pair.fcn->FreeSecureBuffer(pair.session, output_descriptor, secure_fd);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_CreateEntitledKeySession(
|
||||
OEMCrypto_SESSION oec_session, OEMCrypto_SESSION* key_session) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_OPEN_SESSION_FAILED;
|
||||
return gAdapter->CreateEntitledKeySession(oec_session, key_session);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_RemoveEntitledKeySession(
|
||||
OEMCrypto_SESSION key_session) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_OPEN_SESSION_FAILED;
|
||||
return gAdapter->RemoveEntitledKeySession(key_session);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GetBootCertificateChain(
|
||||
uint8_t* bcc, size_t* bcc_size, uint8_t* additional_signature,
|
||||
size_t* additional_signature_size) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->GetBootCertificateChain == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->GetBootCertificateChain(bcc, bcc_size, additional_signature,
|
||||
additional_signature_size);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateCertificateKeyPair(
|
||||
OEMCrypto_SESSION session, uint8_t* public_key, size_t* public_key_size,
|
||||
uint8_t* public_key_signature, size_t* public_key_signature_size,
|
||||
uint8_t* wrapped_private_key, size_t* wrapped_private_key_size,
|
||||
OEMCrypto_PrivateKeyType* key_type) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
LevelSession pair = gAdapter->GetSession(session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (pair.fcn->GenerateCertificateKeyPair == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return pair.fcn->GenerateCertificateKeyPair(
|
||||
pair.session, public_key, public_key_size, public_key_signature,
|
||||
public_key_signature_size, wrapped_private_key, wrapped_private_key_size,
|
||||
key_type);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_InstallOemPrivateKey(
|
||||
OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type,
|
||||
const uint8_t* wrapped_private_key, size_t wrapped_private_key_length) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
LevelSession pair = gAdapter->GetSession(session);
|
||||
if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION;
|
||||
if (pair.fcn->InstallOemPrivateKey == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return pair.fcn->InstallOemPrivateKey(
|
||||
pair.session, key_type, wrapped_private_key, wrapped_private_key_length);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ReassociateEntitledKeySession(
|
||||
OEMCrypto_SESSION key_session, OEMCrypto_SESSION oec_session) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->version < 17) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->ReassociateEntitledKeySession == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->ReassociateEntitledKeySession(key_session, oec_session);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_LoadCasECMKeys(
|
||||
OEMCrypto_SESSION session, const uint8_t* message, size_t message_length,
|
||||
const OEMCrypto_EntitledContentKeyObject* even_key,
|
||||
const OEMCrypto_EntitledContentKeyObject* odd_key) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->version < 17) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->LoadCasECMKeys == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->LoadCasECMKeys(session, message, message_length, even_key,
|
||||
odd_key);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ProductionReady() {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->version < 17) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->ProductionReady == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->ProductionReady();
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_OPK_SerializationVersion(
|
||||
uint32_t* ree_major, uint32_t* ree_minor, uint32_t* tee_major,
|
||||
uint32_t* tee_minor) {
|
||||
@@ -3096,3 +3360,53 @@ extern "C" OEMCryptoResult OEMCrypto_ProcessOTAKeybox(OEMCrypto_SESSION session,
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_Idle(OEMCrypto_IdleState state,
|
||||
uint32_t os_specific_code) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->version < 17) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->Idle == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->Idle(state, os_specific_code);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_Wake() {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->version < 17) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->Wake == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->Wake();
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ReuseUsageEntry(
|
||||
OEMCrypto_SESSION session, uint32_t usage_entry_number) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->version < 17) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->ReuseUsageEntry == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->ReuseUsageEntry(session, usage_entry_number);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GetDTCP2Capability(
|
||||
OEMCrypto_DTCP2_Capability* capability) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->version < 17) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
if (fcn->GetDTCP2Capability == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->GetDTCP2Capability(capability);
|
||||
}
|
||||
|
||||
extern "C" OEMCrypto_WatermarkingSupport OEMCrypto_GetWatermarkingSupport() {
|
||||
if (!gAdapter) return OEMCrypto_WatermarkingError;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_WatermarkingError;
|
||||
if (fcn->version < 17) return OEMCrypto_WatermarkingError;
|
||||
if (fcn->GetWatermarkingSupport == nullptr)
|
||||
return OEMCrypto_WatermarkingError;
|
||||
return fcn->GetWatermarkingSupport();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ constexpr int64_t kErrorTime = -1;
|
||||
|
||||
// static
|
||||
std::unique_ptr<SystemFallbackPolicy> SystemFallbackPolicy::Create() {
|
||||
std::unique_ptr<FileSystem> fs(new FileSystem());
|
||||
std::unique_ptr<wvutil::FileSystem> fs(new wvutil::FileSystem());
|
||||
std::unique_ptr<DeviceFiles> device_files(new DeviceFiles(fs.get()));
|
||||
if (!device_files->Init(kSecurityLevelL1)) {
|
||||
LOGE("Failed to initialize device files");
|
||||
@@ -35,7 +35,7 @@ std::unique_ptr<SystemFallbackPolicy> SystemFallbackPolicy::Create() {
|
||||
|
||||
// static
|
||||
std::unique_ptr<SystemFallbackPolicy> SystemFallbackPolicy::CreateForTesting(
|
||||
Clock* clock) {
|
||||
wvutil::Clock* clock) {
|
||||
std::unique_ptr<SystemFallbackPolicy> policy(new SystemFallbackPolicy());
|
||||
if (clock != nullptr) {
|
||||
policy->SetClockForTesting(clock);
|
||||
@@ -46,7 +46,7 @@ std::unique_ptr<SystemFallbackPolicy> SystemFallbackPolicy::CreateForTesting(
|
||||
|
||||
// static
|
||||
std::unique_ptr<SystemFallbackPolicy> SystemFallbackPolicy::CreateForTesting(
|
||||
const SystemFallbackInfo& info, Clock* clock) {
|
||||
const SystemFallbackInfo& info, wvutil::Clock* clock) {
|
||||
std::unique_ptr<SystemFallbackPolicy> policy(new SystemFallbackPolicy());
|
||||
if (clock != nullptr) {
|
||||
policy->SetClockForTesting(clock);
|
||||
@@ -207,7 +207,7 @@ int64_t SystemFallbackPolicy::GenerateInitialBackoffDuration() {
|
||||
return kFastBackoffDuration;
|
||||
}
|
||||
// Use a random backoff period to avoid server spam across all devices.
|
||||
return static_cast<int64_t>(CdmRandom::RandomInRange(
|
||||
return static_cast<int64_t>(wvutil::CdmRandom::RandomInRange(
|
||||
kMinInitialBackoffDuration, kMaxInitialBackoffDuration));
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ CdmResponseType OtaKeyboxProvisioner::GetProvisioningRequest(
|
||||
client_id->Clear();
|
||||
}
|
||||
LOGI("OTA request generated");
|
||||
LOGV("ota_request_data = %s", b2a_hex(ota_request_data).c_str());
|
||||
LOGV("ota_request_data = %s", wvutil::b2a_hex(ota_request_data).c_str());
|
||||
OtaRequest* ota_request = prov_request.mutable_android_ota_keybox_request();
|
||||
ota_request->set_ota_request(ota_request_data);
|
||||
|
||||
@@ -183,7 +183,7 @@ CdmResponseType OtaKeyboxProvisioner::GetProvisioningRequest(
|
||||
signed_request.SerializeToString(request);
|
||||
|
||||
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
|
||||
*request = Base64SafeEncodeNoPad(
|
||||
*request = wvutil::Base64SafeEncodeNoPad(
|
||||
std::vector<uint8_t>(request->begin(), request->end()));
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ CdmResponseType OtaKeyboxProvisioner::HandleProvisioningResponse(
|
||||
kProductionKeybox, ota_response_data);
|
||||
if (result == NO_ERROR) {
|
||||
LOGI("OTA response successfully processed");
|
||||
LOGV("ota_response_data = %s", b2a_hex(ota_response_data).c_str());
|
||||
LOGV("ota_response_data = %s", wvutil::b2a_hex(ota_response_data).c_str());
|
||||
fallback_policy_->MarkProvisioned();
|
||||
response_received_ = true;
|
||||
} else {
|
||||
|
||||
@@ -37,7 +37,7 @@ PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
||||
event_listener_(event_listener),
|
||||
license_keys_(new LicenseKeys(crypto_session->GetSecurityLevel())),
|
||||
policy_timers_(new PolicyTimersV15),
|
||||
clock_(new Clock) {
|
||||
clock_(new wvutil::Clock) {
|
||||
InitDevice(crypto_session);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ bool PolicyEngine::CanDecryptContent(const KeyId& key_id) {
|
||||
return license_keys_->CanDecryptContent(key_id);
|
||||
} else {
|
||||
LOGE("Provided content key is not in license: key_id = %s",
|
||||
b2a_hex(key_id).c_str());
|
||||
wvutil::b2a_hex(key_id).c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -424,7 +424,7 @@ int64_t PolicyEngine::GetCurrentTime() {
|
||||
return current_time;
|
||||
}
|
||||
|
||||
void PolicyEngine::set_clock(Clock* clock) { clock_.reset(clock); }
|
||||
void PolicyEngine::set_clock(wvutil::Clock* clock) { clock_.reset(clock); }
|
||||
|
||||
void PolicyEngine::SetSecurityLevelForTest(CdmSecurityLevel security_level) {
|
||||
license_keys_->SetSecurityLevelForTest(security_level);
|
||||
|
||||
@@ -153,7 +153,7 @@ SecurityLevel CdmSecurityLevelToRequestedLevel(
|
||||
} // namespace
|
||||
|
||||
UsageTableHeader::UsageTableHeader() : clock_ref_(&clock_) {
|
||||
file_system_.reset(new FileSystem());
|
||||
file_system_.reset(new wvutil::FileSystem());
|
||||
device_files_.reset(new DeviceFiles(file_system_.get()));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <threads.h>
|
||||
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
@@ -43,6 +42,8 @@ const char* CdmClientTokenTypeToString(CdmClientTokenType type) {
|
||||
return "DrmCert";
|
||||
case kClientTokenOemCert:
|
||||
return "OemCert";
|
||||
case kClientTokenBootCertChain:
|
||||
return "BootCertChain";
|
||||
case kClientTokenUninitialized:
|
||||
return "Uninitialized";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user