Merge "Support Per-Origin Provisioning"
This commit is contained in:
committed by
Android (Google) Code Review
commit
bf5515faa1
@@ -76,6 +76,7 @@ CdmEngine::~CdmEngine() {
|
||||
|
||||
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
const CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener,
|
||||
CdmSessionId* session_id) {
|
||||
LOGI("CdmEngine::OpenSession");
|
||||
@@ -91,7 +92,7 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
}
|
||||
|
||||
scoped_ptr<CdmSession> new_session(
|
||||
new CdmSession(property_set, event_listener));
|
||||
new CdmSession(property_set, origin, event_listener));
|
||||
if (new_session->session_id().empty()) {
|
||||
LOGE("CdmEngine::OpenSession: failure to generate session ID");
|
||||
return UNKNOWN_ERROR;
|
||||
@@ -115,7 +116,7 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
|
||||
CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
const CdmKeySetId& key_set_id, const CdmClientPropertySet* property_set,
|
||||
WvCdmEventListener* event_listener) {
|
||||
const std::string& origin, WvCdmEventListener* event_listener) {
|
||||
LOGI("CdmEngine::OpenKeySetSession");
|
||||
|
||||
if (key_set_id.empty()) {
|
||||
@@ -125,7 +126,8 @@ CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
|
||||
CdmSessionId session_id;
|
||||
CdmResponseType sts =
|
||||
OpenSession(KEY_SYSTEM, property_set, event_listener, &session_id);
|
||||
OpenSession(KEY_SYSTEM, property_set, origin, event_listener,
|
||||
&session_id);
|
||||
|
||||
if (sts != NO_ERROR) return sts;
|
||||
|
||||
@@ -503,9 +505,10 @@ CdmResponseType CdmEngine::QueryKeyControlInfo(const CdmSessionId& session_id,
|
||||
*/
|
||||
CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||
CdmProvisioningRequest* request, std::string* default_url) {
|
||||
const std::string& origin, CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
if (!request || !default_url) {
|
||||
LOGE("CdmEngine::GetProvisioningRequest: invalid input parameters");
|
||||
LOGE("CdmEngine::GetProvisioningRequest: invalid output parameters");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (NULL == cert_provisioning_.get()) {
|
||||
@@ -513,7 +516,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
}
|
||||
CdmResponseType ret = cert_provisioning_->GetProvisioningRequest(
|
||||
cert_provisioning_requested_security_level_, cert_type, cert_authority,
|
||||
request, default_url);
|
||||
origin, request, default_url);
|
||||
if (ret != NO_ERROR) {
|
||||
cert_provisioning_.reset(NULL); // Release resources.
|
||||
}
|
||||
@@ -528,8 +531,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response, std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
const std::string& origin, CdmProvisioningResponse& response,
|
||||
std::string* cert, std::string* wrapped_key) {
|
||||
if (response.empty()) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
|
||||
cert_provisioning_.reset(NULL);
|
||||
@@ -553,35 +556,55 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
CdmResponseType ret = cert_provisioning_->HandleProvisioningResponse(
|
||||
response, cert, wrapped_key);
|
||||
origin, response, cert, wrapped_key);
|
||||
cert_provisioning_.reset(NULL); // Release resources.
|
||||
return ret;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
bool CdmEngine::IsProvisioned(CdmSecurityLevel security_level,
|
||||
const std::string& origin) {
|
||||
DeviceFiles handle;
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::IsProvisioned: unable to initialize device files");
|
||||
return false;
|
||||
}
|
||||
return handle.HasCertificate(origin);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level,
|
||||
const std::string& origin) {
|
||||
DeviceFiles handle;
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::Unprovision: unable to initialize device files");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (!handle.DeleteAllFiles()) {
|
||||
LOGE("CdmEngine::Unprovision: unable to delete files");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (origin != EMPTY_ORIGIN) {
|
||||
if (!handle.RemoveCertificate(origin)) {
|
||||
LOGE("CdmEngine::Unprovision: unable to delete certificate for origin %s",
|
||||
origin.c_str());
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return NO_ERROR;
|
||||
} else {
|
||||
if (!handle.DeleteAllFiles()) {
|
||||
LOGE("CdmEngine::Unprovision: unable to delete files");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
scoped_ptr<CryptoSession> crypto_session(new CryptoSession());
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::Unprovision: error opening crypto session: %d", status);
|
||||
return UNKNOWN_ERROR;
|
||||
scoped_ptr<CryptoSession> crypto_session(new CryptoSession());
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::Unprovision: error opening crypto session: %d", status);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
status = crypto_session->DeleteAllUsageReports();
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("CdmEngine::Unprovision: error deleteing usage reports: %d", status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
status = crypto_session->DeleteAllUsageReports();
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("CdmEngine::Unprovision: error deleteing usage reports: %d", status);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
@@ -592,7 +615,8 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
}
|
||||
usage_property_set_->set_security_level(kLevelDefault);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
usage_session_.reset(new CdmSession(usage_property_set_.get(), NULL));
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL));
|
||||
CdmResponseType status = usage_session_->Init();
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: session init error");
|
||||
@@ -610,7 +634,8 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
&license_response)) {
|
||||
usage_property_set_->set_security_level(kLevel3);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
usage_session_.reset(new CdmSession(usage_property_set_.get(), NULL));
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL));
|
||||
status = usage_session_->Init();
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: session init error");
|
||||
@@ -678,7 +703,8 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
usage_property_set_->set_security_level(requested_security_level);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
|
||||
usage_session_.reset(new CdmSession(usage_property_set_.get(), NULL));
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL));
|
||||
|
||||
CdmResponseType status = usage_session_->Init();
|
||||
if (NO_ERROR != status) {
|
||||
|
||||
@@ -24,9 +24,11 @@ const size_t kKeySetIdLength = 14;
|
||||
namespace wvcdm {
|
||||
|
||||
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener)
|
||||
: initialized_(false),
|
||||
session_id_(GenerateSessionId()),
|
||||
origin_(origin),
|
||||
license_parser_(new CdmLicense),
|
||||
crypto_session_(new CryptoSession),
|
||||
policy_engine_(
|
||||
@@ -70,7 +72,7 @@ CdmResponseType CdmSession::Init() {
|
||||
if (Properties::use_certificates_as_identification()) {
|
||||
std::string wrapped_key;
|
||||
if (!file_handle_->Init(security_level_) ||
|
||||
!file_handle_->RetrieveCertificate(&token, &wrapped_key) ||
|
||||
!file_handle_->RetrieveCertificate(origin_, &token, &wrapped_key) ||
|
||||
!crypto_session_->LoadCertificatePrivateKey(wrapped_key)) {
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
|
||||
@@ -57,8 +57,8 @@ void CertificateProvisioning::ComposeJsonRequestAsQueryString(
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
SecurityLevel requested_security_level, CdmCertificateType cert_type,
|
||||
const std::string& cert_authority, CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
const std::string& cert_authority, const std::string& origin,
|
||||
CdmProvisioningRequest* request, std::string* default_url) {
|
||||
if (!default_url) {
|
||||
LOGE("GetProvisioningRequest: pointer for returning URL is NULL");
|
||||
return UNKNOWN_ERROR;
|
||||
@@ -113,6 +113,15 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
cert_type_ = cert_type;
|
||||
options->set_certificate_authority(cert_authority);
|
||||
|
||||
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 UNKNOWN_ERROR;
|
||||
}
|
||||
provisioning_request.set_stable_id(device_unique_id + origin);
|
||||
}
|
||||
|
||||
std::string serialized_message;
|
||||
provisioning_request.SerializeToString(&serialized_message);
|
||||
|
||||
@@ -180,8 +189,8 @@ bool CertificateProvisioning::ParseJsonResponse(
|
||||
* Returns NO_ERROR for success and UNKNOWN_ERROR if fails.
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
CdmProvisioningResponse& response, std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
const std::string& origin, CdmProvisioningResponse& response,
|
||||
std::string* cert, std::string* wrapped_key) {
|
||||
// Extracts signed response from JSON string, decodes base64 signed response
|
||||
const std::string kMessageStart = "\"signedResponse\": \"";
|
||||
const std::string kMessageEnd = "\"";
|
||||
@@ -255,7 +264,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
LOGE("HandleProvisioningResponse: failed to init DeviceFiles");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (!handle.StoreCertificate(device_certificate, wrapped_rsa_key)) {
|
||||
if (!handle.StoreCertificate(origin, device_certificate, wrapped_rsa_key)) {
|
||||
LOGE("HandleProvisioningResponse: failed to save provisioning certificate");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
@@ -31,7 +32,8 @@ using video_widevine_client::sdk::UsageInfo_ProviderSession;
|
||||
|
||||
namespace {
|
||||
|
||||
const char kCertificateFileName[] = "cert.bin";
|
||||
const char kCertificateFileNamePrefix[] = "cert";
|
||||
const char kCertificateFileNameExt[] = ".bin";
|
||||
const char kUsageInfoFileNamePrefix[] = "usage";
|
||||
const char kUsageInfoFileNameExt[] = ".bin";
|
||||
const char kLicenseFileNameExt[] = ".lic";
|
||||
@@ -86,7 +88,8 @@ bool DeviceFiles::Init(CdmSecurityLevel security_level) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreCertificate(const std::string& certificate,
|
||||
bool DeviceFiles::StoreCertificate(const std::string& origin,
|
||||
const std::string& certificate,
|
||||
const std::string& wrapped_private_key) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::StoreCertificate: not initialized");
|
||||
@@ -106,10 +109,11 @@ bool DeviceFiles::StoreCertificate(const std::string& certificate,
|
||||
std::string serialized_file;
|
||||
file.SerializeToString(&serialized_file);
|
||||
|
||||
return StoreFileWithHash(kCertificateFileName, serialized_file);
|
||||
return StoreFileWithHash(GetCertificateFileName(origin), serialized_file);
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
bool DeviceFiles::RetrieveCertificate(const std::string& origin,
|
||||
std::string* certificate,
|
||||
std::string* wrapped_private_key) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RetrieveCertificate: not initialized");
|
||||
@@ -121,7 +125,9 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
}
|
||||
|
||||
std::string serialized_file;
|
||||
if (!RetrieveHashedFile(kCertificateFileName, &serialized_file)) return false;
|
||||
if (!RetrieveHashedFile(GetCertificateFileName(origin), &serialized_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (!file.ParseFromString(serialized_file)) {
|
||||
@@ -151,6 +157,24 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::HasCertificate(const std::string& origin) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::HasCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return FileExists(GetCertificateFileName(origin));
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveCertificate(const std::string& origin) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RemoveCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return RemoveFile(GetCertificateFileName(origin));
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreLicense(const std::string& key_set_id,
|
||||
const LicenseState state,
|
||||
const CdmInitData& pssh_data,
|
||||
@@ -749,8 +773,12 @@ void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetCertificateFileName() {
|
||||
return kCertificateFileName;
|
||||
std::string DeviceFiles::GetCertificateFileName(const std::string& origin) {
|
||||
std::string hash;
|
||||
if (origin != EMPTY_ORIGIN) {
|
||||
hash = GetFileNameSafeHash(origin);
|
||||
}
|
||||
return kCertificateFileNamePrefix + hash + kCertificateFileNameExt;
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetLicenseFileNameExtension() {
|
||||
@@ -758,20 +786,23 @@ std::string DeviceFiles::GetLicenseFileNameExtension() {
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) {
|
||||
if (app_id == "") {
|
||||
return std::string(kUsageInfoFileNamePrefix) +
|
||||
std::string(kUsageInfoFileNameExt);
|
||||
std::string hash;
|
||||
if (app_id != "") {
|
||||
hash = GetFileNameSafeHash(app_id);
|
||||
}
|
||||
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
|
||||
const unsigned char* input =
|
||||
reinterpret_cast<const unsigned char*>(app_id.data());
|
||||
MD5(input, app_id.size(), &hash[0]);
|
||||
return std::string(kUsageInfoFileNamePrefix) + wvcdm::Base64SafeEncode(hash) +
|
||||
std::string(kUsageInfoFileNameExt);
|
||||
return kUsageInfoFileNamePrefix + hash + kUsageInfoFileNameExt;
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetBlankFileData() { return kBlankFileData; }
|
||||
|
||||
std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) {
|
||||
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
|
||||
const unsigned char* input_ptr =
|
||||
reinterpret_cast<const unsigned char*>(input.data());
|
||||
MD5(input_ptr, input.size(), &hash[0]);
|
||||
return wvcdm::Base64SafeEncode(hash);
|
||||
}
|
||||
|
||||
void DeviceFiles::SetTestFile(File* file) {
|
||||
file_.reset(file);
|
||||
test_file_ = true;
|
||||
|
||||
Reference in New Issue
Block a user