Source release 17.1.2

This commit is contained in:
John "Juce" Bruce
2023-06-23 15:37:42 -07:00
parent a10f13a2dc
commit 2baa7c6e2b
353 changed files with 12903 additions and 2305 deletions

View File

@@ -65,7 +65,6 @@ class UsagePropertySet : public CdmClientPropertySet {
CdmEngine::CdmEngine(wvutil::FileSystem* file_system,
std::shared_ptr<metrics::EngineMetrics> metrics)
: metrics_(metrics),
cert_provisioning_(),
file_system_(file_system),
spoid_(EMPTY_SPOID),
usage_session_(),
@@ -1065,6 +1064,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
}
// TODO(b/141705730): Remove usage entries on provisioning.
std::unique_lock<std::mutex> cert_lock(cert_provisioning_mutex_);
if (!cert_provisioning_) {
cert_provisioning_.reset(
new CertificateProvisioning(metrics_->GetCryptoMetrics()));
@@ -1094,6 +1094,7 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
std::string* wrapped_key) {
LOGI("response_size = %zu, security_level = %s", response.size(),
RequestedSecurityLevelToString(requested_security_level));
std::unique_lock<std::mutex> cert_lock(cert_provisioning_mutex_);
if (response.empty()) {
LOGE("Empty provisioning response");
cert_provisioning_.reset();
@@ -1655,7 +1656,7 @@ CdmResponseType CdmEngine::RemoveAllUsageInfo(
}
if (!handle.DeleteUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
usage_data[0].provider_session_token)) {
usage_data[0].key_set_id)) {
LOGW("Failed to delete usage info");
break;
}
@@ -1707,25 +1708,18 @@ CdmResponseType CdmEngine::RemoveUsageInfo(
new CdmSession(file_system_, metrics_->AddSession()));
usage_session_->Init(usage_property_set_.get());
CdmKeyMessage license_request;
CdmKeyResponse license_response;
CdmUsageEntry usage_entry;
uint32_t usage_entry_number;
std::string drm_certificate;
CryptoWrappedKey wrapped_private_key;
if (!handle.RetrieveUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id), provider_session_token,
&license_request, &license_response, &usage_entry,
&usage_entry_number, &drm_certificate, &wrapped_private_key)) {
DeviceFiles::CdmUsageData usage_data;
if (!handle.RetrieveUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
provider_session_token, &usage_data)) {
// Try other security level
continue;
}
if (usage_session_->supports_usage_info()) {
status = usage_session_->DeleteUsageEntry(usage_entry_number);
status =
usage_session_->DeleteUsageEntry(usage_data.usage_entry_number);
if (!handle.DeleteUsageInfo(DeviceFiles::GetUsageInfoFileName(app_id),
provider_session_token)) {
usage_data.key_set_id)) {
status = REMOVE_USAGE_INFO_ERROR_1;
}
usage_session_.reset();
@@ -2292,4 +2286,54 @@ void CdmEngine::SetFastOtaKeyboxFallbackDurationRules() {
}
system_fallback_policy->SetFastBackoffDurationRules();
}
CdmResponseType CdmEngine::SignRsa(const std::string& wrapped_key,
const std::string& message,
std::string* signature,
RSA_Padding_Scheme padding_scheme) {
// Try to open cdm session.
CdmSessionId session_id;
auto sts = OpenSession("com.widevine", nullptr, nullptr, &session_id);
if (sts != NO_ERROR) {
LOGE("OpenSession failed, status: %d", static_cast<int>(sts));
return sts;
}
// Retrieve the cdm session
std::shared_ptr<CdmSession> session;
{
std::unique_lock<std::recursive_mutex> lock(session_map_lock_);
if (!session_map_.FindSession(session_id, &session)) {
LOGE("Session not found: session_id = %s", IdToString(session_id));
CloseSession(session_id);
return CdmResponseType(SESSION_NOT_FOUND_24);
}
}
// Load cast private key for signing
CryptoWrappedKey key(CryptoWrappedKey::kRsa, wrapped_key);
sts = session->LoadCastPrivateKey(key);
if (sts != NO_ERROR) {
LOGE("LoadCastPrivateKey failed, status: %d", static_cast<int>(sts));
CloseSession(session_id);
return sts;
}
// Generate Rsa signature for cast message
sts = session->GenerateRsaSignature(message, signature, padding_scheme);
if (sts != NO_ERROR) {
LOGE("GenerateRsaSignature failed, status: %d", static_cast<int>(sts));
CloseSession(session_id);
return sts;
}
// Try to close cdm session.
sts = CloseSession(session_id);
if (sts != NO_ERROR) {
LOGE("CloseSession failed, status: %d", static_cast<int>(sts));
return sts;
}
return sts;
}
} // namespace wvcdm

