Merge Changes from CDM repository

This CL merges the following changes from the Widevine repository:

Avoid CdmSession reinitialization
https://widevine-internal-review.googlesource.com/#/c/10530/

Fix timer-related unit tests.
https://widevine-internal-review.googlesource.com/#/c/10510/

Correct return statement
bug: 15590802
https://widevine-internal-review.googlesource.com/#/c/10553/

Usage reporting fixes
bug/15388863
https://widevine-internal-review.googlesource.com/#/c/10460/

Make public methods virtual
https://widevine-internal-review.googlesource.com/#/c/10500/

Fix the SetTimer contract in the CDM.
https://widevine-internal-review.googlesource.com/#/c/10493/

Move inline CDM methods, add OVERRIDE.
https://widevine-internal-review.googlesource.com/#/c/10475/

Simplify storage APIs related cleanup.
https://widevine-internal-review.googlesource.com/#/c/10473/

Duration values are not correctly reported when queried
b/15592374
https://widevine-internal-review.googlesource.com/#/c/10437/

Propagate IsKeyValid() through ContentDecryptionModule.
https://widevine-internal-review.googlesource.com/#/c/10483/

Minor clean up in config_test_env.
https://widevine-internal-review.googlesource.com/#/c/10440/

General clean up.
https://widevine-internal-review.googlesource.com/#/c/10441/

Refactor HttpSocket and simplify UrlRequest interface.
https://widevine-internal-review.googlesource.com/#/c/10410/

Install good keybox at end of unit tests
b/15385981
https://widevine-internal-review.googlesource.com/#/c/10374/

Privacy crypto fixes
b/15475012
https://widevine-internal-review.googlesource.com/#/c/10383/

Incorporate header files to resolve build issued based on customers feedback.
https://widevine-internal-review.googlesource.com/#/c/10420/

Support unprovisioning
b/12247651
https://widevine-internal-review.googlesource.com/#/c/10356/

Correct usage of Host::Allocate and Cdm::Decrypt.
https://widevine-internal-review.googlesource.com/#/c/10378/

Fix logging bug, arguments in wrong order.
https://widevine-internal-review.googlesource.com/#/c/10380/

Rename types that look like constants.
https://widevine-internal-review.googlesource.com/#/c/10379/

Fix offline test failures
b/13909635
https://widevine-internal-review.googlesource.com/#/c/10348/

Add -DUNIT_TEST to the unit test makefile for Android
https://widevine-internal-review.googlesource.com/#/c/10375/

Refactor privacy-crypto and add dummy version.
https://widevine-internal-review.googlesource.com/#/c/10353/

Remove References to Apiary
https://widevine-internal-review.googlesource.com/#/c/9924/

Delete oldest entry in usage table when full
bug: 15184824
https://widevine-internal-review.googlesource.com/#/c/10295/

Port DeviceFiles to iOS.
https://widevine-internal-review.googlesource.com/#/c/10355/

Make testing functions in DeviceFiles private.
https://widevine-internal-review.googlesource.com/#/c/10354/

Add RSA encryption to haystack
https://widevine-internal-review.googlesource.com/#/c/10280/

Add string and vector includes to CDM header.
https://widevine-internal-review.googlesource.com/#/c/10352/

First version of oemcrypto logging
https://widevine-internal-review.googlesource.com/#/c/10252/

Update Names of Secure Stop Methods
bug: 11987015
https://widevine-internal-review.googlesource.com/#/c/10152/

Adjust timing on the Usage Table unit test
https://widevine-internal-review.googlesource.com/#/c/10307/

Fix all compiler warnings in CDM source release.
https://widevine-internal-review.googlesource.com/#/c/10293/

Fix memset bug: args in wrong order
https://widevine-internal-review.googlesource.com/#/c/10292/

Partial revert of 'Remove refs to test prov server, Level3 support...'
https://widevine-internal-review.googlesource.com/#/c/10281/

Pack structure OEMCrypto_PST_Report
https://widevine-internal-review.googlesource.com/#/c/10243/

Remove refs to test prov server, Level3 support; remove dead code
https://widevine-internal-review.googlesource.com/#/c/10220/

Partial revert of 'Document data strings; clean up license server parameters.'
https://widevine-internal-review.googlesource.com/#/c/10188/

Document data strings; clean up license server parameters.
https://widevine-internal-review.googlesource.com/#/c/10120/

Fix broken build after partner branch merge.
https://widevine-internal-review.googlesource.com/#/c/10181/

TODO Cleanup - core/src, core/include
https://widevine-internal-review.googlesource.com/#/c/9965/

TODO Cleanup - cdm, chromium, core/test.
https://widevine-internal-review.googlesource.com/#/c/9419/

Remove unneeded properties.
https://widevine-internal-review.googlesource.com/#/c/10162/

Change-Id: If2bb9d743a562a3875bebb91933c0aaadea286b2
This commit is contained in:
Fred Gylys-Colwell
2014-06-25 13:02:54 -07:00
parent 8a8feb747c
commit b5e8b87fed
66 changed files with 2927 additions and 1998 deletions

View File

