SPOID
(This is a merge of go/wvgerrit/23182) This patch adds the framework for Stable Per-Origin Identifiers to the CDM. Calculating SPOIDs will be done on the client-side, and they are sent as part of the provisioning request. SPOIDs are also available to the app as the Device Unique ID, replacing the previous method of returning the actual Device Unique ID from the keybox / OEM certificate. Different SPOIDs must use separate storage, just as different origins already do. Support for this has been added to the Android adapter to the CDM Core. However, the code in the Android glue layer that would drive this behavior will be checked in in a separate change. As such, all Android devices will continue using the legacy behavior even after this patch goes in, until the glue layer code can be updated. Bug: 27101531 Test: CE CDM Unit Tests Test: Linux Jenkins Unit Tests Test: Android Unit Tests (with and without SPOIDs forced on) Test: Android GTS Tests Change-Id: Ia0caf890381cbcb97504d08b19aeab8b29bd07ae
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
#include "file_utils.h"
|
||||
#include "log.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/sha.h>
|
||||
@@ -35,8 +36,8 @@ std::string GetFileNameSafeHash(const std::string& input) {
|
||||
return wvcdm::Base64SafeEncode(hash);
|
||||
}
|
||||
|
||||
std::string GetFileNameForOrigin(const std::string path,
|
||||
const std::string origin) {
|
||||
std::string GetFileNameForIdentifier(const std::string path,
|
||||
const std::string identifier) {
|
||||
std::string file_name = path;
|
||||
std::string dir_path;
|
||||
const size_t delimiter_pos = path.rfind(kDirectoryDelimiter);
|
||||
@@ -45,8 +46,8 @@ std::string GetFileNameForOrigin(const std::string path,
|
||||
file_name = path.substr(delimiter_pos + 1);
|
||||
}
|
||||
|
||||
if (file_name == kCertificateFileName && !origin.empty()) {
|
||||
const std::string hash = GetFileNameSafeHash(origin);
|
||||
if (file_name == kCertificateFileName && !identifier.empty()) {
|
||||
const std::string hash = GetFileNameSafeHash(identifier);
|
||||
file_name = kCertificateFileNamePrefix + hash + kCertificateFileNameExt;
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ ssize_t File::Write(const char* buffer, size_t bytes) {
|
||||
|
||||
class FileSystem::Impl {};
|
||||
|
||||
FileSystem::FileSystem() : FileSystem("", NULL) {}
|
||||
FileSystem::FileSystem() : FileSystem(EMPTY_ORIGIN, NULL) {}
|
||||
FileSystem::FileSystem(const std::string& origin, void* /* extra_data */)
|
||||
: origin_(origin) {
|
||||
FileUtils::SecurityLevelPathBackwardCompatibility(kSecurityLevelL1);
|
||||
@@ -121,7 +122,7 @@ FileSystem::~FileSystem() {}
|
||||
File* FileSystem::Open(const std::string& in_name, int flags) {
|
||||
std::string open_flags;
|
||||
|
||||
std::string name = GetFileNameForOrigin(in_name, origin_);
|
||||
std::string name = GetFileNameForIdentifier(in_name, identifier_);
|
||||
|
||||
// create the enclosing directory if it does not exist
|
||||
size_t delimiter_pos = name.rfind(kDirectoryDelimiter);
|
||||
@@ -154,15 +155,15 @@ File* FileSystem::Open(const std::string& in_name, int flags) {
|
||||
}
|
||||
|
||||
bool FileSystem::Exists(const std::string& path) {
|
||||
return FileUtils::Exists(GetFileNameForOrigin(path, origin_));
|
||||
return FileUtils::Exists(GetFileNameForIdentifier(path, identifier_));
|
||||
}
|
||||
|
||||
bool FileSystem::Remove(const std::string& path) {
|
||||
return FileUtils::Remove(GetFileNameForOrigin(path, origin_));
|
||||
return FileUtils::Remove(GetFileNameForIdentifier(path, identifier_));
|
||||
}
|
||||
|
||||
ssize_t FileSystem::FileSize(const std::string& in_path) {
|
||||
std::string path = GetFileNameForOrigin(in_path, origin_);
|
||||
std::string path = GetFileNameForIdentifier(in_path, identifier_);
|
||||
struct stat buf;
|
||||
if (stat(path.c_str(), &buf) == 0)
|
||||
return buf.st_size;
|
||||
@@ -172,4 +173,8 @@ ssize_t FileSystem::FileSize(const std::string& in_path) {
|
||||
|
||||
void FileSystem::SetOrigin(const std::string& origin) { origin_ = origin; }
|
||||
|
||||
void FileSystem::SetIdentifier(const std::string& identifier) {
|
||||
identifier_ = identifier;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -155,4 +155,8 @@ bool Properties::AlwaysUseKeySetIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Properties::UseProviderIdInProvisioningRequest() {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -44,7 +44,7 @@ bool WvContentDecryptionModule::IsHls(const std::string& init_data_type) {
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||
const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
|
||||
const std::string& origin, WvCdmEventListener* event_listener,
|
||||
const CdmIdentifier& identifier, WvCdmEventListener* event_listener,
|
||||
CdmSessionId* session_id) {
|
||||
if (property_set && property_set->is_session_sharing_enabled()) {
|
||||
AutoLock auto_lock(session_sharing_id_generation_lock_);
|
||||
@@ -52,7 +52,7 @@ CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||
property_set->set_session_sharing_id(GenerateSessionSharingId());
|
||||
}
|
||||
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||
CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set,
|
||||
event_listener, session_id);
|
||||
if (sts == NO_ERROR) {
|
||||
@@ -83,9 +83,9 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
|
||||
const CdmSessionId& session_id, const CdmKeySetId& key_set_id,
|
||||
const std::string& init_data_type, const CdmInitData& init_data,
|
||||
const CdmLicenseType license_type, CdmAppParameterMap& app_parameters,
|
||||
CdmClientPropertySet* property_set, const std::string& origin,
|
||||
CdmClientPropertySet* property_set, const CdmIdentifier& identifier,
|
||||
CdmKeyRequest* key_request) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||
CdmResponseType sts;
|
||||
if (license_type == kLicenseTypeRelease) {
|
||||
sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, NULL);
|
||||
@@ -149,7 +149,7 @@ CdmResponseType WvContentDecryptionModule::QueryStatus(
|
||||
SecurityLevel security_level,
|
||||
const std::string& key,
|
||||
std::string* value) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(kDefaultCdmIdentifier);
|
||||
return cdm_engine->QueryStatus(security_level, key, value);
|
||||
}
|
||||
|
||||
@@ -177,32 +177,32 @@ CdmResponseType WvContentDecryptionModule::QueryOemCryptoSessionId(
|
||||
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
|
||||
CdmCertificateType cert_type,
|
||||
const std::string& cert_authority,
|
||||
const std::string& origin,
|
||||
const CdmIdentifier& identifier,
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||
return cdm_engine->GetProvisioningRequest(cert_type, cert_authority, request,
|
||||
default_url);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
|
||||
const std::string& origin,
|
||||
const CdmIdentifier& identifier,
|
||||
CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||
return cdm_engine->HandleProvisioningResponse(response, cert, wrapped_key);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::Unprovision(
|
||||
CdmSecurityLevel level, const std::string& origin) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
|
||||
CdmSecurityLevel level, const CdmIdentifier& identifier) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
|
||||
return cdm_engine->Unprovision(level);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
|
||||
const std::string& app_id, CdmUsageInfo* usage_info) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(kDefaultCdmIdentifier);
|
||||
return cdm_engine->GetUsageInfo(app_id, usage_info);
|
||||
}
|
||||
|
||||
@@ -210,19 +210,19 @@ CdmResponseType WvContentDecryptionModule::GetUsageInfo(
|
||||
const std::string& app_id,
|
||||
const CdmSecureStopId& ssid,
|
||||
CdmUsageInfo* usage_info) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(kDefaultCdmIdentifier);
|
||||
return cdm_engine->GetUsageInfo(app_id, ssid, usage_info);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::ReleaseAllUsageInfo(
|
||||
const std::string& app_id) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(kDefaultCdmIdentifier);
|
||||
return cdm_engine->ReleaseAllUsageInfo(app_id);
|
||||
}
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
|
||||
const CdmUsageInfoReleaseMessage& message) {
|
||||
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
|
||||
CdmEngine* cdm_engine = EnsureCdmForIdentifier(kDefaultCdmIdentifier);
|
||||
return cdm_engine->ReleaseUsageInfo(message);
|
||||
}
|
||||
|
||||
@@ -265,15 +265,21 @@ bool WvContentDecryptionModule::IsValidServiceCertificate(
|
||||
WvContentDecryptionModule::CdmInfo::CdmInfo()
|
||||
: cdm_engine(new CdmEngine(&file_system)) {}
|
||||
|
||||
CdmEngine* WvContentDecryptionModule::EnsureCdmForOrigin(
|
||||
const std::string& origin) {
|
||||
CdmEngine* WvContentDecryptionModule::EnsureCdmForIdentifier(
|
||||
const CdmIdentifier& identifier) {
|
||||
AutoLock auto_lock(cdms_lock_);
|
||||
if (cdms_.find(origin) == cdms_.end()) {
|
||||
// Will create a new instance using the default constructor.
|
||||
cdms_[origin].file_system.SetOrigin(origin);
|
||||
if (cdms_.find(identifier) == cdms_.end()) {
|
||||
// Accessing the map entry will create a new instance using the default
|
||||
// constructor. We then need to provide it with two pieces of info: The
|
||||
// origin provided by the app and an identifier that uniquely identifies
|
||||
// this CDM. We concatenate all pieces of the CdmIdentifier in order to
|
||||
// create an ID that is unique to that identifier.
|
||||
cdms_[identifier].file_system.SetOrigin(identifier.origin);
|
||||
cdms_[identifier].file_system.SetIdentifier(
|
||||
identifier.spoid + identifier.origin);
|
||||
}
|
||||
|
||||
return cdms_[origin].cdm_engine.get();
|
||||
return cdms_[identifier].cdm_engine.get();
|
||||
}
|
||||
|
||||
CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
|
||||
@@ -299,7 +305,7 @@ void WvContentDecryptionModule::DisablePolicyTimer(bool force) {
|
||||
has_sessions = true;
|
||||
++it;
|
||||
} else {
|
||||
// The CDM is no longer used for this origin, delete it.
|
||||
// The CDM is no longer used for this identifier, delete it.
|
||||
it = cdms_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user