View File

@@ -305,8 +305,11 @@ CdmResponseType CdmSession::RestoreOfflineSession(const CdmKeySetId& key_set_id,
std::string fake_message("empty message");
std::string core_message;
std::string license_request_signature;
uint32_t nonce;
// Sign a fake message so that OEMCrypto will start the rental clock. The
// signature and generated core message are ignored.
result = crypto_session_->GenerateNonce(&nonce);
if (result != NO_ERROR) return result;
result = crypto_session_->PrepareAndSignLicenseRequest(
fake_message, &core_message, &license_request_signature);
if (result != NO_ERROR) return result;
@@ -1017,8 +1020,7 @@ bool CdmSession::DeleteLicenseFile() {
std::string app_id;
GetApplicationId(&app_id);
return file_handle_->DeleteUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id),
license_parser_->provider_session_token());
DeviceFiles::GetUsageInfoFileName(app_id), key_set_id_);
}
}
@@ -1151,8 +1153,7 @@ bool CdmSession::UpdateUsageInfo() {
usage_data.usage_entry_number = usage_entry_number_;
return file_handle_->UpdateUsageInfo(
DeviceFiles::GetUsageInfoFileName(app_id), usage_provider_session_token_,
usage_data);
DeviceFiles::GetUsageInfoFileName(app_id), usage_data);
}
void CdmSession::UpdateRequestLatencyTiming(CdmResponseType sts) {
@@ -1237,6 +1238,18 @@ CdmResponseType CdmSession::LoadPrivateKey(
}
}
CdmResponseType CdmSession::LoadCastPrivateKey(
const CryptoWrappedKey& private_key) {
return crypto_session_->LoadCertificatePrivateKey(private_key);
}
CdmResponseType CdmSession::GenerateRsaSignature(const std::string& message,
std::string* signature,
RSA_Padding_Scheme scheme) {
return crypto_session_->GenerateRsaSignature(message, signature,
scheme);
}
// For testing only - takes ownership of pointers
void CdmSession::set_license_parser(CdmLicense* license_parser) {

View File

@@ -22,18 +22,19 @@ const std::string kEmptyString;
// URL for Google Provisioning Server.
// The provisioning server supplies the certificate that is needed
// to communicate with the License Server.
const std::string kProvisioningServerUrl =
const char kProvisioningServerUrl[] =
"https://www.googleapis.com/"
"certificateprovisioning/v1/devicecertificates/create"
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
// In case of provisioning 4, the default url is used as a way to inform app of
// the current provisioning stage. In the first stage, this suffix is appended
// to kProvisioningServerUrl; in the second stage, there is no change to
// kProvisioningServerUrl.
const std::string kProv40FirstStageServerUrlSuffix = "&preProvisioning=true";
const char kProv40FirstStageServerUrlSuffix[] = "&preProvisioning=true";
// NOTE: Provider ID = widevine.com
const std::string kCpProductionServiceCertificate = wvutil::a2bs_hex(
const char kCpProductionServiceCertificate[] =
"0ab9020803121051434fe2a44c763bcc2c826a2d6ef9a718f7d793d005228e02"
"3082010a02820101009e27088659dbd9126bc6ed594caf652b0eaab82abb9862"
"ada1ee6d2cb5247e94b28973fef5a3e11b57d0b0872c930f351b5694354a8c77"
@@ -55,12 +56,12 @@ const std::string kCpProductionServiceCertificate = wvutil::a2bs_hex(
"76e6f76e2751fbefb669f05703cec8c64cf7a62908d5fb870375eb0cc96c508e"
"26e0c050f3fd3ebe68cef9903ef6405b25fc6e31f93559fcff05657662b3653a"
"8598ed5751b38694419242a875d9e00d5a5832933024b934859ec8be78adccbb"
"1ec7127ae9afeef9c5cd2e15bd3048e8ce652f7d8c5d595a0323238c598a28");
"1ec7127ae9afeef9c5cd2e15bd3048e8ce652f7d8c5d595a0323238c598a28";
// Used in provisioning 4 client identification name value pairs.
const std::string kKeyAppParameterSpoid = "spoid";
const std::string kKeyAppParameterProviderId = "provider_id";
const std::string kKeyAppParameterStableId = "stable_id";
const char kKeyAppParameterSpoid[] = "spoid";
const char kKeyAppParameterProviderId[] = "provider_id";
const char kKeyAppParameterStableId[] = "stable_id";
// Retrieves |stored_oem_cert| from |file_handle|, and load the OEM private key
// to |crypto_session|. Returns true if all operations are successful.
@@ -112,9 +113,10 @@ void CertificateProvisioning::GetProvisioningServerUrl(
CdmResponseType CertificateProvisioning::Init(
const std::string& service_certificate) {
std::string certificate = service_certificate.empty()
? kCpProductionServiceCertificate
: service_certificate;
std::string certificate =
service_certificate.empty()
? wvutil::a2bs_hex(kCpProductionServiceCertificate)
: service_certificate;
return service_certificate_->Init(certificate);
}
@@ -371,13 +373,14 @@ CdmResponseType CertificateProvisioning::GetProvisioning40RequestInternal(
if (stored_oem_cert.empty()) {
// This is the first stage provisioning.
default_url->assign(kProvisioningServerUrl +
default_url->assign(std::string(kProvisioningServerUrl) +
kProv40FirstStageServerUrlSuffix);
// First-stage provisioning always uses the WV production service cert for
// encryption.
ServiceCertificate wv_service_cert;
status = wv_service_cert.Init(kCpProductionServiceCertificate);
status = wv_service_cert.Init(
wvutil::a2bs_hex(kCpProductionServiceCertificate));
if (status != NO_ERROR) return status;
// Since |stored_oem_cert| is empty, the client identification token will be

View File

@@ -176,6 +176,12 @@ size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm) {
}
return kAes128BlockSize;
}
uint8_t* MutableStringDataPointer(std::string* s) {
if (s == nullptr) return nullptr;
if (s->empty()) return nullptr;
return reinterpret_cast<uint8_t*>(&s->front());
}
} // namespace
// CryptoSession variables allocation.
@@ -1387,18 +1393,18 @@ CdmResponseType CryptoSession::GetBootCertificateChain(
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);
});
OEMCryptoResult sts =
WithOecReadLock("GetBootCertificateChain Attempt 1", [&] {
return 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()),
sts = WithOecReadLock("GetBootCertificateChain Attempt 2", [&] {
return OEMCrypto_GetBootCertificateChain(
MutableStringDataPointer(bcc), &bcc_length,
MutableStringDataPointer(additional_signature),
&additional_signature_length);
});
}
@@ -1446,11 +1452,10 @@ CdmResponseType CryptoSession::GenerateCertificateKeyPair(
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()),
oec_session_id_, MutableStringDataPointer(public_key),
&public_key_length, MutableStringDataPointer(public_key_signature),
&public_key_signature_length,
reinterpret_cast<uint8_t*>(&wrapped_private_key->front()),
MutableStringDataPointer(wrapped_private_key),
&wrapped_private_key_length, &oemcrypto_key_type),
metrics_, oemcrypto_generate_certificate_key_pair_, status);
});
@@ -1567,7 +1572,8 @@ CdmResponseType CryptoSession::GenerateDerivedKeys(
}
CdmResponseType CryptoSession::GenerateRsaSignature(const std::string& message,
std::string* signature) {
std::string* signature,
RSA_Padding_Scheme scheme) {
LOGV("Generating RSA signature: id = %u", oec_session_id_);
RETURN_IF_NULL(signature, PARAMETER_NULL);
@@ -1584,7 +1590,7 @@ CdmResponseType CryptoSession::GenerateRsaSignature(const std::string& message,
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
message.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
&length, kSign_RSASSA_PSS),
&length, scheme),
metrics_, oemcrypto_generate_rsa_signature_, sts,
metrics::Pow2Bucket(length));
});
@@ -3383,4 +3389,5 @@ CryptoSession* CryptoSessionFactory::MakeCryptoSession(
metrics::CryptoMetrics* crypto_metrics) {
return new CryptoSession(crypto_metrics);
}
} // namespace wvcdm

