(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:
John W. Bruce
2017-01-25 14:35:50 -08:00
parent 5249221e3a
commit c85351682f
18 changed files with 511 additions and 290 deletions

View File

@@ -13,6 +13,7 @@
#include "lock.h"
#include "oemcrypto_adapter.h"
#include "scoped_ptr.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_types.h"
namespace wvcdm {
@@ -31,7 +32,7 @@ typedef std::map<
class CdmEngine {
public:
CdmEngine(FileSystem* file_system);
CdmEngine(FileSystem* file_system, const std::string& spoid = EMPTY_SPOID);
virtual ~CdmEngine();
// Session related methods
@@ -236,6 +237,7 @@ class CdmEngine {
SecurityLevel cert_provisioning_requested_security_level_;
FileSystem* file_system_;
Clock clock_;
std::string spoid_;
static bool seeded_;

View File

@@ -27,6 +27,7 @@ class CertificateProvisioning {
CdmCertificateType cert_type,
const std::string& cert_authority,
const std::string& origin,
const std::string& spoid,
CdmProvisioningRequest* request,
std::string* default_url);
CdmResponseType HandleProvisioningResponse(
@@ -39,6 +40,9 @@ class CertificateProvisioning {
bool GetProvisioningTokenType(
video_widevine::ClientIdentification::TokenType* token_type);
bool FillStableIdField(const std::string& origin, const std::string& spoid,
video_widevine::ProvisioningRequest* request);
video_widevine::SignedProvisioningMessage::ProtocolVersion
GetProtocolVersion();

View File

@@ -58,9 +58,14 @@ class FileSystem {
const std::string& origin() const { return origin_; }
void SetOrigin(const std::string& origin);
const std::string& identifier() const { return identifier_; }
void SetIdentifier(const std::string& identifier);
bool IsGlobal() const { return identifier_.empty(); }
private:
Impl* impl_;
std::string origin_;
std::string identifier_;
CORE_DISALLOW_COPY_AND_ASSIGN(FileSystem);
};

View File

@@ -55,6 +55,7 @@ class Properties {
static bool GetFactoryKeyboxPath(std::string* keybox);
static bool GetOEMCryptoPath(std::string* library_name);
static bool AlwaysUseKeySetIds();
static bool UseProviderIdInProvisioningRequest();
static bool GetSecurityLevelDirectories(std::vector<std::string>* dirs);
static bool GetApplicationId(const CdmSessionId& session_id,

View File

@@ -98,6 +98,7 @@ static const std::string HLS_IV_ATTRIBUTE = "IV";
static const std::string HLS_URI_ATTRIBUTE = "URI";
static const char EMPTY_ORIGIN[] = "";
static const char EMPTY_SPOID[] = "";
} // namespace wvcdm
#endif // WVCDM_CORE_WV_CDM_CONSTANTS_H_

View File

@@ -60,10 +60,11 @@ class UsagePropertySet : public CdmClientPropertySet {
bool CdmEngine::seeded_ = false;
CdmEngine::CdmEngine(FileSystem* file_system)
CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid)
: cert_provisioning_(NULL),
cert_provisioning_requested_security_level_(kLevelDefault),
file_system_(file_system),
spoid_(spoid),
usage_session_(NULL),
last_usage_information_update_time_(0) {
assert(file_system);
@@ -718,7 +719,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
}
CdmResponseType ret = cert_provisioning_->GetProvisioningRequest(
cert_provisioning_requested_security_level_, cert_type, cert_authority,
file_system_->origin(), request, default_url);
file_system_->origin(), spoid_, request, default_url);
if (ret != NO_ERROR) {
cert_provisioning_.reset(NULL); // Release resources.
}
@@ -801,7 +802,7 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
return UNPROVISION_ERROR_1;
}
if (!file_system_->origin().empty()) {
if (!file_system_->IsGlobal()) {
if (!handle.RemoveCertificate()) {
LOGE("CdmEngine::Unprovision: unable to delete certificate");
return UNPROVISION_ERROR_2;
@@ -813,14 +814,14 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
return UNPROVISION_ERROR_3;
}
scoped_ptr<CryptoSession> crypto_session(new CryptoSession());
CdmResponseType status = crypto_session->Open(
CryptoSession crypto_session;
CdmResponseType status = crypto_session.Open(
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
if (NO_ERROR != status) {
LOGE("CdmEngine::Unprovision: error opening crypto session: %d", status);
return UNPROVISION_ERROR_4;
}
status = crypto_session->DeleteAllUsageReports();
status = crypto_session.DeleteAllUsageReports();
if (status != NO_ERROR) {
LOGE("CdmEngine::Unprovision: error deleteing usage reports: %d", status);
}

View File

@@ -5,6 +5,7 @@
#include "file_store.h"
#include "license_protocol.pb.h"
#include "log.h"
#include "properties.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
@@ -68,6 +69,43 @@ bool CertificateProvisioning::GetProvisioningTokenType(
}
}
/*
* Fill in the appropriate field relating to stable IDs in the provisioning
* request, no more than one of |stable_id|, |provider_id|, and |spoid|. It is
* also valid (though deprecated) to fill in none of these in order to leave the
* stable ID behavior up to the provisioning server.
*/
bool CertificateProvisioning::FillStableIdField(
const std::string& origin,
const std::string& spoid,
ProvisioningRequest* request) {
if (!request) {
LOGE("CertificateProvisioning::FillStableIdField : No request buffer "
"passed to method.");
return false;
}
if (!spoid.empty()) {
// Use the SPOID that has been pre-provided
request->set_spoid(spoid);
} else if (Properties::UseProviderIdInProvisioningRequest() &&
false /* TODO(gmorgan): use provider ID. */) {
// Use the provider ID from the service certificate
// TODO(gmorgan): use provider ID.
// request->set_provider_id(???);
} else if (origin != EMPTY_ORIGIN) {
// Legacy behavior - Concatenate Unique ID with Origin
std::string device_unique_id;
if (!crypto_session_.GetDeviceUniqueId(&device_unique_id)) {
LOGE("CryptoSession::GetStableIdField: Failure to get device unique ID");
return false;
}
request->set_stable_id(device_unique_id + origin);
} // No else clause, by design. It is valid to do nothing.
return true;
}
/*
* Return the provisioning protocol version - dictated by OEMCrypto
* support for OEM certificates.
@@ -90,6 +128,7 @@ SignedProvisioningMessage::ProtocolVersion
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) {
if (!default_url) {
LOGE("GetProvisioningRequest: pointer for returning URL is NULL");
@@ -165,15 +204,8 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
cert_type_ = cert_type;
options->set_certificate_authority(cert_authority);
// TODO(gmorgan): use provider ID.
if (origin != EMPTY_ORIGIN) {
std::string device_unique_id;
if (!crypto_session_.GetDeviceUniqueId(&device_unique_id)) {
LOGE("GetProvisioningRequest: fails to get device unique ID");
return CERT_PROVISIONING_GET_KEYBOX_ERROR_2;
}
// TODO(gmorgan): handle provider id variants.
provisioning_request.set_stable_id(device_unique_id + origin);
if (!FillStableIdField(origin, spoid, &provisioning_request)) {
return CERT_PROVISIONING_GET_KEYBOX_ERROR_2;
}
std::string serialized_message;

View File

@@ -218,27 +218,29 @@ bool CryptoSession::GetDeviceUniqueId(std::string* device_id) {
return false;
}
std::vector<uint8_t> id;
size_t id_length = 32;
id.resize(id_length);
LOGV("CryptoSession::GetDeviceUniqueId: Lock");
AutoLock auto_lock(crypto_lock_);
if (!initialized_) {
return false;
}
if (pre_provision_token_type_ == kClientTokenKeybox) {
if (pre_provision_token_type_ == kClientTokenOemCert) {
return GetTokenFromOemCert(device_id);
} else {
std::vector<uint8_t> id;
size_t id_length = 32;
id.resize(id_length);
OEMCryptoResult sts =
OEMCrypto_GetDeviceID(&id[0], &id_length, requested_security_level_);
if (OEMCrypto_SUCCESS != sts) {
return false;
}
}
device_id->assign(reinterpret_cast<char*>(&id[0]), id_length);
return true;
device_id->assign(reinterpret_cast<char*>(&id[0]), id_length);
return true;
}
}
bool CryptoSession::GetApiVersion(uint32_t* version) {