@@ -2,6 +2,8 @@
#include "cdm_engine.h"
#include <stdlib.h>
#include <iostream>
#include <sstream>
@@ -18,27 +20,30 @@
namespace {
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
const size_t kMinNoncesPerSession = 4;
const size_t kUsageReportsPerRequest = 1;
} // unnamed namespace
namespace wvcdm {
bool CdmEngine::seeded_ = false;
CdmEngine::CdmEngine()
: cert_provisioning_requested_security_level_(kLevelDefault),
usage_session_(NULL),
last_usage_information_update_time(0) {
Properties::Init();
if (!seeded_) {
Clock clock;
srand(clock.GetCurrentTime());
seeded_ = true;
}
}
CdmEngine::~CdmEngine() {
CancelSessions();
if (NULL != usage_session_)
delete usage_session_;
CdmSessionMap::iterator i(sessions_.begin());
for (; i != sessions_.end(); ++i)
for (; i != sessions_.end(); ++i) {
delete i->second;
}
sessions_.clear();
}
@@ -286,9 +291,6 @@ CdmResponseType CdmEngine::RestoreKey(
CdmResponseType CdmEngine::CancelKeyRequest(const CdmSessionId& session_id) {
LOGI("CdmEngine::CancelKeyRequest");
//TODO(gmorgan): Issue: what is semantics of canceling a key request. Should
//this call cancel all keys for the session?
CdmSessionMap::iterator iter = sessions_.find(session_id);
if (iter == sessions_.end()) {
LOGE("CdmEngine::CancelKeyRequest: session_id not found = %s",
@@ -494,11 +496,23 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
wrapped_key);
}
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
if (NULL == usage_session_) {
usage_session_ = new CdmSession(NULL);
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
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;
}
return NO_ERROR;
}
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
usage_session_.reset(new CdmSession(NULL));
CdmResponseType status = usage_session_->Init();
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
@@ -523,35 +537,32 @@ CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
}
std::string server_url;
// rate limit secure stop messages based on minimum nonce
// table size per session
usage_info->resize(license_info.size() >= kMinNoncesPerSession - 1
? kMinNoncesPerSession - 1
: license_info.size());
for (size_t i = 0; i < usage_info->size(); ++i) {
status = usage_session_->RestoreUsageSession(license_info[i].first,
license_info[i].second);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session error: %ld",
status);
usage_info->clear();
return status;
}
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[i],
&server_url);
if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
status);
usage_info->clear();
return status;
}
usage_info->resize(kUsageReportsPerRequest);
uint32_t index = rand() % license_info.size();
status = usage_session_->RestoreUsageSession(license_info[index].first,
license_info[index].second);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session (%d) error %ld",
index, status);
usage_info->clear();
return status;
}
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[0], &server_url);
if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
status);
usage_info->clear();
return status;
}
return KEY_MESSAGE;
}
CdmResponseType CdmEngine::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) {
if (NULL == usage_session_) {
if (NULL == usage_session_.get()) {
LOGE("CdmEngine::ReleaseUsageInfo: cdm session not initialized");
return UNKNOWN_ERROR;
}
@@ -559,9 +570,8 @@ CdmResponseType CdmEngine::ReleaseUsageInfo(
CdmResponseType status = usage_session_->ReleaseKey(message);
if (NO_ERROR != status) {
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %ld", status);
return UNKNOWN_ERROR;
}
return NO_ERROR;
return status;
}
CdmResponseType CdmEngine::Decrypt(
@@ -588,23 +598,23 @@ CdmResponseType CdmEngine::Decrypt(
LOGE("CdmEngine::Decrypt: no dest decrypt buffer");
return KEY_ERROR;
} // else we must be level 1 direct and we don't need to return a buffer.
// TODO:(eschacker) look at renaming Properties::oem_crypto_use_fifo()
// to something like Properties::oem_crypto_use_direct_rendering().
}
CdmSessionMap::iterator iter;
if (session_id.empty()) {
if (!Properties::decrypt_with_empty_session_support()) return KEY_ERROR;
// Loop through the sessions to find the session containing the key_id.
for (iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
if (iter->second->IsKeyLoaded(*parameters.key_id)) break;
if (iter->second->IsKeyLoaded(*parameters.key_id)) {
break;
}
}
} else {
iter = sessions_.find(session_id);
}
if (iter == sessions_.end()) {
LOGE("CdmEngine::Decrypt: session_id not found = %s", session_id.c_str());
LOGE("CdmEngine::Decrypt: session not found: id=%s, id size=%d",
session_id.c_str(),
session_id.size());
return KEY_ERROR;
}
@@ -679,11 +689,6 @@ bool CdmEngine::ValidateKeySystem(const CdmKeySystem& key_system) {
return (key_system.find("widevine") != std::string::npos);
}
bool CdmEngine::CancelSessions() {
// TODO(gmorgan) Implement CancelSessions()
return true;
}
void CdmEngine::OnTimerEvent() {
Clock clock;
uint64_t current_time = clock.GetCurrentTime();

View File

@@ -1,5 +1,4 @@
// Copyright 2012 Google Inc. All Rights Reserved.
// Author: jfore@google.com (Jeff Fore), rkuroiwa@google.com (Rintaro Kuroiwa)
#include "cdm_session.h"
@@ -30,11 +29,10 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set)
: session_id_(GenerateSessionId()),
crypto_session_(NULL),
license_received_(false),
reinitialize_session_(false),
is_offline_(false),
is_release_(false),
is_usage_update_needed_(false),
is_certificate_loaded_(false) {
is_initial_decryption_(true) {
if (cdm_client_property_set) {
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
}
@@ -51,8 +49,10 @@ CdmResponseType CdmSession::Init() {
std::string token;
if (Properties::use_certificates_as_identification()) {
DeviceFiles handle;
std::string wrapped_key;
if (!handle.Init(session.get()->GetSecurityLevel()) ||
!handle.RetrieveCertificate(&token, &wrapped_key_)) {
!handle.RetrieveCertificate(&token, &wrapped_key) ||
!session->LoadCertificatePrivateKey(wrapped_key)) {
return NEED_PROVISIONING;
}
} else {
@@ -64,7 +64,7 @@ CdmResponseType CdmSession::Init() {
crypto_session_.reset(session.release());
license_received_ = false;
reinitialize_session_ = false;
is_initial_decryption_ = true;
return NO_ERROR;
}
@@ -94,15 +94,6 @@ CdmResponseType CdmSession::RestoreOfflineSession(
return UNKNOWN_ERROR;
}
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
return NEED_PROVISIONING;
}
}
if (!license_parser_.RestoreOfflineLicense(key_request_, key_response_,
offline_key_renewal_response_)) {
return UNKNOWN_ERROR;
@@ -120,15 +111,6 @@ CdmResponseType CdmSession::RestoreUsageSession(
key_request_ = key_request;
key_response_ = key_response;
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
return NEED_PROVISIONING;
}
}
if (!license_parser_.RestoreUsageLicense(key_request_, key_response_)) {
return UNKNOWN_ERROR;
}
@@ -139,25 +121,10 @@ CdmResponseType CdmSession::RestoreUsageSession(
return KEY_ADDED;
}
bool CdmSession::VerifySession(const CdmKeySystem& key_system,
const InitializationData& init_data) {
// TODO(gmorgan): Compare key_system and init_data with value received
// during session startup - they should be the same.
return true;
}
CdmResponseType CdmSession::GenerateKeyRequest(
const InitializationData& init_data, const CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
std::string* server_url) {
if (reinitialize_session_) {
CdmResponseType sts = Init();
if (sts != NO_ERROR) {
LOGW("CdmSession::GenerateKeyRequest: Reinitialization failed");
return sts;
}
}
if (crypto_session_.get() == NULL) {
LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session");
return UNKNOWN_ERROR;
@@ -181,9 +148,7 @@ CdmResponseType CdmSession::GenerateKeyRequest(
if (is_release_) {
return GenerateReleaseRequest(key_request, server_url);
} else if (license_received_) { // renewal
return Properties::require_explicit_renew_request()
? UNKNOWN_ERROR
: GenerateRenewalRequest(key_request, server_url);
return GenerateRenewalRequest(key_request, server_url);
} else {
if (!init_data.is_supported()) {
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
@@ -195,16 +160,6 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return KEY_ERROR;
}
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
reinitialize_session_ = true;
return NEED_PROVISIONING;
}
}
if (!license_parser_.PrepareKeyRequest(init_data, license_type,
app_parameters, session_id_,
key_request, server_url)) {
@@ -235,11 +190,10 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
}
if (is_release_) {
return ReleaseKey(key_response);
CdmResponseType sts = ReleaseKey(key_response);
return (NO_ERROR == sts) ? KEY_ADDED : sts;
} else if (license_received_) { // renewal
return Properties::require_explicit_renew_request()
? UNKNOWN_ERROR
: RenewKey(key_response);
return RenewKey(key_response);
} else {
CdmResponseType sts = license_parser_.HandleKeyResponse(key_response);
@@ -313,7 +267,6 @@ CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
// CancelKeyRequest() - Cancel session.
CdmResponseType CdmSession::CancelKeyRequest() {
// TODO(gmorgan): cancel and clean up session
crypto_session_->Close();
return NO_ERROR;
}
@@ -324,17 +277,12 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
return UNKNOWN_ERROR;
CdmResponseType status = crypto_session_->Decrypt(params);
// TODO(rfrias): Remove after support for OEMCrypto_ERROR_KEY_EXPIRED is in
if (UNKNOWN_ERROR == status) {
Clock clock;
int64_t current_time = clock.GetCurrentTime();
if (policy_engine_.IsLicenseDurationExpired(current_time) ||
policy_engine_.IsPlaybackDurationExpired(current_time)) {
return NEED_KEY;
}
}
if (NO_ERROR == status) {
if (is_initial_decryption_) {
policy_engine_.BeginDecryption();
is_initial_decryption_ = false;
}
if (!is_usage_update_needed_) {
is_usage_update_needed_ =
!license_parser_.provider_session_token().empty();
@@ -390,7 +338,7 @@ CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
CdmResponseType sts = license_parser_.HandleKeyUpdateResponse(false,
key_response);
if (NO_ERROR != sts)
if (KEY_ADDED != sts)
return sts;
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
@@ -405,8 +353,6 @@ bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
CdmSessionId CdmSession::GenerateSessionId() {
static int session_num = 1;
// TODO(rkuroiwa): Want this to be unique. Probably doing Hash(time+init_data)
// to get something that is reasonably unique.
return SESSION_ID_PREFIX + IntToString(++session_num);
}
@@ -539,8 +485,9 @@ void CdmSession::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) {
}
SecurityLevel CdmSession::GetRequestedSecurityLevel() {
if (Properties::GetSecurityLevel(session_id_)
.compare(QUERY_VALUE_SECURITY_LEVEL_L3) == 0) {
std::string security_level;
if (Properties::GetSecurityLevel(session_id_, &security_level) &&
security_level == QUERY_VALUE_SECURITY_LEVEL_L3) {
return kLevel3;
}

View File

@@ -11,7 +11,7 @@
namespace {
// URL for Google Provisioning Server.
// This server supplies the certificate that is needed
// The provisioning server supplies the certificate that is needed
// to communicate with the License Server.
const std::string kProvisioningServerUrl =
"https://www.googleapis.com/"
@@ -28,10 +28,9 @@ using video_widevine_server::sdk::ProvisioningResponse;
using video_widevine_server::sdk::SignedProvisioningMessage;
/*
* This function converts SignedProvisioningRequest into base64 string.
* It then wraps it in JSON format expected by the Apiary frontend.
* Apiary requires the base64 encoding to replace '+' with minus '-',
* and '/' with underscore '_'; opposite to stubby's.
* This function converts SignedProvisioningRequest into base64 string. It then
* wraps it in JSON format expected by the frontend. This server requires a
* "web-safe" base 64 encoding, where '+' becomes '-' and '/' becomes '_'.
*
* Returns the JSON formated string in *request. The JSON string will be
* appended as a query parameter, i.e. signedRequest=<base 64 encoded

View File

@@ -159,6 +159,25 @@ bool CryptoSession::GetDeviceUniqueId(std::string* device_id) {
return true;
}
bool CryptoSession::GetApiVersion(uint32_t* version) {
if (!version) {
LOGE("CryptoSession::GetApiVersion: No buffer passed to method.");
return false;
}
if (!initialized_) {
return false;
}
CdmSecurityLevel level = GetSecurityLevel();
SecurityLevel security_level = kLevelDefault;
if (kSecurityLevelL3 == level) security_level = kLevel3;
LOGV("CryptoSession::GetApiVersion: Lock");
AutoLock auto_lock(crypto_lock_);
*version = OEMCrypto_APIVersion(security_level);
return true;
}
bool CryptoSession::GetSystemId(uint32_t* system_id) {
if (!system_id) {
LOGE("CryptoSession::GetSystemId : No buffer passed to method.");
@@ -270,9 +289,9 @@ bool CryptoSession::PrepareRequest(const std::string& message,
if (!Properties::use_certificates_as_identification() || is_provisioning) {
if (!GenerateDerivedKeys(message)) return false;
if (!GenerateSignature(message, false, signature)) return false;
if (!GenerateSignature(message, signature)) return false;
} else {
if (!GenerateSignature(message, true, signature)) return false;
if (!GenerateRsaSignature(message, signature)) return false;
}
return true;
@@ -290,7 +309,7 @@ bool CryptoSession::PrepareRenewalRequest(const std::string& message,
return false;
}
if (!GenerateSignature(message, false, signature)) {
if (!GenerateSignature(message, signature)) {
return false;
}
@@ -508,55 +527,77 @@ bool CryptoSession::GenerateDerivedKeys(const std::string& message,
return true;
}
bool CryptoSession::GenerateSignature(const std::string& message, bool use_rsa,
bool CryptoSession::GenerateSignature(const std::string& message,
std::string* signature) {
LOGV("GenerateSignature: id=%ld", (uint32_t)oec_session_id_);
if (!signature) return false;
size_t length = 0;
OEMCryptoResult sts = OEMCrypto_SUCCESS;
if (use_rsa) {
sts = OEMCrypto_GenerateRSASignature(
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
message.size(), NULL, &length, kSign_RSASSA_PSS);
size_t length = signature->size();
OEMCryptoResult sts = OEMCrypto_GenerateSignature(
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
message.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
&length);
if (OEMCrypto_SUCCESS != sts) {
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
LOGD("GenerateSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
return false;
}
} else {
length = kSignatureSize;
// TODO(gmorgan,kqyang): Use OEMCrypto_GenerateSignature to determine
// length after marvell fixes their implementation.
/*
sts = OEMCrypto_GenerateSignature(
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
message.size(), NULL, &length);
*/
}
signature->resize(length);
if (use_rsa) {
sts = OEMCrypto_GenerateRSASignature(
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);
} else {
// Retry with proper-sized signature buffer
signature->resize(length);
sts = OEMCrypto_GenerateSignature(
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
message.size(),
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
&length);
if (OEMCrypto_SUCCESS != sts) {
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
return false;
}
}
// Trim signature buffer
signature->resize(length);
return true;
}
bool CryptoSession::GenerateRsaSignature(const std::string& message,
std::string* signature) {
LOGV("GenerateRsaSignature: id=%ld", (uint32_t)oec_session_id_);
if (!signature) return false;
size_t length = signature->size();
OEMCryptoResult sts = OEMCrypto_GenerateRSASignature(
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);
if (OEMCrypto_SUCCESS != sts) {
LOGD("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
return false;
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
LOGD("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
return false;
}
// Retry with proper-sized signature buffer
signature->resize(length);
sts = OEMCrypto_GenerateRSASignature(
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);
if (OEMCrypto_SUCCESS != sts) {
LOGD("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
return false;
}
}
// TODO(fredgc): b/8878371
// remove in K, when L1 library reports correct length.
// Trim signature buffer
signature->resize(length);
return true;
@@ -588,7 +629,8 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
buffer_descriptor.buffer.clear.address =
static_cast<uint8_t*>(params.decrypt_buffer) +
params.decrypt_buffer_offset;
buffer_descriptor.buffer.clear.max_length = params.decrypt_buffer_length;
buffer_descriptor.buffer.clear.max_length =
params.decrypt_buffer_length - params.decrypt_buffer_offset;
break;
case OEMCrypto_BufferType_Secure:
buffer_descriptor.buffer.secure.handle = params.decrypt_buffer;
@@ -768,8 +810,6 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
reinterpret_cast<uint8_t*>(&(*wrapped_rsa_key)[0]),
&wrapped_rsa_key_length);
// TODO(fredgc): b/8878371
// remove in K, when L1 library reports correct length.
wrapped_rsa_key->resize(wrapped_rsa_key_length);
if (OEMCrypto_SUCCESS != status) {

View File

@@ -2,13 +2,20 @@
#include "device_files.h"
#if defined(__APPLE__)
# include <CommonCrypto/CommonDigest.h>
# define SHA256 CC_SHA256
# define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
#else
# include <openssl/sha.h>
#endif
#include <cstring>
#include <string>
#include "device_files.pb.h"
#include "file_store.h"
#include "log.h"
#include "openssl/sha.h"
#include "properties.h"
#include "string_conversions.h"
@@ -22,6 +29,7 @@ using video_widevine_client::sdk::UsageInfo;
using video_widevine_client::sdk::UsageInfo_ProviderSession;
namespace {
const char kCertificateFileName[] = "cert.bin";
const char kUsageInfoFileName[] = "usage.bin";
const char kLicenseFileNameExt[] = ".lic";
@@ -31,6 +39,18 @@ const char* kSecurityLevelPathCompatibilityExclusionList[] = {"ay64.dat"};
size_t kSecurityLevelPathCompatibilityExclusionListSize =
sizeof(kSecurityLevelPathCompatibilityExclusionList) /
sizeof(*kSecurityLevelPathCompatibilityExclusionList);
bool Hash(const std::string& data, std::string* hash) {
if (!hash) return false;
hash->resize(SHA256_DIGEST_LENGTH);
const unsigned char* input =
reinterpret_cast<const unsigned char*>(data.data());
unsigned char* output = reinterpret_cast<unsigned char*>(&(*hash)[0]);
SHA256(input, data.size(), output);
return true;
}
} // unnamed namespace
namespace wvcdm {
@@ -343,18 +363,13 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
return false;
}
UsageInfo* updated_info = file.mutable_usage_info();
UsageInfo info(*(const_cast<const UsageInfo*>(updated_info)));
updated_info->clear_sessions();
UsageInfo* usage_info = file.mutable_usage_info();
int index = 0;
bool found = false;
for (int i = 0; i < info.sessions_size(); ++i) {
if (info.sessions(i).token().compare(provider_session_token) == 0) {
for (; index < usage_info->sessions_size(); ++index) {
if (usage_info->sessions(index).token().compare(provider_session_token) == 0) {
found = true;
} else {
updated_info->add_sessions()->set_token(info.sessions(i).token());
updated_info->add_sessions()->set_license_request(
info.sessions(i).license_request());
updated_info->add_sessions()->set_license(info.sessions(i).license());
break;
}
}
@@ -364,6 +379,13 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
return false;
}
google::protobuf::RepeatedPtrField<UsageInfo_ProviderSession>* sessions =
usage_info->mutable_sessions();
if (index < usage_info->sessions_size() - 1) {
sessions->SwapElements(index, usage_info->sessions_size() - 1);
}
sessions->RemoveLast();
file.SerializeToString(&serialized_file);
return StoreFile(kUsageInfoFileName, serialized_file);
}
@@ -430,17 +452,6 @@ bool DeviceFiles::RetrieveUsageInfo(std::vector<
return true;
}
bool DeviceFiles::Hash(const std::string& data, std::string* hash) {
if (!hash) return false;
hash->resize(SHA256_DIGEST_LENGTH);
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data.data(), data.size());
SHA256_Final(reinterpret_cast<unsigned char*>(&(*hash)[0]), &sha256);
return true;
}
bool DeviceFiles::StoreFile(const char* name,
const std::string& serialized_file) {
if (!file_) {

View File

@@ -47,7 +47,7 @@ message File {
enum FileType {
DEVICE_CERTIFICATE = 1;
LICENSE = 2;
USAGE_INFO = 2;
USAGE_INFO = 3;
}
enum FileVersion {
@@ -63,5 +63,6 @@ message File {
message HashedFile {
optional bytes file = 1;
// A raw (not hex-encoded) SHA256, taken over the bytes of 'file'.
optional bytes hash = 2;
}

View File

@@ -22,6 +22,7 @@ std::string kDeviceNameKey = "device_name";
std::string kProductNameKey = "product_name";
std::string kBuildInfoKey = "build_info";
std::string kDeviceIdKey = "device_id";
std::string kOemCryptoApiVersion = "oemcrypto_api_version";
const unsigned char kServiceCertificateCAPublicKey[] = {
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81,
0x00, 0xb4, 0xfe, 0x39, 0xc3, 0x65, 0x90, 0x03,
@@ -193,10 +194,10 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
}
bool privacy_mode_enabled = Properties::UsePrivacyMode(session_id);
std::vector<uint8_t> cert = Properties::GetServiceCertificate(session_id);
std::string serialized_service_certificate(cert.begin(), cert.end());
if (serialized_service_certificate.empty())
std::string serialized_service_certificate;
if (!Properties::GetServiceCertificate(session_id,
&serialized_service_certificate) ||
serialized_service_certificate.empty())
serialized_service_certificate = service_certificate_;
if (privacy_mode_enabled && serialized_service_certificate.empty()) {
@@ -254,12 +255,17 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
client_info->set_name(kBuildInfoKey);
client_info->set_value(value);
}
if (session_->GetDeviceUniqueId(&value)) {
client_info = client_id->add_client_info();
client_info->set_name(kDeviceIdKey);
client_info->set_value(value);
}
uint32_t version = 0;
if (session_->GetApiVersion(&version)) {
client_info = client_id->add_client_info();
client_info->set_name(kOemCryptoApiVersion);
client_info->set_value(UintToString(version));
}
if (privacy_mode_enabled) {
EncryptedClientIdentification* encrypted_client_id =
@@ -353,7 +359,7 @@ bool CdmLicense::PrepareKeyRequest(const InitializationData& init_data,
return false;
}
// TODO(jfore): The time field will be updated once the cdm wrapper
// The time field will be updated once the cdm wrapper
// has been updated to pass us in the time.
license_request.set_request_time(0);
@@ -432,8 +438,9 @@ bool CdmLicense::PrepareKeyUpdateRequest(bool is_renewal,
if (!is_renewal) {
if (license_id.has_provider_session_token()) {
std::string usage_report;
if (!session_->GenerateUsageReport(license_id.provider_session_token(),
&usage_report)) {
if (NO_ERROR !=
session_->GenerateUsageReport(license_id.provider_session_token(),
&usage_report)) {
return false;
}
current_license->set_session_usage_table_entry(usage_report);
@@ -560,7 +567,6 @@ CdmResponseType CdmLicense::HandleKeyResponse(
return KEY_ERROR;
}
std::string provider_session_token;
if (license.id().has_provider_session_token())
provider_session_token_ = license.id().provider_session_token();
@@ -568,9 +574,6 @@ CdmResponseType CdmLicense::HandleKeyResponse(
server_url_ = license.policy().renewal_server_url();
}
// TODO(kqyang, jfore, gmorgan): change SetLicense function signature to
// be able to return true/false to accept/reject the license. (Pending code
// merge from Eureka)
policy_engine_->SetLicense(license);
CdmResponseType resp = session_->LoadKeys(signed_response.msg(),
@@ -578,7 +581,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
mac_key_iv,
mac_key,
key_array,
provider_session_token);
provider_session_token_);
if (KEY_ADDED == resp) {
loaded_keys_.clear();
@@ -630,27 +633,23 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
return KEY_ERROR;
}
if (is_renewal) {
if (license.policy().has_renewal_server_url() &&
license.policy().renewal_server_url().size() > 0) {
server_url_ = license.policy().renewal_server_url();
}
}
else {
if (license.id().has_provider_session_token()) {
provider_session_token_ = license.id().provider_session_token();
session_->ReleaseUsageInformation(signed_response.msg(),
signed_response.signature(),
provider_session_token_);
}
}
// TODO(kqyang, jfore, gmorgan): change UpdateLicense function signature to
// be able to return true/false to accept/reject the license. (Pending code
// merge from Eureka)
policy_engine_->UpdateLicense(license);
if (!is_renewal) return KEY_ADDED;
if (!is_renewal) {
if (!license.id().has_provider_session_token()) return KEY_ADDED;
provider_session_token_ = license.id().provider_session_token();
CdmResponseType status =
session_->ReleaseUsageInformation(signed_response.msg(),
signed_response.signature(),
provider_session_token_);
return (NO_ERROR == status) ? KEY_ADDED : status;
}
if (license.policy().has_renewal_server_url() &&
license.policy().renewal_server_url().size() > 0) {
server_url_ = license.policy().renewal_server_url();
}
std::vector<CryptoKey> key_array = ExtractContentKeys(license);

View File

@@ -315,7 +315,7 @@ class Adapter {
if (level1_.InstallKeybox(keybox, size) != OEMCrypto_SUCCESS) {
LOGE("Could NOT install keybox from %s. Falling Back to L3.",
filename.c_str());
false;
return false;
}
LOGI("Installed keybox from %s", filename.c_str());
return true;

View File

@@ -76,7 +76,7 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys(
const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys,
const OEMCrypto_KeyObject* key_array,
const uint8_t* pst, size_t pst_length) {
return OEMCrypto_LoadKeys_V8(pair.session, message, message_length, signature,
return OEMCrypto_LoadKeys_V8(session, message, message_length, signature,
signature_length, enc_mac_key_iv, enc_mac_key,
num_keys, key_array);
}

View File

@@ -2,16 +2,16 @@
#include "policy_engine.h"
#include <algorithm>
#include <map>
#include <limits.h>
#include <sstream>
#include <string>
#include <vector>
#include "clock.h"
#include "log.h"
#include "properties.h"
#include "string_conversions.h"
#include "clock.h"
#include "wv_cdm_constants.h"
namespace wvcdm {
@@ -59,7 +59,6 @@ void PolicyEngine::OnTimerEvent(bool* event_occurred, CdmEventType* event) {
// Test to determine if renewal should be attempted.
switch (license_state_) {
case kLicenseStateInitialPendingUsage:
case kLicenseStateCanPlay: {
if (IsRenewalDelayExpired(current_time))
renewal_needed = true;
@@ -115,11 +114,6 @@ void PolicyEngine::UpdateLicense(
policy_.MergeFrom(license.policy());
if (!policy_.can_play()) {
license_state_ = kLicenseStateExpired;
return;
}
// some basic license validation
if (license_state_ == kLicenseStateInitial) {
// license start time needs to be present in the initial response
@@ -158,35 +152,23 @@ void PolicyEngine::UpdateLicense(
policy_max_duration_seconds_ = policy_.license_duration_seconds();
}
if (Properties::begin_license_usage_when_received())
playback_start_time_ = current_time;
if (!policy_.can_play()) {
license_state_ = kLicenseStateExpired;
return;
}
if (IsLicenseDurationExpired(current_time)) return;
if (IsPlaybackDurationExpired(current_time)) return;
// Update state
if (Properties::begin_license_usage_when_received()) {
if (policy_.renew_with_usage()) {
license_state_ = kLicenseStateNeedRenewal;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
}
else {
if (license_state_ == kLicenseStateInitial) {
license_state_ = kLicenseStateInitialPendingUsage;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
}
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
void PolicyEngine::BeginDecryption() {
if ((playback_start_time_ == 0) &&
(!Properties::begin_license_usage_when_received())) {
if (playback_start_time_ == 0) {
switch (license_state_) {
case kLicenseStateInitialPendingUsage:
case kLicenseStateCanPlay:
case kLicenseStateNeedRenewal:
case kLicenseStateWaitingLicenseUpdate:
playback_start_time_ = clock_->GetCurrentTime();
@@ -194,12 +176,7 @@ void PolicyEngine::BeginDecryption() {
if (policy_.renew_with_usage()) {
license_state_ = kLicenseStateNeedRenewal;
}
else {
license_state_ = kLicenseStateCanPlay;
can_decrypt_ = true;
}
break;
case kLicenseStateCanPlay:
case kLicenseStateInitial:
case kLicenseStateExpired:
default:
@@ -224,17 +201,10 @@ CdmResponseType PolicyEngine::Query(CdmQueryMap* key_info) {
QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
(*key_info)[QUERY_KEY_RENEW_ALLOWED] = policy_.can_renew() ?
QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
int64_t remaining_time = policy_max_duration_seconds_ +
license_received_time_ - current_time;
if (remaining_time < 0)
remaining_time = 0;
ss << remaining_time;
ss << GetLicenseDurationRemaining(current_time);
(*key_info)[QUERY_KEY_LICENSE_DURATION_REMAINING] = ss.str();
remaining_time = policy_.playback_duration_seconds() + playback_start_time_ -
current_time;
if (remaining_time < 0)
remaining_time = 0;
ss << remaining_time;
ss.str("");
ss << GetPlaybackDurationRemaining(current_time);
(*key_info)[QUERY_KEY_PLAYBACK_DURATION_REMAINING] = ss.str();
(*key_info)[QUERY_KEY_RENEWAL_SERVER_URL] = policy_.renewal_server_url();
@@ -255,6 +225,16 @@ bool PolicyEngine::IsLicenseDurationExpired(int64_t current_time) {
current_time;
}
int64_t PolicyEngine::GetLicenseDurationRemaining(int64_t current_time) {
if (0 == policy_max_duration_seconds_) return LLONG_MAX;
int64_t remaining_time = policy_max_duration_seconds_
+ license_received_time_ - current_time;
if (remaining_time < 0) remaining_time = 0;
return remaining_time;
}
bool PolicyEngine::IsPlaybackDurationExpired(int64_t current_time) {
return (policy_.playback_duration_seconds() > 0) &&
playback_start_time_ &&
@@ -262,6 +242,17 @@ bool PolicyEngine::IsPlaybackDurationExpired(int64_t current_time) {
current_time;
}
int64_t PolicyEngine::GetPlaybackDurationRemaining(int64_t current_time) {
if (0 == policy_.playback_duration_seconds()) return LLONG_MAX;
if (0 == playback_start_time_) return policy_.playback_duration_seconds();
int64_t remaining_time = policy_.playback_duration_seconds()
+ playback_start_time_ - current_time;
if (remaining_time < 0) remaining_time = 0;
return remaining_time;
}
bool PolicyEngine::IsRenewalDelayExpired(int64_t current_time) {
return policy_.can_renew() &&
(policy_.renewal_delay_seconds() > 0) &&

View File

@@ -7,38 +7,60 @@
#include "privacy_crypto.h"
#include <openssl/aes.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include "log.h"
#include "openssl/aes.h"
#include "openssl/bio.h"
#include "openssl/err.h"
#include "openssl/pem.h"
#include "openssl/sha.h"
namespace {
const int kPssSaltLength = 20;
const int kRsaPkcs1OaepPaddingLength = 41;
RSA* GetKey(const std::string& serialized_key) {
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_key.data()),
serialized_key.size());
if (bio == NULL) {
LOGE("GetKey: BIO_new_mem_buf returned NULL");
return NULL;
}
RSA* key = d2i_RSAPublicKey_bio(bio, NULL);
BIO_free(bio);
if (key == NULL) {
LOGE("GetKey: RSA key deserialization failure: %s",
ERR_error_string(ERR_get_error(), NULL));
return NULL;
}
return key;
}
void FreeKey(RSA* key) {
if (key != NULL) {
RSA_free(key);
}
}
} // namespace
namespace wvcdm {
AesCbcKey::AesCbcKey() {}
AesCbcKey::~AesCbcKey() {}
bool AesCbcKey::Init(const std::string& key) {
if (key.empty()) {
LOGE("AesCbcKey::Init: no key provided");
return false;
}
if (key.size() != AES_BLOCK_SIZE) {
LOGE("AesCbcKey::Init: unexpected key size: %d", key.size());
return false;
}
EVP_CIPHER_CTX_init(&ctx_);
if (EVP_EncryptInit(&ctx_, EVP_aes_128_cbc(),
reinterpret_cast<const uint8_t*>(&key[0]), NULL) == 0) {
LOGE("AesCbcKey::Init: AES CBC key setup failure: %s",
ERR_error_string(ERR_get_error(), NULL));
return false;
}
initialized_ = true;
key_ = key;
return true;
}
@@ -60,14 +82,16 @@ bool AesCbcKey::Encrypt(const std::string& in, std::string* out,
LOGE("AesCbcKey::Encrypt: crypttext destination not provided");
return false;
}
if (!initialized_) {
if (key_.empty()) {
LOGE("AesCbcKey::Encrypt: AES key not initialized");
return false;
}
if (EVP_EncryptInit(&ctx_, NULL, NULL,
reinterpret_cast<const uint8_t*>(iv->data())) == 0) {
LOGE("AesCbcKey::Encrypt: AES CBC iv setup failure: %s",
EVP_CIPHER_CTX ctx;
if (EVP_EncryptInit(&ctx, EVP_aes_128_cbc(),
reinterpret_cast<uint8_t*>(&key_[0]),
reinterpret_cast<uint8_t*>(&(*iv)[0])) == 0) {
LOGE("AesCbcKey::Encrypt: AES CBC setup failure: %s",
ERR_error_string(ERR_get_error(), NULL));
return false;
}
@@ -75,7 +99,7 @@ bool AesCbcKey::Encrypt(const std::string& in, std::string* out,
out->resize(in.size() + AES_BLOCK_SIZE);
int out_length = out->size();
if (EVP_EncryptUpdate(
&ctx_, reinterpret_cast<uint8_t*>(&(*out)[0]), &out_length,
&ctx, reinterpret_cast<uint8_t*>(&(*out)[0]), &out_length,
reinterpret_cast<uint8_t*>(const_cast<char*>(in.data())),
in.size()) == 0) {
LOGE("AesCbcKey::Encrypt: encryption failure: %s",
@@ -84,7 +108,7 @@ bool AesCbcKey::Encrypt(const std::string& in, std::string* out,
}
int padding = 0;
if (EVP_EncryptFinal(&ctx_, reinterpret_cast<uint8_t*>(&(*out)[out_length]),
if (EVP_EncryptFinal(&ctx, reinterpret_cast<uint8_t*>(&(*out)[out_length]),
&padding) == 0) {
LOGE("AesCbcKey::Encrypt: PKCS7 padding failure: %s",
ERR_error_string(ERR_get_error(), NULL));
@@ -95,34 +119,17 @@ bool AesCbcKey::Encrypt(const std::string& in, std::string* out,
return true;
}
RsaPublicKey::~RsaPublicKey() {
if (key_ != NULL) {
RSA_free(key_);
}
}
RsaPublicKey::RsaPublicKey() {}
RsaPublicKey::~RsaPublicKey() {}
bool RsaPublicKey::Init(const std::string& serialized_key) {
if (serialized_key.empty()) {
LOGE("RsaPublicKey::Init: no serialized key provided");
return false;
}
BIO* bio = BIO_new_mem_buf(const_cast<char*>(serialized_key.data()),
serialized_key.size());
if (bio == NULL) {
LOGE("RsaPublicKey::Init: BIO_new_mem_buf returned NULL");
return false;
}
key_ = d2i_RSAPublicKey_bio(bio, NULL);
BIO_free(bio);
if (key_ == NULL) {
LOGE("RsaPublicKey::Init: RSA key deserialization failure: %s",
ERR_error_string(ERR_get_error(), NULL));
return false;
}
serialized_key_ = serialized_key;
return true;
}
@@ -136,36 +143,46 @@ bool RsaPublicKey::Encrypt(const std::string& clear_message,
LOGE("RsaPublicKey::Encrypt: no encrypt message buffer provided");
return false;
}
if (key_ == NULL) {
if (serialized_key_.empty()) {
LOGE("RsaPublicKey::Encrypt: RSA key not initialized");
return false;
}
int rsa_size = RSA_size(key_);
RSA* key = GetKey(serialized_key_);
if (key == NULL) {
// Error already logged by GetKey.
return false;
}
int rsa_size = RSA_size(key);
if (static_cast<int>(clear_message.size()) >
rsa_size - kRsaPkcs1OaepPaddingLength) {
LOGE("RsaPublicKey::Encrypt: message too large to be encrypted (actual %d",
" max allowed %d)", clear_message.size(),
rsa_size - kRsaPkcs1OaepPaddingLength);
FreeKey(key);
return false;
}
encrypted_message->assign(rsa_size, 0);
if (RSA_public_encrypt(
clear_message.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(clear_message.data())),
reinterpret_cast<unsigned char*>(&(*encrypted_message)[0]), key_,
reinterpret_cast<unsigned char*>(&(*encrypted_message)[0]), key,
RSA_PKCS1_OAEP_PADDING) != rsa_size) {
LOGE("RsaPublicKey::Encrypt: encrypt failure: %s",
ERR_error_string(ERR_get_error(), NULL));
FreeKey(key);
return false;
}
return true;
}
bool RsaPublicKey::VerifySignature(const std::string& message,
const std::string& signature) {
if (key_ == NULL) {
if (serialized_key_.empty()) {
LOGE("RsaPublicKey::VerifySignature: RSA key not initialized");
return false;
}
@@ -173,25 +190,33 @@ bool RsaPublicKey::VerifySignature(const std::string& message,
LOGE("RsaPublicKey::VerifySignature: signed message is empty");
return false;
}
RSA* key = GetKey(serialized_key_);
if (key == NULL) {
// Error already logged by GetKey.
return false;
}
int rsa_size = RSA_size(key_);
int rsa_size = RSA_size(key);
if (static_cast<int>(signature.size()) != rsa_size) {
LOGE(
"RsaPublicKey::VerifySignature: message signature is of the wrong "
"size (expected %d, actual %d)",
rsa_size, signature.size());
FreeKey(key);
return false;
}
// Decrypt the signature.
std::string padded_digest(signature.size(), 0);
if (RSA_public_decrypt(
signature.size(),
const_cast<unsigned char*>(
reinterpret_cast<const unsigned char*>(signature.data())),
reinterpret_cast<unsigned char*>(&padded_digest[0]), key_,
reinterpret_cast<unsigned char*>(&padded_digest[0]), key,
RSA_NO_PADDING) != rsa_size) {
LOGE("RsaPublicKey::VerifySignature: RSA public decrypt failure: %s",
ERR_error_string(ERR_get_error(), NULL));
FreeKey(key);
return false;
}
@@ -202,12 +227,13 @@ bool RsaPublicKey::VerifySignature(const std::string& message,
// Verify PSS padding.
if (RSA_verify_PKCS1_PSS(
key_, reinterpret_cast<const unsigned char*>(message_digest.data()),
key, reinterpret_cast<const unsigned char*>(message_digest.data()),
EVP_sha1(),
reinterpret_cast<const unsigned char*>(padded_digest.data()),
kPssSaltLength) == 0) {
LOGE("RsaPublicKey::VerifySignature: RSA verify failure: %s",
ERR_error_string(ERR_get_error(), NULL));
FreeKey(key);
return false;
}

View File

@@ -0,0 +1,43 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Description:
// Dummy version of privacy crypto classes for systems which
// can't tolerate OpenSSL as a dependency.
//
#include "privacy_crypto.h"
namespace wvcdm {
AesCbcKey::AesCbcKey() {}
AesCbcKey::~AesCbcKey() {}
bool AesCbcKey::Init(const std::string& key) {
return false;
}
bool AesCbcKey::Encrypt(const std::string& in, std::string* out,
std::string* iv) {
return false;
}
RsaPublicKey::RsaPublicKey() {}
RsaPublicKey::~RsaPublicKey() {}
bool RsaPublicKey::Init(const std::string& serialized_key) {
return false;
}
bool RsaPublicKey::Encrypt(const std::string& clear_message,
std::string* encrypted_message) {
return false;
}
bool RsaPublicKey::VerifySignature(const std::string& message,
const std::string& signature) {
return false;
}
} // namespace wvcdm

View File

@@ -9,27 +9,21 @@ const char* kSecurityLevelDirs[] = {"L1/", "L3/"};
} // namespace
namespace wvcdm {
bool Properties::begin_license_usage_when_received_;
bool Properties::require_explicit_renew_request_;
bool Properties::oem_crypto_use_secure_buffers_;
bool Properties::oem_crypto_use_fifo_;
bool Properties::oem_crypto_use_userspace_buffers_;
bool Properties::oem_crypto_require_usage_tables_;
bool Properties::use_certificates_as_identification_;
bool Properties::decrypt_with_empty_session_support_;
bool Properties::security_level_path_backward_compatibility_support_;
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_;
void Properties::Init() {
begin_license_usage_when_received_ = kPropertyBeginLicenseUsageWhenReceived;
require_explicit_renew_request_ = kPropertyRequireExplicitRenewRequest;
oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers;
oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo;
oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers;
oem_crypto_require_usage_tables_ = kPropertyOemCryptoRequireUsageTable;
use_certificates_as_identification_ =
kPropertyUseCertificatesAsIdentification;
decrypt_with_empty_session_support_ = kDecryptWithEmptySessionSupport;
security_level_path_backward_compatibility_support_ =
kSecurityLevelPathBackwardCompatibilitySupport;
session_property_set_.reset(new CdmClientPropertySetMap());
@@ -66,27 +60,30 @@ const CdmClientPropertySet* Properties::GetCdmClientPropertySet(
return NULL;
}
const std::string Properties::GetSecurityLevel(const CdmSessionId& session_id) {
bool Properties::GetSecurityLevel(const CdmSessionId& session_id,
std::string* security_level) {
const CdmClientPropertySet* property_set =
GetCdmClientPropertySet(session_id);
if (NULL == property_set) {
LOGE("Properties::GetSecurityLevel: cannot find property set for %s",
session_id.c_str());
return "";
return false;
}
return property_set->security_level();
*security_level = property_set->security_level();
return true;
}
const std::vector<uint8_t> Properties::GetServiceCertificate(
const CdmSessionId& session_id) {
bool Properties::GetServiceCertificate(const CdmSessionId& session_id,
std::string* service_certificate) {
const CdmClientPropertySet* property_set =
GetCdmClientPropertySet(session_id);
if (NULL == property_set) {
LOGE("Properties::GetServiceCertificate: cannot find property set for %s",
session_id.c_str());
return std::vector<uint8_t>();
return false;
}
return property_set->service_certificate();
*service_certificate = property_set->service_certificate();
return true;
}
bool Properties::UsePrivacyMode(const CdmSessionId& session_id) {

View File

@@ -77,11 +77,11 @@ std::string b2a_hex(const std::string& byte) {
// Filename-friendly base64 encoding (RFC4648), commonly referred to
// as Base64WebSafeEncode.
// This is the encoding required to interface with the provisioning
// server's Apiary interface as well as for certain license server
// transactions. It is also used for logging certain strings.
// The difference between web safe encoding vs regular encoding is that
// the web safe version replaces '+' with '-' and '/' with '_'.
//
// This is the encoding required to interface with the provisioning server, as
// well as for certain license server transactions. It is also used for logging
// certain strings. The difference between web safe encoding vs regular encoding
// is that the web safe version replaces '+' with '-' and '/' with '_'.
std::string Base64SafeEncode(const std::vector<uint8_t>& bin_input) {
if (bin_input.empty()) {
return std::string();