Merges to android Pi release (part 9)

These are a set of CLs merged from the wv cdm repo to the android repo.

* Make Android NDK Builds Work With Latest BoringSSL

  Author: John W. Bruce <juce@google.com>

  [ Merge of http://go/wvgerrit/37000 ]

  The latest updates to BoringSSL require C99 or later. Our NDK-based
  builds (OEMCrypto Variants & Fastball) were not specifying a C standard.
  This patch adds compiler flags so that C files are compiled as C11 now.
  Note that this is about the *C* standard in use, not the *C++* standard,
  which this patch leaves untouched.

  BUG: 67907873
  Test: build_android_mock.sh

*  Update BoringSSL to f7412cb072cc6b1847140e0c4f8b3ceeccd0e708

  Author: John W. Bruce <juce@google.com>

  [ Merge of http://go/wvgerrit/36761 ]

  This is the result of running UPDATE_BORINGSSL.sh. Future runs of this
  script should produce much smaller sets of changed files, but because
  the BoringSSL revision already in this directory was so old and
  contained many extraneous files from the Android operating system, the
  set of changed files is extensive this time.

  BUG: 67907873

* Refactoring the build files.

  Author: Vasantha Rao Polipelli <vasanthap@google.com>

  [ Merge of http://go/wvgerrit/37041 ]

  Move all common build dependencies to .gypi so that all fuzz test
  binary targets can be added to .gyp file without repeating code.

* Introduce service certificate request property

  Author: Rahul Frias <rfrias@google.com>

  [ Merge of http://go/wvgerrit/36941 ]

  Platforms differ on whether they allows service certificates to be
  requested if privacy mode is enabled and a certificate is not present.
  This property allows behavior to be configurable.

  Generating the service certificate request will be introduced
  in a follow on CL.

  BUG: 68328352

* Deprecate using keyboxes as identification

  Author: Rahul Frias <rfrias@google.com>

  [ Merge of http://go/wvgerrit/36740 ]

  Previously some platforms supported using keyboxes rather than
  certificates as the identification tokens in the license request
  message. All platforms that share core CDM code of the master branch now
  either provision using a keybox and use a DRM certificate or an
  OEM certificate as identification. No future usage of keyboxes
  as identifying tokens is planned.

  Since the platform property use_certificates_as_identification
  is always set to true, the negative code paths are never taken and
  can be removed.

* OEMCrypto_GenerateSignature API Fuzz Test.

  Author: Vasantha Rao Polipelli <vasanthap@google.com>

  [ Merge of http://go/wvgerrit/36863 ]

  - The first automated API fuzz test.
  - Also sumitting the corpus for the API fuzzed.

* Add Script to Update BoringSSL from Source

  Author: John W. Bruce <juce@google.com>

  [ Merge of http://go/wvgerrit/36760 ]

  Adds a script to third_party/boringssl/ that, when run, deletes all the
  auto-generated files in the generated/ directory and regenerates them
  from scratch, starting from the latest public HEAD of BoringSSL.

  Bug: 67907873

* Fix Fastball / OEMCrypto Variant BoringSSL Makefiles

  Author: John W. Bruce <juce@google.com>

  [ Merge of http://go/wvgerrit/36926 ]

  Previously, when moving the BoringSSL source within the tree, I was not
  able to verify that I had not broken the NDK-compatible makefiles used
  by Fastball because that build is broken on master. I had to make a
  best-guess as to how they should be updated and hope.

  Now, however, I have been informed that the OEMCrypto Variants also use
  these makefiles, and I have been able to use that build to find where I
  broke them and get them fully working.

  Bug: 67386164
  Test: build_android_mock.sh

* Add kit/ to BoringSSL Include Path for Fastball & OEMCrypto Variants

  Author: John W. Bruce <juce@google.com>

  [ Merge of http://go/wvgerrit/36925 ]

  When I moved the BoringSSL source in the tree, I updated the Android.mk
  files that pointed to it in order to build it. I did not realize that
  some makefiles outside that directory also contained hardcoded pointers
  into that directory. These references broke after the move. This patch
  fixes those paths to point to the new BoringSSL location.

  Bug: 67386164
  Test: build_android_mock.sh

* OEMCrypto Unit Test Refactor.

  Author: Vasantha Rao Polipelli <vasanthap@google.com>

  [ Merge of http://go/wvgerrit/36562 ]

  Refactoring OEMCrypto Tests so the Session Utility test code can be reused in fuzz tests.

* Reorder license server config table to match ids

  Author: Jeff Fore <jfore@google.com>

  [ Merge of http://go/wvgerrit/36743 ]

* Separate Hand-Written BoringSSL Files from Downloaded/Generated Ones

  Author: John W. Bruce <juce@google.com>

  [ Merge of http://go/wvgerrit/36561 ]

  I want to make updating BoringSSL as simple as possible for us going
  forward. A future commit will add a script that automatically downloads
  and sets up the latest version of BoringSSL. To facilitate this script,
  a clear distinction needs to be made between the files that can be
  downloaded with / regenerated from the BoringSSL source and the files
  that are maintained by us by hand.

  The version of BoringSSL in this change is exactly the same as the one
  already in this directory. It has just been moved one folder deeper.

  Bug: 67907873

* Remove BoringSSL Symlinks, They Are Confusing Gerrit

  Author: John W. Bruce <juce@google.com>

  [ Merge of http://go/wvgerrit/36560 ]

  There are some symlinks in the current copy of BoringSSL that are
  causing headaches when I try to upload future changes to Gerrit. These
  were inherited from the Android OS and are not used by our build
  anywhere. They would be wiped out when I update BoringSSL anyway, but
  wiping them out in a separate change before I upload any other changes
  avoids confusing Gerrit.

  Bug: 67907873

* Add group master key id to support sublicense master
  key rotation, and content identification.

  Author: Jeff Fore <jfore@google.com>

  [ Merge of http://go/wvgerrit/36180 ]

* OEMCrypto Fuzzer test framework

  Author: Vasantha Rao Polipelli <vasanthap@google.com>

  [ Merge of http://go/wvgerrit/36280 ]

  - Adding a sample fuzz test.
  - Adding build scripts for building the new Fuzz Tests to come.

  Design doc: go/oemcrypt_ref_impl_fuzz

* Build Mod Mock with C++ 11

  Author: Fred Gylys-Colwell <fredgc@google.com>

  [ Merge of http://go/wvgerrit/36328 ]

  This should fix the android oemcrypto mock build:
  http://go/wvbuild/job/Android_OEMCrypto_Variants

BUG: 71650075
Test: Not currently passing. Will be addressed in a subsequent
    commit in the chain.

Change-Id: Ic4d5be3118ef97e3f7d386149a2b5d9be8f0a87e
This commit is contained in:
Rahul Frias
2018-01-10 18:01:48 -08:00
parent 1884cf738e
commit 81d607c008
35 changed files with 688 additions and 1055 deletions

View File

@@ -209,7 +209,8 @@ class CryptoSession {
const std::string& provider_session_token);
virtual metrics::CryptoMetrics* GetCryptoMetrics() { return metrics_; }
virtual CdmResponseType AddSubSession(const std::string& sub_session_key_id);
virtual CdmResponseType AddSubSession(const std::string& sub_session_key_id,
const std::string& group_master_key_id);
// TODO(jfore): exists is set based on whether a sub session exists. For now,
// that is not assumed to be an error.
virtual bool GenerateSubSessionNonce(const std::string& sub_session_key_id,

View File

@@ -29,6 +29,7 @@ class InitializationData {
std::vector<uint8_t> hls_iv() const { return hls_iv_; }
CdmHlsMethod hls_method() const { return hls_method_; }
std::vector<video_widevine::SubLicense> ExtractEmbeddedKeys() const;
const std::string ExtractGroupMasterKeyId() const;
private:
// Parse a blob of multiple concatenated PSSH atoms to extract the first

View File

@@ -37,12 +37,12 @@ class Properties {
static inline bool oem_crypto_use_userspace_buffers() {
return oem_crypto_use_userspace_buffers_;
}
static inline bool use_certificates_as_identification() {
return use_certificates_as_identification_;
}
static inline bool provisioning_messages_are_binary() {
return provisioning_messages_are_binary_;
}
static inline bool allow_service_certificate_requests() {
return allow_service_certificate_requests_;
}
static void set_provisioning_messages_are_binary(bool flag) {
provisioning_messages_are_binary_ = flag;
}
@@ -119,6 +119,7 @@ class Properties {
static bool use_certificates_as_identification_;
static bool security_level_path_backward_compatibility_support_;
static bool provisioning_messages_are_binary_;
static bool allow_service_certificate_requests_;
static scoped_ptr<CdmClientPropertySetMap> session_property_set_;
CORE_DISALLOW_COPY_AND_ASSIGN(Properties);

View File

@@ -109,6 +109,7 @@ static const char EMPTY_SPOID[] = "";
//Policy engine HDCP enforcement
static const uint32_t HDCP_UNSPECIFIED_VIDEO_RESOLUTION = 0;
static const int64_t HDCP_DEVICE_CHECK_INTERVAL = 10;
static const char EMPTY_APP_PACKAGE_NAME[] = "";
} // namespace wvcdm
#endif // WVCDM_CORE_WV_CDM_CONSTANTS_H_

View File

@@ -75,6 +75,15 @@ CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid)
}
life_span_.Start();
metrics_.cdm_engine_creation_time_millis_.Record(clock_.GetCurrentTime());
std::string cdm_version;
if(Properties::GetWVCdmVersion(&cdm_version)) {
metrics_.cdm_engine_cdm_version_.Record(cdm_version);
} else {
// Set error "false", the return value of GetWVCdmVersion.
metrics_.cdm_engine_cdm_version_.SetError(false);
}
}
CdmEngine::~CdmEngine() {
@@ -333,13 +342,8 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
if (license_type == kLicenseTypeRelease &&
!session->license_received()) {
M_TIME(
sts = session->RestoreOfflineSession(
key_set_id,
kLicenseTypeRelease),
session->GetMetrics(),
cdm_session_restore_offline_session_,
sts);
sts = session->RestoreOfflineSession(key_set_id, kLicenseTypeRelease);
session->GetMetrics()->cdm_session_restore_offline_session_.Increment(sts);
if (sts != KEY_ADDED) {
LOGE("CdmEngine::GenerateKeyRequest: key release restoration failed,"
"sts = %d", static_cast<int>(sts));
@@ -448,14 +452,8 @@ CdmResponseType CdmEngine::RestoreKey(const CdmSessionId& session_id,
}
CdmResponseType sts;
M_TIME(
sts = session->RestoreOfflineSession(
key_set_id,
kLicenseTypeOffline),
session->GetMetrics(),
cdm_session_restore_offline_session_,
sts);
sts = session->RestoreOfflineSession(key_set_id, kLicenseTypeOffline);
session->GetMetrics()->cdm_session_restore_offline_session_.Increment(sts);
if (sts == NEED_PROVISIONING) {
cert_provisioning_requested_security_level_ =
session->GetRequestedSecurityLevel();
@@ -564,13 +562,9 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
}
if (query_token == QUERY_KEY_SECURITY_LEVEL) {
CdmSecurityLevel level;
M_TIME(
level = crypto_session.GetSecurityLevel(),
metrics_.GetCryptoMetrics(),
crypto_session_get_security_level_,
level);
switch (level) {
CdmSecurityLevel found_security_level =
crypto_session.GetSecurityLevel();
switch (found_security_level) {
case kSecurityLevelL1:
*query_response = QUERY_VALUE_SECURITY_LEVEL_L1;
break;
@@ -585,18 +579,15 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
*query_response = QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
break;
default:
LOGW("CdmEngine::QueryStatus: Unknown security level: %d", level);
LOGW("CdmEngine::QueryStatus: Unknown security level: %d",
found_security_level);
return UNKNOWN_ERROR;
}
} else if (query_token == QUERY_KEY_DEVICE_ID) {
std::string deviceId;
bool got_id;
M_TIME(
got_id = crypto_session.GetExternalDeviceUniqueId(
&deviceId),
metrics_.GetCryptoMetrics(),
crypto_session_get_device_unique_id_,
got_id);
bool got_id = crypto_session.GetExternalDeviceUniqueId(&deviceId);
metrics_.GetCryptoMetrics()->crypto_session_get_device_unique_id_
.Increment(got_id);
if (!got_id) {
LOGW("CdmEngine::QueryStatus: QUERY_KEY_DEVICE_ID unknown failure");
return UNKNOWN_ERROR;
@@ -605,14 +596,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
*query_response = deviceId;
} else if (query_token == QUERY_KEY_SYSTEM_ID) {
uint32_t system_id;
bool got_id;
M_TIME(
got_id = crypto_session.GetSystemId(
&system_id),
metrics_.GetCryptoMetrics(),
crypto_session_get_system_id_,
got_id,
system_id);
bool got_id = crypto_session.GetSystemId(&system_id);
if (!got_id) {
LOGW("CdmEngine::QueryStatus: QUERY_KEY_SYSTEM_ID unknown failure");
return UNKNOWN_ERROR;
@@ -642,17 +626,17 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
current_hdcp : max_hdcp);
} else if (query_token == QUERY_KEY_USAGE_SUPPORT) {
bool supports_usage_reporting;
bool got_info;
M_TIME(
got_info = crypto_session.UsageInformationSupport(
&supports_usage_reporting),
metrics_.GetCryptoMetrics(),
crypto_session_usage_information_support_,
got_info);
bool got_info = crypto_session.UsageInformationSupport(
&supports_usage_reporting);
if (!got_info) {
LOGW("CdmEngine::QueryStatus: UsageInformationSupport failed");
metrics_.GetCryptoMetrics()->crypto_session_usage_information_support_
.SetError(got_info);
return UNKNOWN_ERROR;
}
metrics_.GetCryptoMetrics()->crypto_session_usage_information_support_
.Record(supports_usage_reporting);
*query_response =
supports_usage_reporting ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
@@ -912,12 +896,7 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
"missing and crypto session open failed.");
return EMPTY_PROVISIONING_CERTIFICATE_2;
}
CdmSecurityLevel security_level;
M_TIME(
security_level = crypto_session.GetSecurityLevel(),
metrics_.GetCryptoMetrics(),
crypto_session_get_security_level_,
security_level);
CdmSecurityLevel security_level = crypto_session.GetSecurityLevel();
if (!IsProvisioned(security_level)) {
LOGE(
"CdmEngine::HandleProvisioningResponse: provisioning object "
@@ -969,11 +948,10 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
}
CdmResponseType CdmEngine::DeleteUsageTable(CdmSecurityLevel security_level) {
scoped_ptr<CryptoSession> crypto_session(
new CryptoSession(metrics_.GetCryptoMetrics()));
CryptoSession crypto_session(metrics_.GetCryptoMetrics());
CdmResponseType status;
M_TIME(
status = crypto_session->Open(
status = crypto_session.Open(
security_level == kSecurityLevelL3 ?
kLevel3 :
kLevelDefault),
@@ -983,14 +961,12 @@ CdmResponseType CdmEngine::DeleteUsageTable(CdmSecurityLevel security_level) {
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
if (NO_ERROR != status) {
LOGE("CdmEngine::DeleteUsageTable: error opening crypto session: %d",
status);
status);
return UNPROVISION_ERROR_4;
}
M_TIME(
status = crypto_session->DeleteAllUsageReports(),
metrics_.GetCryptoMetrics(),
crypto_session_delete_all_usage_reports_,
status);
status = crypto_session.DeleteAllUsageReports();
metrics_.GetCryptoMetrics()->crypto_session_delete_all_usage_reports_
.Increment(status);
if (status != NO_ERROR) {
LOGE("CdmEngine::DeleteUsageTable: error deleteing usage reports: %d",
status);
@@ -1418,13 +1394,8 @@ CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
return LOAD_USAGE_INFO_MISSING;
}
CdmResponseType status;
M_TIME(
status = session->RestoreUsageSession(usage_data),
session->GetMetrics(),
cdm_session_restore_usage_session_,
status);
CdmResponseType status = session->RestoreUsageSession(usage_data);
session->GetMetrics()->cdm_session_restore_usage_session_.Increment(status);
if (KEY_ADDED != status) {
LOGE("CdmEngine::LoadUsageSession: usage session error %ld", status);
return status;
@@ -1760,11 +1731,9 @@ void CdmEngine::DeleteAllUsageReportsUponFactoryReset() {
status,
cert_provisioning_requested_security_level_);
if (NO_ERROR == status) {
M_TIME(
status = crypto_session->DeleteAllUsageReports(),
metrics_.GetCryptoMetrics(),
crypto_session_delete_all_usage_reports_,
status);
status = crypto_session->DeleteAllUsageReports();
metrics_.GetCryptoMetrics()->crypto_session_delete_all_usage_reports_
.Increment(status);
if (NO_ERROR != status) {
LOGW(
"CdmEngine::DeleteAllUsageReportsUponFactoryReset: "

View File

@@ -92,11 +92,10 @@ CdmResponseType CdmSession::Init(
sts,
requested_security_level_);
if (NO_ERROR != sts) return sts;
M_TIME(
security_level_ = crypto_session_->GetSecurityLevel(),
crypto_metrics_,
crypto_session_get_security_level_,
security_level_);
security_level_ = crypto_session_->GetSecurityLevel();
crypto_metrics_->crypto_session_security_level_.Record(security_level_);
if (!file_handle_->Init(security_level_)) {
LOGE("CdmSession::Init: Unable to initialize file handle");
return SESSION_FILE_HANDLE_INIT_ERROR;
@@ -121,42 +120,25 @@ CdmResponseType CdmSession::Init(
std::string serial_number;
CdmClientTokenType client_token_type =
crypto_session_->GetPreProvisionTokenType();
if ((client_token_type == kClientTokenKeybox) &&
!Properties::use_certificates_as_identification()) {
// Keybox is client token.
LOGW("CdmSession::Init: Properties::use_certificates_as_identification() "
"is not set - using Keybox for license requests (not recommended).");
bool get_client_token_sts;
M_TIME(
get_client_token_sts = crypto_session_->GetClientToken(
&client_token),
crypto_metrics_,
crypto_session_get_token_,
get_client_token_sts);
if (!get_client_token_sts) {
return SESSION_INIT_ERROR_1;
}
} else {
// License server client ID token is a stored certificate. Stage it or
// indicate that provisioning is needed. Get token from stored certificate
std::string wrapped_key;
if (!file_handle_->RetrieveCertificate(&client_token, &wrapped_key,
&serial_number, nullptr)) {
return NEED_PROVISIONING;
}
bool load_cert_sts;
M_TIME(
load_cert_sts = crypto_session_->LoadCertificatePrivateKey(
wrapped_key),
crypto_metrics_,
crypto_session_load_certificate_private_key_,
load_cert_sts);
if(!load_cert_sts) {
return NEED_PROVISIONING;
}
client_token_type = kClientTokenDrmCert;
// License server client ID token is a stored certificate. Stage it or
// indicate that provisioning is needed. Get token from stored certificate
std::string wrapped_key;
if (!file_handle_->RetrieveCertificate(&client_token, &wrapped_key,
&serial_number, nullptr)) {
return NEED_PROVISIONING;
}
bool load_cert_sts;
M_TIME(
load_cert_sts = crypto_session_->LoadCertificatePrivateKey(
wrapped_key),
crypto_metrics_,
crypto_session_load_certificate_private_key_,
load_cert_sts);
if(!load_cert_sts) {
return NEED_PROVISIONING;
}
client_token_type = kClientTokenDrmCert;
// Session is provisioned with certificate needed to construct
// license request (or with keybox).
@@ -396,7 +378,8 @@ CdmResponseType CdmSession::GenerateKeyRequest(
init_data.ExtractEmbeddedKeys();
for (size_t i = 0; i < embedded_key_data.size(); ++i) {
CdmResponseType sts = crypto_session_->AddSubSession(
embedded_key_data[i].sub_session_key_id());
embedded_key_data[i].sub_session_key_id(),
init_data.ExtractGroupMasterKeyId());
if (NO_ERROR != sts) {
LOGE("CdmSession::GenerateKeyRequest: Unable to generate sub session");
return sts;
@@ -874,13 +857,10 @@ void CdmSession::GetApplicationId(std::string* app_id) {
CdmResponseType CdmSession::DeleteMultipleUsageInformation(
const std::vector<std::string>& provider_session_tokens) {
CdmResponseType sts;
M_TIME(
sts = crypto_session_->DeleteMultipleUsageInformation(
provider_session_tokens),
crypto_metrics_,
crypto_session_delete_multiple_usage_information_,
sts);
CdmResponseType sts = crypto_session_->DeleteMultipleUsageInformation(
provider_session_tokens);
crypto_metrics_->crypto_session_delete_multiple_usage_information_
.Increment(sts);
return sts;
}

View File

@@ -295,25 +295,22 @@ class SubLicenseKeySession : public KeySession {
public:
SubLicenseKeySession(SubLicenseSessionMap& sub_license_oec_sessions,
metrics::CryptoMetrics* metrics,
std::string& wrapped_private_device_key,
SecurityLevel requested_security_level)
const std::string& wrapped_private_device_key,
SecurityLevel requested_security_level,
const std::string& group_master_key_id)
: KeySession(metrics),
state_(kInitializing),
wrapped_private_device_key_(wrapped_private_device_key),
sub_license_oec_sessions_(sub_license_oec_sessions),
requested_security_level_(requested_security_level) {}
requested_security_level_(requested_security_level),
group_master_key_id_(group_master_key_id) {}
virtual ~SubLicenseKeySession() {
for (SubLicenseSessionMap::iterator oec_session =
sub_license_oec_sessions_.begin();
oec_session != sub_license_oec_sessions_.end(); oec_session++) {
OEMCryptoResult close_sts;
M_TIME(
close_sts = OEMCrypto_CloseSession(
oec_session->second),
metrics_,
oemcrypto_close_session_,
close_sts);
metrics_->oemcrypto_close_session_.Increment(
OEMCrypto_CloseSession(oec_session->second));
}
sub_license_oec_sessions_.clear();
}
@@ -438,16 +435,12 @@ class SubLicenseKeySession : public KeySession {
OEMCryptoResult ResetCryptoSessions() {
for (SubLicenseSessionMap::iterator it = sub_license_oec_sessions_.begin();
it != sub_license_oec_sessions_.end(); it++) {
OEMCryptoResult sts;
M_TIME(
sts = OEMCrypto_CloseSession(it->second),
metrics_, oemcrypto_close_session_, sts);
OEMCryptoResult sts = OEMCrypto_CloseSession(it->second);
metrics_->oemcrypto_close_session_.Increment(sts);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
M_TIME(
sts = OEMCrypto_OpenSession(&it->second, requested_security_level_),
metrics_, oemcrypto_open_session_, sts, requested_security_level_);
sts = OEMCrypto_OpenSession(&it->second, requested_security_level_);
if (OEMCrypto_SUCCESS != sts) {
return sts;
}
@@ -589,8 +582,10 @@ class SubLicenseKeySession : public KeySession {
std::string mac_deriv_message;
std::string enc_deriv_message;
GenerateMacContext(key.track_label(), &mac_deriv_message);
GenerateEncryptContext(key.track_label(), &enc_deriv_message);
GenerateMacContext(group_master_key_id_ +
key.track_label(), &mac_deriv_message);
GenerateEncryptContext(group_master_key_id_ +
key.track_label(), &enc_deriv_message);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL;
@@ -688,6 +683,7 @@ class SubLicenseKeySession : public KeySession {
std::vector<CryptoKey> keys_;
SubLicenseSessionMap& sub_license_oec_sessions_;
SecurityLevel requested_security_level_;
KeyId group_master_key_id_;
};
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
@@ -701,6 +697,7 @@ CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
usage_table_header_(NULL),
request_id_base_(0),
cipher_mode_(kCipherModeCtr) {
assert(metrics);
Init();
life_span_.Start();
}
@@ -799,8 +796,7 @@ bool CryptoSession::GetTokenFromKeybox(std::string* token) {
metrics_,
oemcrypto_get_key_data_,
status,
metrics::Pow2Bucket(buf_size),
requested_security_level_);
metrics::Pow2Bucket(buf_size));
if (OEMCrypto_SUCCESS == status) {
token->swap(temp_buffer);
return true;
@@ -883,21 +879,13 @@ bool CryptoSession::GetProvisioningToken(std::string* token) {
CdmSecurityLevel CryptoSession::GetSecurityLevel() {
LOGV("CryptoSession::GetSecurityLevel");
if (!initialized_) {
M_RECORD(metrics_, oemcrypto_security_level_, 0,
kSecurityLevelUninitialized, requested_security_level_);
return kSecurityLevelUninitialized;
}
wvcdm::metrics::TimerMetric timer;
timer.Start();
std::string security_level =
OEMCrypto_SecurityLevel(requested_security_level_);
double clock_time = timer.AsUs();
if ((security_level.size() != 2) || (security_level.at(0) != 'L')) {
M_RECORD(metrics_, oemcrypto_security_level_, clock_time,
kSecurityLevelUnknown, requested_security_level_);
return kSecurityLevelUnknown;
}
@@ -917,8 +905,6 @@ CdmSecurityLevel CryptoSession::GetSecurityLevel() {
break;
}
M_RECORD(metrics_, oemcrypto_security_level_, clock_time,
cdm_security_level, requested_security_level_);
return cdm_security_level;
}
@@ -944,16 +930,10 @@ bool CryptoSession::GetInternalDeviceUniqueId(std::string* device_id) {
size_t id_length = 32;
id.resize(id_length);
OEMCryptoResult sts;
M_TIME(
sts = OEMCrypto_GetDeviceID(
&id[0],
&id_length,
requested_security_level_),
metrics_,
oemcrypto_get_device_id_,
sts,
requested_security_level_);
OEMCryptoResult sts = OEMCrypto_GetDeviceID(&id[0], &id_length,
requested_security_level_);
// Increment the count of times this method was called.
metrics_->oemcrypto_get_device_id_.Increment(sts);
if (OEMCrypto_SUCCESS != sts) {
return false;
@@ -993,12 +973,10 @@ bool CryptoSession::GetApiVersion(uint32_t* version) {
if (!initialized_) {
return false;
}
M_TIME(
*version = OEMCrypto_APIVersion(requested_security_level_),
metrics_,
oemcrypto_api_version_,
*version,
requested_security_level_);
*version = OEMCrypto_APIVersion(requested_security_level_);
// Record the version into the metrics.
metrics_->oemcrypto_api_version_.Record(*version);
return true;
}
@@ -1026,8 +1004,7 @@ bool CryptoSession::GetSystemId(uint32_t* system_id) {
metrics_,
oemcrypto_get_key_data_,
sts,
metrics::Pow2Bucket(buf_size),
requested_security_level_);
metrics::Pow2Bucket(buf_size));
if (OEMCrypto_SUCCESS != sts) {
return false;
@@ -1078,8 +1055,7 @@ bool CryptoSession::GetProvisioningId(std::string* provisioning_id) {
metrics_,
oemcrypto_get_key_data_,
sts,
metrics::Pow2Bucket(buf_size),
requested_security_level_);
metrics::Pow2Bucket(buf_size));
if (OEMCrypto_SUCCESS != sts) {
return false;
}
@@ -1090,14 +1066,8 @@ bool CryptoSession::GetProvisioningId(std::string* provisioning_id) {
}
uint8_t CryptoSession::GetSecurityPatchLevel() {
uint8_t patch;
M_TIME(
patch = OEMCrypto_Security_Patch_Level(
requested_security_level_),
metrics_,
oemcrypto_security_patch_level_,
patch,
requested_security_level_);
uint8_t patch = OEMCrypto_Security_Patch_Level(requested_security_level_);
metrics_->oemcrypto_security_patch_level_.Record(patch);
return patch;
}
@@ -1112,10 +1082,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
OEMCrypto_SESSION sid;
requested_security_level_ = requested_security_level;
OEMCryptoResult sts;
M_TIME(
sts = OEMCrypto_OpenSession(&sid, requested_security_level),
metrics_, oemcrypto_open_session_, sts, requested_security_level);
OEMCryptoResult sts = OEMCrypto_OpenSession(&sid, requested_security_level);
if (OEMCrypto_SUCCESS == sts) {
oec_session_id_ = static_cast<CryptoSessionId>(sid);
LOGV("OpenSession: id= %ld", (uint32_t)oec_session_id_);
@@ -1130,15 +1097,10 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
sts, session_count_, (int)initialized_);
return UNKNOWN_ERROR;
}
OEMCryptoResult random_sts;
M_TIME(
random_sts = OEMCrypto_GetRandom(
reinterpret_cast<uint8_t*>(&request_id_base_),
sizeof(request_id_base_)),
metrics_,
oemcrypto_get_random_,
random_sts,
metrics::Pow2Bucket(sizeof(request_id_base_)));
OEMCryptoResult random_sts = OEMCrypto_GetRandom(
reinterpret_cast<uint8_t*>(&request_id_base_),
sizeof(request_id_base_));
metrics_->oemcrypto_get_random_.Increment(random_sts);
++request_id_index_;
CdmUsageSupportType usage_support_type;
@@ -1186,10 +1148,8 @@ void CryptoSession::Close() {
AutoLock auto_lock(crypto_lock_);
if (!open_) return;
key_session_.reset();
M_TIME(
close_sts = OEMCrypto_CloseSession(oec_session_id_),
metrics_, oemcrypto_close_session_, close_sts);
close_sts = OEMCrypto_CloseSession(oec_session_id_);
metrics_->oemcrypto_close_session_.Increment(close_sts);
if (OEMCrypto_SUCCESS == close_sts)
open_ = false;
update_usage_table = update_usage_table_after_close_session_;
@@ -1226,8 +1186,7 @@ bool CryptoSession::PrepareRequest(const std::string& message,
return false;
}
if (!Properties::use_certificates_as_identification() ||
(is_provisioning && (pre_provision_token_type_ == kClientTokenKeybox))) {
if (is_provisioning && (pre_provision_token_type_ == kClientTokenKeybox)) {
if (!GenerateDerivedKeys(message)) return false;
if (!GenerateSignature(message, signature)) return false;
@@ -1549,7 +1508,6 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
metrics_,
oemcrypto_copy_buffer_,
sts,
requested_security_level_,
metrics::Pow2Bucket(params.encrypt_length));
if (sts == OEMCrypto_ERROR_BUFFER_TOO_LARGE &&
@@ -1635,12 +1593,8 @@ CdmResponseType CryptoSession::UpdateUsageInformation() {
return NO_ERROR;
}
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_UpdateUsageTable(),
metrics_,
oemcrypto_update_usage_table_,
status);
OEMCryptoResult status = OEMCrypto_UpdateUsageTable();
metrics_->oemcrypto_update_usage_table_.Increment(status);
if (status != OEMCrypto_SUCCESS) {
LOGE("CryptoSession::UpdateUsageInformation: error=%ld", status);
return UNKNOWN_ERROR;
@@ -1657,15 +1611,9 @@ CdmResponseType CryptoSession::DeactivateUsageInformation(
const_cast<char*>(provider_session_token.data()));
// TODO(fredgc or rfrias): make sure oec_session_id_ is valid.
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_DeactivateUsageEntry(
(uint32_t)oec_session_id_,
pst,
provider_session_token.length()),
metrics_,
oemcrypto_deactivate_usage_entry_,
status);
OEMCryptoResult status = OEMCrypto_DeactivateUsageEntry(
(uint32_t)oec_session_id_, pst, provider_session_token.length());
metrics_->oemcrypto_deactivate_usage_entry_.Increment(status);
switch (status) {
case OEMCrypto_SUCCESS:
@@ -1695,17 +1643,10 @@ CdmResponseType CryptoSession::GenerateUsageReport(
const_cast<char*>(provider_session_token.data()));
size_t usage_length = 0;
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_ReportUsage(
oec_session_id_,
pst,
provider_session_token.length(),
NULL,
&usage_length),
metrics_,
oemcrypto_report_usage_,
status);
OEMCryptoResult status = OEMCrypto_ReportUsage(
oec_session_id_, pst, provider_session_token.length(),
NULL, &usage_length);
metrics_->oemcrypto_report_usage_.Increment(status);
if (OEMCrypto_SUCCESS != status) {
if (OEMCrypto_ERROR_SHORT_BUFFER != status) {
@@ -1717,16 +1658,13 @@ CdmResponseType CryptoSession::GenerateUsageReport(
std::vector<uint8_t> buffer(usage_length);
M_TIME(
status = OEMCrypto_ReportUsage(
status = OEMCrypto_ReportUsage(
oec_session_id_,
pst,
provider_session_token.length(),
&buffer[0],
&usage_length),
metrics_,
oemcrypto_report_usage_,
status);
&usage_length);
metrics_->oemcrypto_report_usage_.Increment(status);
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::GenerateUsageReport: Report Usage error=%ld", status);
@@ -1800,19 +1738,10 @@ CdmResponseType CryptoSession::ReleaseUsageInformation(
const uint8_t* sig = reinterpret_cast<const uint8_t*>(signature.data());
const uint8_t* pst = msg + GetOffset(message, provider_session_token);
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_DeleteUsageEntry(
oec_session_id_,
pst,
provider_session_token.length(),
msg,
message.length(),
sig,
signature.length()),
metrics_,
oemcrypto_delete_usage_entry_,
status);
OEMCryptoResult status = OEMCrypto_DeleteUsageEntry(
oec_session_id_, pst, provider_session_token.length(),
msg, message.length(), sig, signature.length());
metrics_->oemcrypto_delete_usage_entry_.Increment(status);
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::ReleaseUsageInformation: Report Usage error=%ld",
@@ -1833,13 +1762,10 @@ CdmResponseType CryptoSession::DeleteUsageInformation(
OEMCryptoResult status;
{
AutoLock auto_lock(crypto_lock_);
M_TIME(
status = OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(provider_session_token.c_str()),
provider_session_token.length()),
metrics_,
oemcrypto_force_delete_usage_entry_,
status);
status = OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(provider_session_token.c_str()),
provider_session_token.length());
metrics_->oemcrypto_force_delete_usage_entry_.Increment(status);
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::DeleteUsageInformation: Delete Usage Table error "
"= %ld", status);
@@ -1858,15 +1784,10 @@ CdmResponseType CryptoSession::DeleteMultipleUsageInformation(
{
AutoLock auto_lock(crypto_lock_);
for (size_t i=0; i < provider_session_tokens.size(); ++i) {
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(
provider_session_tokens[i].c_str()),
provider_session_tokens[i].length()),
metrics_,
oemcrypto_force_delete_usage_entry_,
status);
OEMCryptoResult status = OEMCrypto_ForceDeleteUsageEntry(
reinterpret_cast<const uint8_t*>(provider_session_tokens[i].c_str()),
provider_session_tokens[i].length());
metrics_->oemcrypto_force_delete_usage_entry_.Increment(status);
if (OEMCrypto_SUCCESS != status) {
LOGW("CryptoSession::DeleteMultipleUsageInformation: "
"Delete Usage Table error =%ld", status);
@@ -1884,11 +1805,8 @@ CdmResponseType CryptoSession::DeleteAllUsageReports() {
OEMCryptoResult status;
{
AutoLock auto_lock(crypto_lock_);
M_TIME(
status = OEMCrypto_DeleteOldUsageTable(),
metrics_,
oemcrypto_delete_usage_table_,
status);
status = OEMCrypto_DeleteOldUsageTable();
metrics_->oemcrypto_delete_usage_table_.Increment(status);
if (OEMCrypto_SUCCESS != status) {
LOGE("CryptoSession::DeleteAllUsageReports: Delete Usage Table error "
"=%ld", status);
@@ -1901,13 +1819,9 @@ CdmResponseType CryptoSession::DeleteAllUsageReports() {
}
bool CryptoSession::IsAntiRollbackHwPresent() {
bool is_present;
M_TIME(
is_present = OEMCrypto_IsAntiRollbackHwPresent(requested_security_level_),
metrics_,
oemcrypto_is_anti_rollback_hw_present_,
is_present,
requested_security_level_);
bool is_present =
OEMCrypto_IsAntiRollbackHwPresent(requested_security_level_);
metrics_->oemcrypto_is_anti_rollback_hw_present_.Record(is_present);
return is_present;
}
@@ -1920,14 +1834,8 @@ bool CryptoSession::GenerateNonce(uint32_t* nonce) {
LOGV("CryptoSession::GenerateNonce: Lock");
AutoLock auto_lock(crypto_lock_);
OEMCryptoResult result;
M_TIME(
result = OEMCrypto_GenerateNonce(
oec_session_id_,
nonce),
metrics_,
oemcrypto_generate_nonce_,
result);
OEMCryptoResult result = OEMCrypto_GenerateNonce(oec_session_id_, nonce);
metrics_->oemcrypto_generate_nonce_.Increment(result);
return OEMCrypto_SUCCESS == result;
}
@@ -2112,20 +2020,17 @@ bool CryptoSession::GetHdcpCapabilities(HdcpCapability* current,
"NULL");
return false;
}
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_GetHDCPCapability(
requested_security_level_,
current,
max),
metrics_,
oemcrypto_get_hdcp_capability_,
status,
requested_security_level_);
OEMCryptoResult status = OEMCrypto_GetHDCPCapability(
requested_security_level_, current, max);
if (OEMCrypto_SUCCESS != status) {
metrics_->oemcrypto_current_hdcp_capability_.SetError(status);
metrics_->oemcrypto_max_hdcp_capability_.SetError(status);
LOGW("OEMCrypto_GetHDCPCapability fails with %d", status);
return false;
}
metrics_->oemcrypto_current_hdcp_capability_.Record(*current);
metrics_->oemcrypto_max_hdcp_capability_.Record(*max);
return true;
}
@@ -2152,15 +2057,8 @@ bool CryptoSession::GetRandom(size_t data_length, uint8_t* random_data) {
LOGE("CryptoSession::GetRandom: random data destination not provided");
return false;
}
OEMCryptoResult sts;
M_TIME(
sts = OEMCrypto_GetRandom(
random_data,
data_length),
metrics_,
oemcrypto_get_random_,
sts,
metrics::Pow2Bucket(data_length));
OEMCryptoResult sts = OEMCrypto_GetRandom(random_data, data_length);
metrics_->oemcrypto_get_random_.Increment(sts);
if (sts != OEMCrypto_SUCCESS) {
LOGE("OEMCrypto_GetRandom fails with %d", sts);
@@ -2179,19 +2077,16 @@ bool CryptoSession::GetNumberOfOpenSessions(size_t* count) {
}
size_t sessions_count;
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_GetNumberOfOpenSessions(
requested_security_level_,
&sessions_count),
metrics_,
oemcrypto_get_number_of_open_sessions_,
status,
requested_security_level_);
OEMCryptoResult status = OEMCrypto_GetNumberOfOpenSessions(
requested_security_level_, &sessions_count);
if (OEMCrypto_SUCCESS != status) {
LOGW("OEMCrypto_GetNumberOfOpenSessions fails with %d", status);
metrics_->oemcrypto_number_of_open_sessions_.SetError(status);
return false;
}
metrics_->oemcrypto_number_of_open_sessions_.Record(sessions_count);
*count = sessions_count;
return true;
}
@@ -2205,20 +2100,15 @@ bool CryptoSession::GetMaxNumberOfSessions(size_t* max) {
}
size_t max_sessions;
OEMCryptoResult status;
M_TIME(
status = OEMCrypto_GetMaxNumberOfSessions(
requested_security_level_,
&max_sessions),
metrics_,
oemcrypto_get_max_number_of_sessions_,
status,
requested_security_level_);
OEMCryptoResult status = OEMCrypto_GetMaxNumberOfSessions(
requested_security_level_, &max_sessions);
if (OEMCrypto_SUCCESS != status) {
LOGW("OEMCrypto_GetMaxNumberOfSessions fails with %d", status);
metrics_->oemcrypto_max_number_of_sessions_.SetError(status);
return false;
}
metrics_->oemcrypto_max_number_of_sessions_.Record(max_sessions);
*max = max_sessions;
return true;
}
@@ -2793,7 +2683,8 @@ CdmResponseType CryptoSession::CopyOldUsageEntry(
}
CdmResponseType CryptoSession::AddSubSession(
const std::string& sub_session_key_id) {
const std::string& sub_session_key_id,
const std::string& group_master_key_id) {
size_t exists = sub_license_oec_sessions_.count(sub_session_key_id);
if (exists > 0) {
// TODO(jfore): Should this be an error if the key exists? If so add a new
@@ -2815,15 +2706,26 @@ CdmResponseType CryptoSession::AddSubSession(
return UNKNOWN_ERROR;
}
sts = OEMCrypto_LoadDeviceRSAKey(
sid, reinterpret_cast<const uint8_t*>(wrapped_key_.data()),
wrapped_key_.size());
M_TIME(
sts = OEMCrypto_LoadDeviceRSAKey(
sid,
reinterpret_cast<const uint8_t*>(wrapped_key_.data()),
wrapped_key_.size()),
metrics_,
oemcrypto_load_device_rsa_key_,
sts);
if (OEMCrypto_SUCCESS != sts) {
LOGE("LoadDeviceRSAKey failed: %d", sts);
return NEED_PROVISIONING;
}
sub_license_oec_sessions_[sub_session_key_id] = sid;
if (key_session_->Type() != KeySession::kSubLicense) {
key_session_.reset(
new SubLicenseKeySession(sub_license_oec_sessions_, metrics_,
wrapped_key_, requested_security_level_));
wrapped_key_, requested_security_level_,
group_master_key_id));
}
return NO_ERROR;
}
@@ -2932,7 +2834,6 @@ OEMCryptoResult CryptoSession::CopyBufferInChunks(
metrics_,
oemcrypto_copy_buffer_,
sts,
requested_security_level_,
metrics::Pow2Bucket(chunk_size));
if (sts != OEMCrypto_SUCCESS) {

View File

@@ -589,4 +589,19 @@ std::vector<std::string> InitializationData::ExtractKeyFormatVersions(
return versions;
}
// Extract the key id of the group master key used to generate sublicense data.
// Returns an empty string if not defined.
const std::string InitializationData::ExtractGroupMasterKeyId() const {
if (!is_cenc_) {
return "";
}
WidevinePsshData cenc_header;
if (!cenc_header.ParseFromString(data_)) {
return "";
}
return cenc_header.group_master_key_id();
}
} // namespace wvcdm

View File

@@ -316,8 +316,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
std::string serialized_license_req;
license_request.SerializeToString(&serialized_license_req);
if (Properties::use_certificates_as_identification())
key_request_ = serialized_license_req;
key_request_ = serialized_license_req;
// Derive signing and encryption keys and construct signature.
std::string license_request_signature;
@@ -514,15 +513,13 @@ CdmResponseType CdmLicense::HandleKeyResponse(
return LICENSE_RESPONSE_PARSE_ERROR_1;
}
if (Properties::use_certificates_as_identification()) {
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::HandleKeyResponse: no session keys present");
return SESSION_KEYS_NOT_FOUND;
}
if (!crypto_session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
return GENERATE_DERIVED_KEYS_ERROR;
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::HandleKeyResponse: no session keys present");
return SESSION_KEYS_NOT_FOUND;
}
if (!crypto_session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
return GENERATE_DERIVED_KEYS_ERROR;
// Extract mac key
std::string mac_key_iv;
@@ -683,10 +680,19 @@ CdmResponseType CdmLicense::HandleSubLicense(
if (!keyc.ParseFromString(sm.msg())) {
return LICENSE_REQUEST_INVALID_SUBLICENSE;
}
size_t length;
std::vector<CryptoKey> keys;
keys.resize(1);
keys[0].set_key_id(keyc.id());
keys[0].set_key_data(keyc.key());
// Strip PKCS#5 padding from sublicense content keys.
// TODO(jfore): Refactor this to use ExtractContentKeys.
if (keyc.key().size() > KEY_SIZE) {
length = keyc.key().size() - KEY_SIZE;
} else {
length = 0;
}
keys[0].set_key_data(keyc.key().substr(0, length));
keys[0].set_key_data_iv(keyc.iv());
keys[0].set_key_control(keyc.key_control().key_control_block());
keys[0].set_key_control_iv(keyc.key_control().iv());
@@ -737,13 +743,7 @@ bool CdmLicense::RestoreOfflineLicense(
return false;
}
if (Properties::use_certificates_as_identification()) {
key_request_ = signed_request.msg();
} else {
if (!crypto_session_->GenerateDerivedKeys(signed_request.msg())) {
return false;
}
}
key_request_ = signed_request.msg();
CdmResponseType sts = HandleKeyResponse(license_response);
@@ -821,13 +821,7 @@ bool CdmLicense::RestoreLicenseForRelease(
return false;
}
if (Properties::use_certificates_as_identification()) {
key_request_ = signed_request.msg();
} else {
if (!crypto_session_->GenerateDerivedKeys(signed_request.msg())) {
return false;
}
}
key_request_ = signed_request.msg();
SignedMessage signed_response;
if (!signed_response.ParseFromString(license_response)) {
@@ -866,19 +860,15 @@ bool CdmLicense::RestoreLicenseForRelease(
if (license.policy().has_always_include_client_id())
renew_with_client_id_ = license.policy().always_include_client_id();
if (Properties::use_certificates_as_identification()) {
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::RestoreLicenseForRelease: no session keys present");
return false;
}
if (!signed_response.has_session_key()) {
LOGE("CdmLicense::RestoreLicenseForRelease: no session keys present");
return false;
}
if (license.id().has_provider_session_token()) {
if (!crypto_session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
return false;
} else {
return KEY_ADDED == HandleKeyResponse(license_response);
}
if (license.id().has_provider_session_token()) {
if (!crypto_session_->GenerateDerivedKeys(key_request_,
signed_response.session_key()))
return false;
}
if (license.policy().has_renewal_server_url())

View File

@@ -768,6 +768,10 @@ message WidevinePsshData {
// Required when using content keys that are embedded in content.
repeated SubLicense sub_licenses = 11;
// Key ID used to identify the group master key License Server is supposed
// to use to generate group license.
optional string group_master_key_id = 12;
}
// Signed device certificate definition.

View File

@@ -217,12 +217,12 @@ typedef OEMCryptoResult (*L1_GetCurrentSRMVersion_t)(uint16_t* version);
typedef OEMCryptoResult (*L1_LoadSRM_t)(const uint8_t* buffer,
size_t buffer_length);
typedef OEMCryptoResult (*L1_RemoveSRM_t)();
typedef OEMCryptoResult (*L1_CreateUsageTableHeader_t)(uint8_t* header_buffer,
size_t* header_buffer_length);
typedef OEMCryptoResult (*L1_CreateUsageTableHeader_t)(
uint8_t* header_buffer, size_t* header_buffer_length);
typedef OEMCryptoResult (*L1_LoadUsageTableHeader_t)(const uint8_t* buffer,
size_t buffer_length);
typedef OEMCryptoResult (*L1_CreateNewUsageEntry_t)(OEMCrypto_SESSION session,
uint32_t *usage_entry_number);
typedef OEMCryptoResult (*L1_CreateNewUsageEntry_t)(
OEMCrypto_SESSION session, uint32_t *usage_entry_number);
typedef OEMCryptoResult (*L1_LoadUsageEntry_t)(OEMCrypto_SESSION session,
uint32_t index,
const uint8_t *buffer,
@@ -235,9 +235,10 @@ typedef OEMCryptoResult (*L1_UpdateUsageEntry_t)(OEMCrypto_SESSION session,
typedef OEMCryptoResult (*L1_DeactivateUsageEntry_t)(OEMCrypto_SESSION session,
const uint8_t* pst,
size_t pst_length);
typedef OEMCryptoResult (*L1_ShrinkUsageTableHeader_t)(uint32_t new_table_size,
uint8_t* header_buffer,
size_t* header_buffer_length);
typedef OEMCryptoResult (*L1_ShrinkUsageTableHeader_t)(
uint32_t new_table_size,
uint8_t* header_buffer,
size_t* header_buffer_length);
typedef OEMCryptoResult (*L1_MoveEntry_t)(OEMCrypto_SESSION session,
uint32_t new_index);
typedef OEMCryptoResult (*L1_CopyOldUsageEntry_t)(OEMCrypto_SESSION session,
@@ -434,7 +435,8 @@ class WatchDog {
}
// Check to see if the failure file was created before that last abort.
void CheckForPreviousFailure(wvcdm::metrics::CryptoMetrics* metrics) {
void CheckForPreviousFailure(
wvcdm::metrics::OemCryptoDynamicAdapterMetrics* metrics) {
wvcdm::FileSystem file_system;
std::string filename = FailureFilename();
if (!file_system.Exists(filename)) return;
@@ -448,10 +450,7 @@ class WatchDog {
if (size == size_read && flag) {
LOGE("Previous L3 Init failed.");
if (metrics == nullptr) return;
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_L3_INITIALIZATION_FAILED);
}
}
@@ -584,15 +583,12 @@ class Adapter {
OEMCryptoResult Initialize() {
/*
* To avoid changing the function signature and function contract - declare
* a one-off metrics group to collect detailed information about how
* oemcrypto was intialized.
*
* TODO(blueeyes): Refactor this to allow Initialize to provide the
* details to the caller or to use the metrics instance provided by
* the caller.
* To avoid changing the function signature and function contract, use a
* reference to a singleton object for the metrics collected from the
* dynamic adapter.
*/
wvcdm::metrics::CryptoMetrics metrics;
wvcdm::metrics::OemCryptoDynamicAdapterMetrics& metrics =
wvcdm::metrics::GetDynamicAdapterMetricsInstance();
level1_ = FunctionPointers(); // start with all null pointers.
level3_ = FunctionPointers(); // start with all null pointers.
@@ -602,29 +598,20 @@ class Adapter {
watcher->StartThread();
OEMCryptoResult result = watcher->WaitForStatusAndCleanUp();
if (Level3_IsInApp()) {
M_RECORD(
&metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics.SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_IN_APP);
return result;
}
if (force_level3()) {
LOGW("Test code. User requested falling back to L3");
M_RECORD(
&metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics.SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_FORCING_L3);
return result;
}
std::string library_name;
if (!wvcdm::Properties::GetOEMCryptoPath(&library_name)) {
LOGW("L1 library not specified. Falling back to L3");
M_RECORD(
&metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics.OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_NO_L1_LIBRARY_PATH);
return result;
}
@@ -632,10 +619,7 @@ class Adapter {
if (level1_library_ == NULL) {
LOGW("Could not load %s. Falling back to L3. %s", library_name.c_str(),
dlerror());
M_RECORD(
&metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics.OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_L1_OPEN_FAILED);
return result;
}
@@ -650,7 +634,7 @@ class Adapter {
return result;
}
bool LoadLevel1(wvcdm::metrics::CryptoMetrics* metrics) {
bool LoadLevel1(wvcdm::metrics::OemCryptoDynamicAdapterMetrics* metrics) {
if (metrics == nullptr) {
return false;
}
@@ -662,37 +646,26 @@ class Adapter {
LOOKUP_ALL(8, APIVersion, OEMCrypto_APIVersion);
LOOKUP_ALL(8, Terminate, OEMCrypto_Terminate);
if (!level1_valid_) {
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_INVALID_L1);
return false;
}
OEMCryptoResult st = level1_.Initialize();
if (st != OEMCrypto_SUCCESS) {
LOGW("Could not initialize L1. Falling Back to L3.");
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INITIALIZE_L1);
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INITIALIZE_L1);
return false;
}
level1_.version = level1_.APIVersion();
M_RECORD(
metrics,
oemcrypto_l1_api_version_,
NO_TIME,
level1_.version,
kMinimumVersion);
metrics->SetL1ApiVersion(level1_.version);
metrics->SetL1MinApiVersion(kMinimumVersion);
if (level1_.version < kMinimumVersion) {
LOGW("liboemcrypto.so is version %d, not %d. Falling Back to L3.",
level1_.version, kMinimumVersion);
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_WRONG_L1_VERSION);
level1_.Terminate();
return false;
@@ -767,10 +740,7 @@ class Adapter {
// If we have a valid keybox, initialization is done. We're good.
if (OEMCrypto_SUCCESS == level1_.IsKeyboxValid()) {
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_KEYBOX);
return true;
}
@@ -779,10 +749,7 @@ class Adapter {
// will have to be caught in the future when provisioning fails.
if (level1_.version > 11 &&
(level1_.GetProvisioningMethod() == OEMCrypto_OEMCertificate)) {
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_PROVISIONING_3_0);
return true;
}
@@ -793,24 +760,8 @@ class Adapter {
// If GetKeyData is not implemented, then the device should only use a
// baked in certificate as identification. We will assume that a device
// with a bad keybox returns a different error code.
if (!wvcdm::Properties::use_certificates_as_identification()) {
// If OEMCrypto does not support a keybox, but the CDM code expects
// one, things will not work well at all. This is not a fatal error
// because we still want to test OEMCrypto in that configuration.
LOGE("OEMCrypto uses cert as identification, but cdm does not!");
LOGE("This will not work on a production device.");
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_CERTIFICATE_MIX);
} else {
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_CERTIFICATE);
}
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_WITH_CERTIFICATE);
return true;
}
wvcdm::FileSystem file_system;
@@ -818,10 +769,7 @@ class Adapter {
if (!wvcdm::Properties::GetFactoryKeyboxPath(&filename)) {
LOGW("Bad Level 1 Keybox. Falling Back to L3.");
level1_.Terminate();
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_BAD_KEYBOX);
return false;
}
@@ -830,11 +778,9 @@ class Adapter {
if (size <= 0 || !file) {
LOGW("Could not open %s. Falling Back to L3.", filename.c_str());
level1_.Terminate();
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_OPEN_FACTORY_KEYBOX);
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_OPEN_FACTORY_KEYBOX);
return false;
}
uint8_t keybox[size];
@@ -844,18 +790,13 @@ class Adapter {
LOGE("Could NOT install keybox from %s. Falling Back to L3.",
filename.c_str());
level1_.Terminate();
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::
OEMCrypto_INITIALIZED_USING_L3_COULD_NOT_INSTALL_KEYBOX);
return false;
}
LOGI("Installed keybox from %s", filename.c_str());
M_RECORD(
metrics,
oemcrypto_initialization_mode_,
NO_TIME,
metrics->OemCryptoDynamicAdapterMetrics::SetInitializationMode(
wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L1_INSTALLED_KEYBOX);
return true;
}

View File

@@ -12,8 +12,8 @@ namespace wvcdm {
bool Properties::oem_crypto_use_secure_buffers_;
bool Properties::oem_crypto_use_fifo_;
bool Properties::oem_crypto_use_userspace_buffers_;
bool Properties::use_certificates_as_identification_;
bool Properties::provisioning_messages_are_binary_;
bool Properties::allow_service_certificate_requests_;
bool Properties::security_level_path_backward_compatibility_support_;
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_;

View File

@@ -334,7 +334,7 @@ class WvCdmEngineTest : public WvCdmEnginePreProvTest {
static void SetUpTestCase() {
// NOTE: Select server configuration
CommonSetup(kContentProtectionStagingServer);
CommonSetup(kContentProtectionUatServer);
}
virtual void SetUp() {

View File

@@ -102,7 +102,8 @@ class MockDeviceFiles : public DeviceFiles {
class MockCryptoSession : public CryptoSession {
public:
MockCryptoSession() : CryptoSession(NULL) { }
MockCryptoSession(metrics::CryptoMetrics* crypto_metrics)
: CryptoSession(crypto_metrics) { }
MOCK_METHOD1(GetClientToken, bool(std::string*));
MOCK_METHOD1(GetProvisioningToken, bool(std::string*));
MOCK_METHOD0(GetPreProvisionTokenType, CdmClientTokenType());
@@ -148,7 +149,7 @@ class CdmSessionTest : public ::testing::Test {
// Inject testing mocks.
license_parser_ = new MockCdmLicense(cdm_session_->session_id());
cdm_session_->set_license_parser(license_parser_);
crypto_session_ = new MockCryptoSession();
crypto_session_ = new MockCryptoSession(&crypto_metrics_);
cdm_session_->set_crypto_session(crypto_session_);
policy_engine_ = new MockPolicyEngine();
cdm_session_->set_policy_engine(policy_engine_);
@@ -165,6 +166,7 @@ class CdmSessionTest : public ::testing::Test {
metrics::SessionMetrics metrics_;
scoped_ptr<CdmSession> cdm_session_;
MockCdmLicense* license_parser_;
metrics::CryptoMetrics crypto_metrics_;
MockCryptoSession* crypto_session_;
MockPolicyEngine* policy_engine_;
MockDeviceFiles* file_handle_;
@@ -194,8 +196,6 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) {
Eq(kEmptyString), Eq(crypto_session_), Eq(policy_engine_)))
.WillOnce(Return(true));
Properties::set_use_certificates_as_identification(true);
ASSERT_EQ(NO_ERROR, cdm_session_->Init(NULL));
}
@@ -223,33 +223,6 @@ TEST_F(CdmSessionTest, InitWithCertificate) {
Eq(kEmptyString), Eq(crypto_session_), Eq(policy_engine_)))
.WillOnce(Return(true));
Properties::set_use_certificates_as_identification(true);
ASSERT_EQ(NO_ERROR, cdm_session_->Init(NULL));
}
TEST_F(CdmSessionTest, InitWithKeybox) {
Sequence crypto_session_seq;
CdmSecurityLevel level = kSecurityLevelL1;
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
.InSequence(crypto_session_seq)
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*crypto_session_, GetSecurityLevel())
.InSequence(crypto_session_seq)
.WillOnce(Return(level));
EXPECT_CALL(*crypto_session_, GetClientToken(NotNull()))
.InSequence(crypto_session_seq)
.WillOnce(DoAll(SetArgPointee<0>(kToken), Return(true)));
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
.WillOnce(Return(kClientTokenKeybox));
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
EXPECT_CALL(*license_parser_,
Init(NULL, Eq(kToken), Eq(kClientTokenKeybox),
Eq(kEmptyString), Eq(crypto_session_), Eq(policy_engine_)))
.WillOnce(Return(true));
Properties::set_use_certificates_as_identification(false);
ASSERT_EQ(NO_ERROR, cdm_session_->Init(NULL));
}
@@ -277,8 +250,6 @@ TEST_F(CdmSessionTest, ReInitFail) {
Eq(kEmptyString), Eq(crypto_session_), Eq(policy_engine_)))
.WillOnce(Return(true));
Properties::set_use_certificates_as_identification(true);
ASSERT_EQ(NO_ERROR, cdm_session_->Init(NULL));
ASSERT_NE(NO_ERROR, cdm_session_->Init(NULL));
}
@@ -287,8 +258,6 @@ TEST_F(CdmSessionTest, InitFailCryptoError) {
EXPECT_CALL(*crypto_session_, Open(Eq(kLevelDefault)))
.WillOnce(Return(UNKNOWN_ERROR));
Properties::set_use_certificates_as_identification(true);
ASSERT_EQ(UNKNOWN_ERROR, cdm_session_->Init(NULL));
}
@@ -308,8 +277,6 @@ TEST_F(CdmSessionTest, InitNeedsProvisioning) {
NotNull(), _))
.WillOnce(Return(false));
Properties::set_use_certificates_as_identification(true);
ASSERT_EQ(NEED_PROVISIONING, cdm_session_->Init(NULL));
}

View File

@@ -197,16 +197,17 @@ const std::string kWrongKeyId =
const ConfigTestEnv::LicenseServerConfiguration license_servers[] = {
{kGooglePlayServer, kGpLicenseServer, "", kGpClientAuth, kGpKeyId,
kGpOfflineKeyId, kCpProductionProvisioningServerUrl, ""},
{kContentProtectionProductionServer, kCpProductionLicenseServer,
kCpProductionServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
kCpProductionProvisioningServerUrl, kCpProductionServiceCertificate},
kGpOfflineKeyId, kCpProductionProvisioningServerUrl, ""},
{kContentProtectionUatServer, kCpUatLicenseServer, kCpUatServiceCertificate,
kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
kCpUatProvisioningServerUrl, kCpUatServiceCertificate},
kCpClientAuth, kCpKeyId, kCpOfflineKeyId, kCpUatProvisioningServerUrl,
kCpUatServiceCertificate},
{kContentProtectionStagingServer, kCpStagingLicenseServer,
kCpStagingServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
kCpStagingProvisioningServerUrl, kCpStagingServiceCertificate},
kCpStagingServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
kCpStagingProvisioningServerUrl, kCpStagingServiceCertificate},
{kContentProtectionProductionServer, kCpProductionLicenseServer,
kCpProductionServiceCertificate, kCpClientAuth, kCpKeyId,
kCpOfflineKeyId, kCpProductionProvisioningServerUrl,
kCpProductionServiceCertificate},
};
} // namespace

View File

@@ -115,7 +115,8 @@ const CryptoSession::SupportedCertificateTypes kDefaultSupportedCertTypes = {
class MockCryptoSession : public CryptoSession {
public:
MockCryptoSession() : CryptoSession(NULL) { }
MockCryptoSession(metrics::CryptoMetrics* crypto_metrics)
: CryptoSession(crypto_metrics) { }
MOCK_METHOD0(IsOpen, bool());
MOCK_METHOD1(GenerateRequestId, bool(std::string*));
MOCK_METHOD1(UsageInformationSupport, bool(bool*));
@@ -170,7 +171,7 @@ class CdmLicenseTest : public ::testing::Test {
: pssh_(pssh) {}
virtual void SetUp() {
clock_ = new MockClock();
crypto_session_ = new MockCryptoSession();
crypto_session_ = new MockCryptoSession(&crypto_metrics_);
init_data_ = new MockInitializationData(CENC_INIT_DATA_FORMAT, pssh_);
policy_engine_ = new MockPolicyEngine(crypto_session_);
@@ -194,6 +195,7 @@ class CdmLicenseTest : public ::testing::Test {
CdmLicense* cdm_license_;
MockClock* clock_;
metrics::CryptoMetrics crypto_metrics_;
MockCryptoSession* crypto_session_;
MockInitializationData* init_data_;
MockPolicyEngine* policy_engine_;
@@ -277,7 +279,6 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
CdmAppParameterMap app_parameters;
CdmKeyMessage signed_request;
Properties::set_use_certificates_as_identification(true);
std::string server_url;
EXPECT_EQ(cdm_license_->PrepareKeyRequest(
*init_data_, kLicenseTypeStreaming, app_parameters,
@@ -411,7 +412,6 @@ TEST_F(SubLicenseTest, VerifySubSessionData) {
crypto_session_, policy_engine_));
CdmAppParameterMap app_parameters;
CdmKeyMessage signed_request;
Properties::set_use_certificates_as_identification(true);
std::string server_url;
EXPECT_EQ(cdm_license_->PrepareKeyRequest(*init_data_, kLicenseTypeStreaming,
app_parameters, &signed_request,

View File

@@ -5,6 +5,7 @@
#include "crypto_session.h"
#include "license.h"
#include "metrics_collections.h"
#include "policy_engine.h"
#include "mock_clock.h"
#include "scoped_ptr.h"
@@ -61,7 +62,8 @@ const int64_t kHdcpInterval = 10;
class HdcpOnlyMockCryptoSession : public CryptoSession {
public:
HdcpOnlyMockCryptoSession() : CryptoSession(NULL) { }
HdcpOnlyMockCryptoSession(metrics::CryptoMetrics* crypto_metrics)
: CryptoSession(crypto_metrics) { }
MOCK_METHOD2(GetHdcpCapabilities, bool(HdcpCapability*, HdcpCapability*));
};
@@ -79,6 +81,11 @@ class MockCdmEventListener : public WvCdmEventListener {
} // namespace
class PolicyEngineConstraintsTest : public Test {
public:
PolicyEngineConstraintsTest() :
crypto_session_(&dummy_metrics_) {
}
protected:
virtual void SetUp() {
current_time_ = 0;
@@ -206,6 +213,7 @@ class PolicyEngineConstraintsTest : public Test {
scoped_ptr<PolicyEngine> policy_engine_;
MockClock* mock_clock_;
int64_t current_time_;
metrics::CryptoMetrics dummy_metrics_;
StrictMock<HdcpOnlyMockCryptoSession> crypto_session_;
StrictMock<MockCdmEventListener> mock_event_listener_;
License license_;

View File

@@ -56,8 +56,8 @@ int64_t ParseInt(const std::string& str) {
class HdcpOnlyMockCryptoSession : public CryptoSession {
public:
HdcpOnlyMockCryptoSession() :
CryptoSession(NULL) {}
HdcpOnlyMockCryptoSession(metrics::CryptoMetrics* metrics) :
CryptoSession(metrics) {}
MOCK_METHOD2(GetHdcpCapabilities, bool(HdcpCapability*, HdcpCapability*));
bool DoRealGetHdcpCapabilities(HdcpCapability* current,
@@ -97,6 +97,9 @@ using ::testing::StrictMock;
using ::testing::UnorderedElementsAre;
class PolicyEngineTest : public ::testing::Test {
public:
PolicyEngineTest() : crypto_session_(&dummy_metrics_) {
}
protected:
virtual void SetUp() {
policy_engine_.reset(
@@ -163,6 +166,7 @@ class PolicyEngineTest : public ::testing::Test {
expected_has_new_usable_key));
}
metrics::CryptoMetrics dummy_metrics_;
NiceMock<HdcpOnlyMockCryptoSession> crypto_session_;
StrictMock<MockCdmEventListener> mock_event_listener_;
MockClock* mock_clock_;

View File

@@ -140,7 +140,8 @@ class MockDeviceFiles : public DeviceFiles {
class MockCryptoSession : public CryptoSession {
public:
MockCryptoSession() : CryptoSession(NULL) {}
MockCryptoSession(metrics::CryptoMetrics* metrics)
: CryptoSession(metrics) {}
MOCK_METHOD1(Open, CdmResponseType(SecurityLevel));
MOCK_METHOD1(LoadUsageTableHeader,
CdmResponseType(const CdmUsageTableHeader&));
@@ -170,7 +171,7 @@ class UsageTableHeaderTest : public ::testing::Test {
virtual void SetUp() {
// UsageTableHeader will take ownership of the pointer
device_files_ = new MockDeviceFiles();
crypto_session_ = new MockCryptoSession();
crypto_session_ = new MockCryptoSession(&crypto_metrics_);
usage_table_header_ = new UsageTableHeader();
// usage_table_header_ object takes ownership of these objects
@@ -196,6 +197,7 @@ class UsageTableHeaderTest : public ::testing::Test {
}
MockDeviceFiles* device_files_;
metrics::CryptoMetrics crypto_metrics_;
MockCryptoSession* crypto_session_;
UsageTableHeader* usage_table_header_;
};