View File

@@ -1123,7 +1123,7 @@ bool DeviceFiles::GetProviderSessionToken(const std::string& app_id,
}
bool DeviceFiles::DeleteUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token) {
const CdmKeySetId& key_set_id) {
RETURN_FALSE_IF_UNINITIALIZED();
video_widevine_client::sdk::File file;
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
@@ -1135,17 +1135,19 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& usage_info_file_name,
int index = 0;
bool found = false;
for (; index < usage_info->sessions_size(); ++index) {
if (usage_info->sessions(index).token() == provider_session_token) {
const auto& session = usage_info->sessions(index);
if (session.key_set_id() == key_set_id) {
found = true;
break;
}
}
if (!found) {
LOGE("Unable to find provider session token: pst = %s",
wvutil::b2a_hex(provider_session_token).c_str());
LOGE("Unable to find usage info: key_set_id = %s", IdToString(key_set_id));
return false;
}
LOGD("Deleting usage info: key_set_id = %s, pst = %s", IdToString(key_set_id),
wvutil::b2a_hex(usage_info->sessions(index).token()).c_str());
google::protobuf::RepeatedPtrField<UsageInfo_ProviderSession>* sessions =
usage_info->mutable_sessions();
@@ -1374,7 +1376,6 @@ bool DeviceFiles::StoreUsageInfo(const std::string& usage_info_file_name,
}
bool DeviceFiles::UpdateUsageInfo(const std::string& usage_info_file_name,
const std::string& provider_session_token,
const CdmUsageData& usage_data) {
RETURN_FALSE_IF_UNINITIALIZED();
@@ -1383,43 +1384,52 @@ bool DeviceFiles::UpdateUsageInfo(const std::string& usage_info_file_name,
LOGE("Usage info file does not exist");
return false;
}
if (RetrieveHashedFile(usage_info_file_name, &file) != kNoError) {
LOGE("Unable to retrieve usage info file");
return false;
}
video_widevine_client::sdk::UsageInfo* usage_info = file.mutable_usage_info();
int index = 0;
for (; index < file.usage_info().sessions_size(); ++index) {
if (file.usage_info().sessions(index).token() == provider_session_token) {
UsageInfo* usage_info = file.mutable_usage_info();
UsageInfo_ProviderSession* provider_session =
usage_info->mutable_sessions(index);
provider_session->set_license_request(usage_data.license_request);
provider_session->set_license(usage_data.license);
provider_session->set_key_set_id(usage_data.key_set_id);
provider_session->set_usage_entry(usage_data.usage_entry);
provider_session->set_usage_entry_number(usage_data.usage_entry_number);
if (usage_data.drm_certificate.size() > 0) {
uint32_t drm_certificate_id;
if (!FindOrInsertUsageCertificate(usage_data.drm_certificate,
usage_data.wrapped_private_key,
usage_info, &drm_certificate_id)) {
LOGE("Unable to find a certificate in to update the usage info");
return false;
}
provider_session->set_drm_certificate_id(drm_certificate_id);
}
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(usage_info_file_name, serialized_file) ==
kNoError;
}
for (; index < usage_info->sessions_size(); ++index) {
// Use key set ID to identify usage info. PST is not guaranteed
// to be unique.
if (usage_info->sessions(index).key_set_id() == usage_data.key_set_id)
break;
}
if (index == usage_info->sessions_size()) {
LOGE("Failed to find usage info: key_set_id = %s",
IdToString(usage_data.key_set_id));
return false;
}
return false;
video_widevine_client::sdk::UsageInfo::ProviderSession* session =
usage_info->mutable_sessions(index);
// Verify that the PST are the same.
if (session->token() != usage_data.provider_session_token) {
LOGE("Mismatch PST: key_set_id = %s", IdToString(usage_data.key_set_id));
return false;
}
// Update session.
session->set_license_request(usage_data.license_request);
session->set_license(usage_data.license);
session->set_usage_entry(usage_data.usage_entry);
session->set_usage_entry_number(usage_data.usage_entry_number);
if (usage_data.drm_certificate.size() > 0) {
uint32_t drm_certificate_id;
if (!FindOrInsertUsageCertificate(usage_data.drm_certificate,
usage_data.wrapped_private_key,
usage_info, &drm_certificate_id)) {
LOGE("Unable to find a certificate in to update the usage info");
return false;
}
session->set_drm_certificate_id(drm_certificate_id);
}
std::string serialized_file;
file.SerializeToString(&serialized_file);
return StoreFileWithHash(usage_info_file_name, serialized_file) == kNoError;
}
bool DeviceFiles::RetrieveUsageInfo(const std::string& usage_info_file_name,

View File

@@ -96,7 +96,7 @@ bool LicenseKeys::GetAllowedUsage(const KeyId& key_id,
} else if (content_keyid_to_entitlement_key_id_.count(key_id) > 0) {
if (key_statuses_.count(content_keyid_to_entitlement_key_id_[key_id]) > 0) {
return key_statuses_[content_keyid_to_entitlement_key_id_[key_id]]
->CanDecryptContent();
->GetAllowedUsage(allowed_usage);
}
return false;
} else {

View File

@@ -12,7 +12,10 @@ const char* kSecurityLevelDirs[] = {"L1/", "L3/"};
} // namespace
namespace wvcdm {
using UniqueLock = std::unique_lock<std::mutex>;
std::mutex Properties::init_mutex_;
std::mutex Properties::session_mutex_;
bool Properties::is_initialized_ = false;
bool Properties::oem_crypto_use_secure_buffers_;
bool Properties::oem_crypto_use_fifo_;
@@ -26,6 +29,7 @@ std::unique_ptr<CdmClientPropertySetMap> Properties::session_property_set_;
bool Properties::AddSessionPropertySet(const CdmSessionId& session_id,
CdmClientPropertySet* property_set) {
UniqueLock lock(session_mutex_);
if (!session_property_set_) {
return false;
}
@@ -37,6 +41,7 @@ bool Properties::AddSessionPropertySet(const CdmSessionId& session_id,
}
bool Properties::RemoveSessionPropertySet(const CdmSessionId& session_id) {
UniqueLock lock(session_mutex_);
if (!session_property_set_) {
return false;
}
@@ -45,6 +50,7 @@ bool Properties::RemoveSessionPropertySet(const CdmSessionId& session_id) {
CdmClientPropertySet* Properties::GetCdmClientPropertySet(
const CdmSessionId& session_id) {
// Call must obtain |session_mutex_|.
if (session_property_set_) {
CdmClientPropertySetMap::iterator it =
session_property_set_->find(session_id);
@@ -57,6 +63,7 @@ CdmClientPropertySet* Properties::GetCdmClientPropertySet(
bool Properties::GetApplicationId(const CdmSessionId& session_id,
std::string* app_id) {
UniqueLock lock(session_mutex_);
const CdmClientPropertySet* property_set =
GetCdmClientPropertySet(session_id);
if (property_set == nullptr) {
@@ -68,6 +75,7 @@ bool Properties::GetApplicationId(const CdmSessionId& session_id,
bool Properties::GetServiceCertificate(const CdmSessionId& session_id,
std::string* service_certificate) {
UniqueLock lock(session_mutex_);
const CdmClientPropertySet* property_set =
GetCdmClientPropertySet(session_id);
if (property_set == nullptr) {
@@ -79,6 +87,7 @@ bool Properties::GetServiceCertificate(const CdmSessionId& session_id,
bool Properties::SetServiceCertificate(const CdmSessionId& session_id,
const std::string& service_certificate) {
UniqueLock lock(session_mutex_);
CdmClientPropertySet* property_set = GetCdmClientPropertySet(session_id);
if (property_set == nullptr) {
return false;
@@ -88,6 +97,7 @@ bool Properties::SetServiceCertificate(const CdmSessionId& session_id,
}
bool Properties::UsePrivacyMode(const CdmSessionId& session_id) {
UniqueLock lock(session_mutex_);
const CdmClientPropertySet* property_set =
GetCdmClientPropertySet(session_id);
if (property_set == nullptr) {
@@ -97,6 +107,7 @@ bool Properties::UsePrivacyMode(const CdmSessionId& session_id) {
}
uint32_t Properties::GetSessionSharingId(const CdmSessionId& session_id) {
UniqueLock lock(session_mutex_);
const CdmClientPropertySet* property_set =
GetCdmClientPropertySet(session_id);
if (property_set == nullptr) {

View File

@@ -19,7 +19,7 @@ constexpr size_t kKeyboxSystemIdOffset = 4;
// system ID (0 = leaf/device cert, 1 = intermediate/device family cert).
constexpr size_t kOemCertSystemIdIndex = 1;
// OID of X.509 certificate extension containing the Widevine system ID.
const std::string kWidevineSystemIdExtensionOid = "1.3.6.1.4.1.11129.4.1.1";
const char kWidevineSystemIdExtensionOid[] = "1.3.6.1.4.1.11129.4.1.1";
constexpr size_t kSystemIdLength = sizeof(uint32_t);

View File

@@ -835,7 +835,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
}
device_files->DeleteUsageInfo(
usage_entry_info_[usage_entry_number].usage_info_file_name,
provider_session_token);
usage_entry_info_[usage_entry_number].key_set_id);
if (!device_files->StoreUsageInfo(
provider_session_token, key_request, key_response,
usage_entry_info_[usage_entry_number].usage_info_file_name,