Source release v3.1.0

This commit is contained in:
Gene Morgan
2016-07-19 18:43:15 -07:00
parent 7a7f78d654
commit 643b91b616
108 changed files with 16537 additions and 7174 deletions

View File

@@ -10,8 +10,6 @@
#include "cdm_engine.h"
#include "clock.h"
#include "crypto_session.h"
#include "device_files.h"
#include "file_store.h"
#include "log.h"
#include "properties.h"
@@ -25,47 +23,22 @@ const size_t kKeySetIdLength = 14;
namespace wvcdm {
CdmSession::CdmSession(CdmClientPropertySet* cdm_client_property_set,
const std::string& origin,
WvCdmEventListener* event_listener,
const CdmSessionId* forced_session_id)
: initialized_(false),
session_id_(GenerateSessionId()),
origin_(origin),
crypto_session_(new CryptoSession),
file_handle_(new DeviceFiles),
license_received_(false),
is_offline_(false),
is_release_(false),
is_temporary_(false),
security_level_(kSecurityLevelUninitialized),
requested_security_level_(kLevelDefault),
is_initial_decryption_(true),
has_decrypted_since_last_report_(false),
is_initial_usage_update_(true),
is_usage_update_needed_(false) {
if (Properties::AlwaysUseKeySetIds()) {
if (forced_session_id) {
key_set_id_ = *forced_session_id;
} else {
bool ok = GenerateKeySetId(&key_set_id_);
(void)ok; // ok is now used when assertions are turned off.
assert(ok);
}
session_id_ = key_set_id_;
}
license_parser_.reset(new CdmLicense(session_id_));
policy_engine_.reset(new PolicyEngine(
session_id_, event_listener, crypto_session_.get()));
if (cdm_client_property_set) {
if (cdm_client_property_set->security_level() ==
QUERY_VALUE_SECURITY_LEVEL_L3) {
requested_security_level_ = kLevel3;
security_level_ = kSecurityLevelL3;
}
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
}
}
CdmSession::CdmSession(FileSystem* file_system) :
initialized_(false),
crypto_session_(new CryptoSession),
file_handle_(new DeviceFiles(file_system)),
license_received_(false),
is_offline_(false),
is_release_(false),
is_temporary_(false),
security_level_(kSecurityLevelUninitialized),
requested_security_level_(kLevelDefault),
is_initial_decryption_(true),
has_decrypted_since_last_report_(false),
is_initial_usage_update_(true),
is_usage_update_needed_(false),
mock_license_parser_in_use_(false),
mock_policy_engine_in_use_(false) {}
CdmSession::~CdmSession() {
if (!key_set_id_.empty()) {
@@ -75,24 +48,38 @@ CdmSession::~CdmSession() {
Properties::RemoveSessionPropertySet(session_id_);
}
CdmResponseType CdmSession::Init() {
if (session_id_.empty()) {
LOGE("CdmSession::Init: Failed, session not properly constructed");
return SESSION_INIT_ERROR_1;
}
CdmResponseType CdmSession::Init(
CdmClientPropertySet* cdm_client_property_set) {
return Init(cdm_client_property_set, NULL, NULL);
}
CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
const CdmSessionId* forced_session_id,
WvCdmEventListener* event_listener) {
if (initialized_) {
LOGE("CdmSession::Init: Failed due to previous initialization");
return SESSION_INIT_ERROR_2;
}
if (cdm_client_property_set &&
cdm_client_property_set->security_level() ==
QUERY_VALUE_SECURITY_LEVEL_L3) {
requested_security_level_ = kLevel3;
security_level_ = kSecurityLevelL3;
}
CdmResponseType sts = crypto_session_->Open(requested_security_level_);
if (NO_ERROR != sts) return sts;
security_level_ = crypto_session_->GetSecurityLevel();
if (!file_handle_->Init(security_level_)) {
LOGE("CdmSession::Init: Unable to initialize file handle");
return SESSION_FILE_HANDLE_INIT_ERROR;
}
std::string token;
if (Properties::use_certificates_as_identification()) {
std::string wrapped_key;
if (!file_handle_->Init(security_level_) ||
!file_handle_->RetrieveCertificate(origin_, &token, &wrapped_key) ||
if (!file_handle_->RetrieveCertificate(&token, &wrapped_key) ||
!crypto_session_->LoadCertificatePrivateKey(wrapped_key)) {
return NEED_PROVISIONING;
}
@@ -101,6 +88,30 @@ CdmResponseType CdmSession::Init() {
return SESSION_INIT_GET_KEYBOX_ERROR;
}
if (forced_session_id) {
key_set_id_ = *forced_session_id;
} else {
bool ok = GenerateKeySetId(&key_set_id_);
(void)ok; // ok is now used when assertions are turned off.
assert(ok);
}
session_id_ =
Properties::AlwaysUseKeySetIds() ? key_set_id_ : GenerateSessionId();
if (session_id_.empty()) {
LOGE("CdmSession::Init: empty session ID");
return EMPTY_SESSION_ID;
}
if (cdm_client_property_set)
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
if (!mock_license_parser_in_use_)
license_parser_.reset(new CdmLicense(session_id_));
if (!mock_policy_engine_in_use_)
policy_engine_.reset(new PolicyEngine(
session_id_, event_listener, crypto_session_.get()));
if (!license_parser_->Init(token, crypto_session_.get(),
policy_engine_.get()))
return LICENSE_PARSER_INIT_ERROR;
@@ -115,10 +126,6 @@ CdmResponseType CdmSession::RestoreOfflineSession(
const CdmKeySetId& key_set_id, const CdmLicenseType license_type) {
key_set_id_ = key_set_id;
// Retrieve license information from persistent store
if (!file_handle_->Reset(security_level_))
return RESTORE_OFFLINE_LICENSE_ERROR_1;
DeviceFiles::LicenseState license_state;
int64_t playback_start_time;
int64_t last_playback_time;
@@ -177,9 +184,9 @@ CdmResponseType CdmSession::RestoreUsageSession(
CdmResponseType CdmSession::GenerateKeyRequest(
const InitializationData& init_data, CdmLicenseType license_type,
const CdmAppParameterMap& app_parameters, CdmKeyMessage* key_request,
CdmKeyRequestType* key_request_type, std::string* server_url,
CdmKeySetId* key_set_id) {
const CdmAppParameterMap& app_parameters,
CdmKeyRequest* key_request) {
if (crypto_session_.get() == NULL) {
LOGW("CdmSession::GenerateKeyRequest: Invalid crypto session");
return INVALID_CRYPTO_SESSION_1;
@@ -190,6 +197,11 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return CRYPTO_SESSION_OPEN_ERROR_1;
}
if (!key_request) {
LOGE("CdmSession::GenerateKeyRequest: No output destination provided");
return INVALID_PARAMETERS_ENG_5;
}
switch (license_type) {
case kLicenseTypeTemporary:
is_temporary_ = true;
@@ -230,13 +242,12 @@ CdmResponseType CdmSession::GenerateKeyRequest(
}
if (is_release_) {
if (key_request_type) *key_request_type = kKeyRequestTypeRelease;
return GenerateReleaseRequest(key_request, server_url);
return GenerateReleaseRequest(key_request);
} else if (license_received_) { // renewal
if (key_request_type) *key_request_type = kKeyRequestTypeRenewal;
return GenerateRenewalRequest(key_request, server_url);
return GenerateRenewalRequest(key_request);
} else {
if (key_request_type) *key_request_type = kKeyRequestTypeInitial;
key_request->type = kKeyRequestTypeInitial;
if (!license_parser_->HasInitData()) {
if (!init_data.is_supported()) {
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
@@ -248,8 +259,7 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return INIT_DATA_NOT_FOUND;
}
}
if (is_offline_ && key_set_id_.empty() &&
!GenerateKeySetId(&key_set_id_)) {
if (is_offline_ && key_set_id_.empty()) {
LOGE("CdmSession::GenerateKeyRequest: Unable to generate key set ID");
return KEY_REQUEST_ERROR_1;
}
@@ -257,24 +267,24 @@ CdmResponseType CdmSession::GenerateKeyRequest(
app_parameters_ = app_parameters;
CdmResponseType status = license_parser_->PrepareKeyRequest(
init_data, license_type,
app_parameters, key_request, server_url);
app_parameters, &key_request->message,
&key_request->url);
if (KEY_MESSAGE != status) return status;
key_request_ = *key_request;
key_request_ = key_request->message;
if (is_offline_) {
offline_init_data_ = init_data.data();
offline_release_server_url_ = *server_url;
offline_release_server_url_ = key_request->url;
}
if (key_set_id) *key_set_id = key_set_id_;
return KEY_MESSAGE;
}
}
// AddKey() - Accept license response and extract key info.
CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
CdmKeySetId* key_set_id) {
CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
if (crypto_session_.get() == NULL) {
LOGW("CdmSession::AddKey: Invalid crypto session");
return INVALID_CRYPTO_SESSION_2;
@@ -303,12 +313,11 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
if (sts != NO_ERROR) return sts;
}
if (key_set_id) *key_set_id = key_set_id_;
return KEY_ADDED;
}
}
CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
CdmResponseType CdmSession::QueryStatus(CdmQueryMap* query_response) {
if (crypto_session_.get() == NULL) {
LOGE("CdmSession::QueryStatus: Invalid crypto session");
return INVALID_CRYPTO_SESSION_3;
@@ -321,17 +330,20 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
switch (security_level_) {
case kSecurityLevelL1:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1;
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
QUERY_VALUE_SECURITY_LEVEL_L1;
break;
case kSecurityLevelL2:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L2;
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
QUERY_VALUE_SECURITY_LEVEL_L2;
break;
case kSecurityLevelL3:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
QUERY_VALUE_SECURITY_LEVEL_L3;
break;
case kSecurityLevelUninitialized:
case kSecurityLevelUnknown:
(*key_info)[QUERY_KEY_SECURITY_LEVEL] =
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
break;
default:
@@ -340,24 +352,30 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
return NO_ERROR;
}
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) {
return policy_engine_->Query(key_info);
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* query_response) {
return policy_engine_->Query(query_response);
}
CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
CdmResponseType CdmSession::QueryKeyAllowedUsage(
const std::string& key_id, CdmKeyAllowedUsage* key_usage) {
return policy_engine_->QueryKeyAllowedUsage(key_id, key_usage);
}
CdmResponseType CdmSession::QueryOemCryptoSessionId(
CdmQueryMap* query_response) {
if (crypto_session_.get() == NULL) {
LOGW("CdmSession::QueryKeyControlInfo: Invalid crypto session");
LOGW("CdmSession::QueryOemCryptoSessionId: Invalid crypto session");
return INVALID_CRYPTO_SESSION_4;
}
if (!crypto_session_->IsOpen()) {
LOGW("CdmSession::QueryKeyControlInfo: Crypto session not open");
LOGW("CdmSession::QueryOemCryptoSessionId: Crypto session not open");
return CRYPTO_SESSION_OPEN_ERROR_4;
}
std::stringstream ss;
ss << crypto_session_->oec_session_id();
(*key_info)[QUERY_KEY_OEMCRYPTO_SESSION_ID] = ss.str();
(*query_response)[QUERY_KEY_OEMCRYPTO_SESSION_ID] = ss.str();
return NO_ERROR;
}
@@ -405,15 +423,17 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
// License renewal
// GenerateRenewalRequest() - Construct valid renewal request for the current
// session keys.
CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
std::string* server_url) {
CdmResponseType CdmSession::GenerateRenewalRequest(
CdmKeyRequest* key_request) {
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
true, app_parameters_, key_request, server_url);
true, app_parameters_, &key_request->message, &key_request->url);
key_request->type = kKeyRequestTypeRenewal;
if (KEY_MESSAGE != status) return status;
if (is_offline_) {
offline_key_renewal_request_ = *key_request;
offline_key_renewal_request_ = key_request->message;
}
return KEY_MESSAGE;
}
@@ -432,11 +452,14 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
return KEY_ADDED;
}
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
std::string* server_url) {
CdmResponseType CdmSession::GenerateReleaseRequest(
CdmKeyRequest* key_request) {
is_release_ = true;
CdmResponseType status = license_parser_->PrepareKeyUpdateRequest(
false, app_parameters_, key_request, server_url);
false, app_parameters_, &key_request->message,
&key_request->url);
key_request->type = kKeyRequestTypeRelease;
if (KEY_MESSAGE != status) return status;
@@ -463,6 +486,11 @@ bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
return license_parser_->IsKeyLoaded(key_id);
}
int64_t CdmSession::GetDurationRemaining() {
if (policy_engine_->IsLicenseForFuture()) return 0;
return policy_engine_->GetLicenseOrPlaybackDurationRemaining();
}
CdmSessionId CdmSession::GenerateSessionId() {
static int session_num = 1;
return SESSION_ID_PREFIX + IntToString(++session_num);
@@ -477,8 +505,6 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
std::vector<uint8_t> random_data(
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0);
if (!file_handle_->Reset(security_level_)) return false;
while (key_set_id->empty()) {
if (!crypto_session_->GetRandom(random_data.size(), &random_data[0]))
return false;
@@ -514,13 +540,6 @@ CdmResponseType CdmSession::StoreLicense() {
if (!StoreLicense(DeviceFiles::kLicenseStateActive)) {
LOGE("CdmSession::StoreLicense: Unable to store license");
CdmResponseType sts = Init();
if (sts != NO_ERROR) {
LOGW("CdmSession::StoreLicense: Reinitialization failed");
return sts;
}
key_set_id_.clear();
return STORE_LICENSE_ERROR_1;
}
return NO_ERROR;
@@ -533,11 +552,6 @@ CdmResponseType CdmSession::StoreLicense() {
return STORE_LICENSE_ERROR_2;
}
if (!file_handle_->Reset(security_level_)) {
LOGE("CdmSession::StoreLicense: Unable to initialize device files");
return STORE_LICENSE_ERROR_3;
}
std::string app_id;
GetApplicationId(&app_id);
if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_,
@@ -549,8 +563,6 @@ CdmResponseType CdmSession::StoreLicense() {
}
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
if (!file_handle_->Reset(security_level_)) return false;
return file_handle_->StoreLicense(
key_set_id_, state, offline_init_data_, key_request_, key_response_,
offline_key_renewal_request_, offline_key_renewal_response_,
@@ -558,14 +570,15 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
policy_engine_->GetLastPlaybackTime(), app_parameters_);
}
CdmResponseType CdmSession::ReleaseCrypto() {
crypto_session_->Close();
return NO_ERROR;
}
bool CdmSession::DeleteLicense() {
if (!is_offline_ && license_parser_->provider_session_token().empty())
return false;
if (!file_handle_->Reset(security_level_)) {
LOGE("CdmSession::DeleteLicense: Unable to initialize device files");
return false;
}
if (is_offline_) {
return file_handle_->DeleteLicense(key_set_id_);
} else {
@@ -613,13 +626,55 @@ CdmResponseType CdmSession::UpdateUsageInformation() {
return crypto_session_->UpdateUsageInformation();
}
CdmResponseType CdmSession::ReleaseCrypto() {
crypto_session_->Close();
return NO_ERROR;
CdmResponseType CdmSession::GenericEncrypt(const std::string& in_buffer,
const std::string& key_id,
const std::string& iv,
CdmEncryptionAlgorithm algorithm,
std::string* out_buffer) {
if (!out_buffer) {
LOGE("CdmSession::GenericEncrypt: No output destination provided");
return INVALID_PARAMETERS_ENG_6;
}
return crypto_session_->GenericEncrypt(in_buffer, key_id, iv, algorithm,
out_buffer);
}
CdmResponseType CdmSession::GenericDecrypt(const std::string& in_buffer,
const std::string& key_id,
const std::string& iv,
CdmEncryptionAlgorithm algorithm,
std::string* out_buffer) {
if (!out_buffer) {
LOGE("CdmSession::GenericDecrypt: No output destination provided");
return INVALID_PARAMETERS_ENG_7;
}
return crypto_session_->GenericDecrypt(in_buffer, key_id, iv, algorithm,
out_buffer);
}
CdmResponseType CdmSession::GenericSign(const std::string& message,
const std::string& key_id,
CdmSigningAlgorithm algorithm,
std::string* signature) {
if (!signature) {
LOGE("CdmSession::GenericSign: No output destination provided");
return INVALID_PARAMETERS_ENG_8;
}
return crypto_session_->GenericSign(message, key_id, algorithm, signature);
}
CdmResponseType CdmSession::GenericVerify(const std::string& message,
const std::string& key_id,
CdmSigningAlgorithm algorithm,
const std::string& signature) {
return crypto_session_->GenericVerify(message, key_id, algorithm, signature);
}
// For testing only - takes ownership of pointers
void CdmSession::set_license_parser(CdmLicense* license_parser) {
license_parser_.reset(license_parser);
mock_license_parser_in_use_ = true;
}
void CdmSession::set_crypto_session(CryptoSession* crypto_session) {
@@ -628,6 +683,7 @@ void CdmSession::set_crypto_session(CryptoSession* crypto_session) {
void CdmSession::set_policy_engine(PolicyEngine* policy_engine) {
policy_engine_.reset(policy_engine);
mock_policy_engine_in_use_ = true;
}
void CdmSession::set_file_handle(DeviceFiles* file_handle) {