diff --git a/libwvdrmengine/Android.mk b/libwvdrmengine/Android.mk index 7f087bed..2c61f443 100644 --- a/libwvdrmengine/Android.mk +++ b/libwvdrmengine/Android.mk @@ -43,9 +43,6 @@ LOCAL_SHARED_LIBRARIES := \ libwvhidl \ libbinder \ -LOCAL_HEADER_LIBRARIES := \ - libstagefright_foundation_headers - LOCAL_MODULE := android.hardware.drm@1.0-service.widevine LOCAL_INIT_RC := src_hidl/android.hardware.drm@1.0-service.widevine.rc LOCAL_REQUIRED_MODULES := move_widevine_data.sh @@ -66,21 +63,14 @@ include $(CLEAR_VARS) LOCAL_MODULE := libcdm_utils LOCAL_MODULE_CLASS := STATIC_LIBRARIES -LOCAL_PROPRIETARY_MODULE := true -LOCAL_STATIC_LIBRARIES := libcrypto +LOCAL_STATIC_LIBRARIES := libcrypto_static LOCAL_C_INCLUDES := \ vendor/widevine/libwvdrmengine/cdm/core/include \ vendor/widevine/libwvdrmengine/cdm/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ -LOCAL_HEADER_LIBRARIES := \ - libutils_headers \ - -LOCAL_SHARED_LIBRARIES := \ - liblog - SRC_DIR := cdm/src CORE_SRC_DIR := cdm/core/src LOCAL_SRC_FILES := \ @@ -104,10 +94,8 @@ include $(CLEAR_VARS) LOCAL_MODULE := libcdm_protos LOCAL_MODULE_CLASS := STATIC_LIBRARIES -LOCAL_PROPRIETARY_MODULE := true -CORE_PROTO_SRC_FILES := $(call all-proto-files-under, cdm/core/src) -LOCAL_SRC_FILES := $(CORE_PROTO_SRC_FILES) $(METRICS_PROTO_SRC_FILES) +LOCAL_SRC_FILES := $(call all-proto-files-under, cdm/core/src) generated_sources_dir := $(call local-generated-sources-dir) @@ -170,7 +158,7 @@ LOCAL_STATIC_LIBRARIES := \ libcdm \ libcdm_protos \ libcdm_utils \ - libcrypto \ + libcrypto_static \ libjsmn \ libwvdrmcryptoplugin \ libwvdrmdrmplugin \ @@ -184,10 +172,6 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright_foundation \ libutils \ -LOCAL_HEADER_LIBRARIES := \ - libutils_headers \ - libstagefright_headers - LOCAL_MODULE := libwvdrmengine LOCAL_MODULE_RELATIVE_PATH := mediadrm @@ -230,7 +214,7 @@ LOCAL_STATIC_LIBRARIES := \ libcdm \ libcdm_protos \ libcdm_utils \ - libcrypto \ + libcrypto_static \ libjsmn \ libwvdrmcryptoplugin_hidl \ libwvdrmdrmplugin_hidl \ diff --git a/libwvdrmengine/cdm/core/include/cdm_engine.h b/libwvdrmengine/cdm/core/include/cdm_engine.h index 67e5b29f..11236435 100644 --- a/libwvdrmengine/cdm/core/include/cdm_engine.h +++ b/libwvdrmengine/cdm/core/include/cdm_engine.h @@ -104,7 +104,26 @@ class CdmEngine { const CdmSessionId& session_id, const CdmKeySetId& key_set_id, const InitializationData& init_data, const CdmLicenseType license_type, CdmAppParameterMap& app_parameters, CdmKeyRequest* key_request); - // Accept license response and extract key info. + // This API may + // (a) accept license response, extract key info and load keys. + // (b) accept a renewal response and update license policy information. + // (c) accept a release response and release an offline license or secure + // stop. + // (d) accept a service certificate and cache that information for the + // the lifetime of the session. + // + // |session_id| identifies the session that generated the request and can + // process the response. Should be empty if a release response. + // |key_data| is the license, renewal, release response or service + // certificate response. + // |key_set_id| should be non-null and specified if license release. + // If offline license or streaming license associated with + // a secure stop, |key_set_id| should be non-null and will + // be filled in on return. Use the |key_set_id| with + // RestoreKeys (to reload offline session) or + // GenerateKeyRequest (to release offline session/secure stop). + // |key_set_id| will be cleared if release or streaming + // (not associated with a secure stop). virtual CdmResponseType AddKey(const CdmSessionId& session_id, const CdmKeyResponse& key_data, CdmKeySetId* key_set_id); diff --git a/libwvdrmengine/cdm/core/include/cdm_session.h b/libwvdrmengine/cdm/core/include/cdm_session.h index 6dbb0423..ca269fd8 100644 --- a/libwvdrmengine/cdm/core/include/cdm_session.h +++ b/libwvdrmengine/cdm/core/include/cdm_session.h @@ -87,8 +87,7 @@ class CdmSession { // ReleaseKey() - Accept response and release key. virtual CdmResponseType ReleaseKey(const CdmKeyResponse& key_response); - virtual CdmResponseType DeleteUsageEntry( - const DeviceFiles::CdmUsageData& usage_data); + virtual CdmResponseType DeleteUsageEntry(uint32_t usage_entry_number); virtual bool IsKeyLoaded(const KeyId& key_id); virtual int64_t GetDurationRemaining(); @@ -122,6 +121,10 @@ class CdmSession { virtual bool is_offline() { return is_offline_; } virtual bool is_temporary() { return is_temporary_; } virtual bool license_received() { return license_received_; } + virtual bool has_provider_session_token() { + return (license_parser_.get() != NULL && + license_parser_->provider_session_token().size() > 0); + } virtual CdmUsageSupportType get_usage_support_type() { return usage_support_type_; } diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index 0224c0c0..1cae7170 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -17,6 +17,8 @@ namespace wvcdm { class CryptoKey; +class UsageTableHeader; + typedef std::map CryptoKeyMap; class CryptoSession { @@ -145,6 +147,9 @@ class CryptoSession { const std::string& signature); // Usage table header and usage entry related methods + virtual UsageTableHeader* GetUsageTableHeader() { + return usage_table_header_; + } virtual CdmResponseType GetUsageSupportType(CdmUsageSupportType* type); virtual CdmResponseType CreateUsageTableHeader( CdmUsageTableHeader* usage_table_header); @@ -230,7 +235,11 @@ class CryptoSession { KeyId cached_key_id_; + bool is_usage_support_type_valid_; CdmUsageSupportType usage_support_type_; + UsageTableHeader* usage_table_header_; + static UsageTableHeader* usage_table_header_l1_; + static UsageTableHeader* usage_table_header_l3_; uint64_t request_id_base_; static uint64_t request_id_index_; diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index 2694335d..5bae53e4 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -21,6 +21,7 @@ class Clock; class CryptoSession; class PolicyEngine; class ServiceCertificate; +class CdmSession; class CdmLicense { public: @@ -38,7 +39,8 @@ class CdmLicense { std::string* server_url); virtual CdmResponseType PrepareKeyUpdateRequest( bool is_renewal, const CdmAppParameterMap& app_parameters, - CdmKeyMessage* signed_request, std::string* server_url); + CdmSession* cdm_session, CdmKeyMessage* signed_request, + std::string* server_url); virtual CdmResponseType HandleKeyResponse( const CdmKeyResponse& license_response); virtual CdmResponseType HandleKeyUpdateResponse( diff --git a/libwvdrmengine/cdm/core/include/usage_table_header.h b/libwvdrmengine/cdm/core/include/usage_table_header.h index 436eadfb..5fb703e9 100644 --- a/libwvdrmengine/cdm/core/include/usage_table_header.h +++ b/libwvdrmengine/cdm/core/include/usage_table_header.h @@ -7,6 +7,7 @@ #include #include "device_files.h" +#include "file_store.h" #include "lock.h" #include "metrics_group.h" #include "scoped_ptr.h" @@ -15,28 +16,40 @@ namespace wvcdm { -class FileSystem; class CryptoSession; -// The UsageTableHeader class is a singleton that CDM sessions will share. -// A separate object will be created for each security level. -// The class synchronizes access to usage table header and associated -// data-structures and controls when they are read in or written out to -// non-secure persistent storage. +// Offline licenses/secure stops may be securely tracked using usage +// tables (OEMCrypto v9-12) or usage table headers+usage entries +// (OEMCrypto v13+). This class assists with the latter, synchronizing +// access to usage table header and associated data-structures and controlling +// when they are read in or written out to non-secure persistent storage. +// +// Each OEMCrypto (for each security level) will maintain its own usage table +// header. Each license will have an associated usage entry that is also +// stored in persistent memory and is noted in the usage table header. +// Usage entry information will be verified when licenses are loaded. +// +// OEMCrypto for each security level have their own usage table +// headers. They are loaded on initialization and written out periodically. +// The lifecycle of this class is tied to when OEMCrypto is +// initialized/terminated. +// +// Sessions and licenses are however handled by CdmSession and so most +// calls to maniplate the usage table header related to usage entries +// are by CdmSession. +// // Upgrades from a fixed size usage table (supported by previous // versions of the OEMCrypto API v9-12) are handled by this class. -// |usage_entry| and |usage_entry_number| need to be saved in the license +// |usage_entry| and |usage_entry_number|s need to be saved in the license // and usage info records by the caller. class UsageTableHeader { public: - // This methods instantiates or retrieves a usage table header singleton of - // appropriate security level as specified by the |crypto_session| - // object. + UsageTableHeader(); + virtual ~UsageTableHeader() {} + // |crypto_session| is used to create or load a usage master table and // not cached beyound this call. - static UsageTableHeader* GetInstance(FileSystem* file_system, - CryptoSession* crypto_session_); - virtual ~UsageTableHeader() {} + bool Init(CdmSecurityLevel security_level, CryptoSession* crypto_session); // |persistent_license| false indicates usage info record CdmResponseType AddEntry(CryptoSession* crypto_session, @@ -53,56 +66,67 @@ class UsageTableHeader { // The licenses or usage info records specified by |usage_entry_number| // should not be in use by any open CryptoSession objects when calls // to DeleteEntry and MoveEntry are made. - CdmResponseType DeleteEntry(uint32_t usage_entry_number); - CdmResponseType MoveEntry(uint32_t from_usage_entry_number, - const CdmUsageEntry& from_usage_entry, - uint32_t to_usage_entry_number); + CdmResponseType DeleteEntry(uint32_t usage_entry_number, DeviceFiles* handle, + metrics::MetricsGroup* metrics); private: - UsageTableHeader(FileSystem* file_system, CryptoSession* crypto_session, - CdmSecurityLevel security_level); + CdmResponseType MoveEntry(uint32_t from /* usage entry number */, + const CdmUsageEntry& from_usage_entry, + uint32_t to /* usage entry number */, + DeviceFiles* handle, + metrics::MetricsGroup* metrics); - CdmResponseType GetEntry(uint32_t usage_entry_number, + CdmResponseType GetEntry(uint32_t usage_entry_number, DeviceFiles* handle, CdmUsageEntry* usage_entry); - CdmResponseType StoreEntry(uint32_t usage_entry_number, + CdmResponseType StoreEntry(uint32_t usage_entry_number, DeviceFiles* handle, const CdmUsageEntry& usage_entry); - bool DeleteLastEntry(); + CdmResponseType Shrink(metrics::MetricsGroup* metrics, + uint32_t number_of_usage_entries_to_delete); - CdmResponseType UpgradeFromUsageTable(); - - // Indicates whether one of more license/usage records failed to be upgraded. - bool UpgradeLicensesFromUsageTable(); - bool UpgradeUsageInfoFromUsageTable(); + CdmResponseType UpgradeFromUsageTable(DeviceFiles* handle, + metrics::MetricsGroup* metrics); + bool UpgradeLicensesFromUsageTable(DeviceFiles* handle, + metrics::MetricsGroup* metrics); + bool UpgradeUsageInfoFromUsageTable(DeviceFiles* handle, + metrics::MetricsGroup* metrics); virtual bool is_inited() { return is_inited_; } - SecurityLevel GetSecurityLevel() { - return security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault; - } - - static UsageTableHeader* usage_table_header_l1_; - static UsageTableHeader* usage_table_header_l3_; - + // This handle and file system is only to be used when accessing + // usage_table_header. Usage entries should use the file system provided + // by CdmSession. scoped_ptr file_handle_; + scoped_ptr file_system_; CdmSecurityLevel security_level_; + SecurityLevel requested_security_level_; CdmUsageTableHeader usage_table_header_; std::vector usage_entry_info_; - metrics::MetricsGroup metrics_; - metrics::TimerMetric life_span_; - // Lock to ensure that a single object is created for each security level // and data member to represent whether an object has been correctly // initialized. bool is_inited_; - static Lock initialization_lock_; // Synchonizes access to the Usage Table Header and bookkeeping // data-structures Lock usage_table_header_lock_; + // Test related declarations + friend class UsageTableHeaderTest; + + // These setters are for testing only. Takes ownership of the pointers. + void SetDeviceFiles(DeviceFiles* device_files) { + file_handle_.reset(device_files); + } + void SetCryptoSession(CryptoSession* crypto_session) { + test_crypto_session_.reset(crypto_session); + } + + // Test related data members + scoped_ptr test_crypto_session_; + CORE_DISALLOW_COPY_AND_ASSIGN(UsageTableHeader); }; diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index a5baf1bb..25f49bc2 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -64,6 +64,10 @@ static const std::string QUERY_KEY_MAX_NUMBER_OF_SESSIONS = "MaxNumberOfSessions"; static const std::string QUERY_KEY_OEMCRYPTO_API_VERSION = "OemCryptoApiVersion"; +static const std::string QUERY_KEY_CURRENT_SRM_VERSION = "CurrentSRMVersion"; +static const std::string QUERY_KEY_SRM_UPDATE_SUPPORT = "SRMUpdateSupport"; + // whether OEM supports SRM update +static const std::string QUERY_KEY_WVCDM_VERSION = "WidevineCdmVersion"; static const std::string QUERY_VALUE_TRUE = "True"; static const std::string QUERY_VALUE_FALSE = "False"; diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 4fb0e82d..60923a1b 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -407,13 +407,19 @@ enum CdmUsageSupportType { enum CdmUsageEntryStorageType { kStorageLicense, kStorageUsageInfo, - kStorageUnknown, + kStorageTypeUnknown, }; struct CdmUsageEntryInfo { CdmUsageEntryStorageType storage_type; CdmKeySetId key_set_id; std::string usage_info_file_name; + bool operator==(const CdmUsageEntryInfo& other) const { + return storage_type == other.storage_type && + key_set_id == other.key_set_id && + (storage_type != kStorageUsageInfo || + usage_info_file_name == other.usage_info_file_name); + } }; class CdmKeyAllowedUsage { diff --git a/libwvdrmengine/cdm/core/src/cdm_engine.cpp b/libwvdrmengine/cdm/core/src/cdm_engine.cpp index fe1b428e..9bff5b29 100644 --- a/libwvdrmengine/cdm/core/src/cdm_engine.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_engine.cpp @@ -409,7 +409,12 @@ CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id, CdmResponseType sts = session->AddKey(key_data); if (key_set_id) { - *key_set_id = session->key_set_id(); + if ((session->is_offline() || + session->has_provider_session_token()) && !license_type_release) { + *key_set_id = session->key_set_id(); + } else { + key_set_id->clear(); + } } switch (sts) { @@ -681,6 +686,28 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level, std::ostringstream api_version_stream; api_version_stream << api_version; *query_response = api_version_stream.str(); + } else if (query_token == QUERY_KEY_CURRENT_SRM_VERSION) { + uint16_t current_srm_version; + if (!crypto_session.GetSrmVersion(¤t_srm_version)) { + LOGW("CdmEngine::QueryStatus: GetCurrentSRMVersion failed"); + return UNKNOWN_ERROR; + } + + std::ostringstream current_srm_version_stream; + current_srm_version_stream << current_srm_version; + *query_response = current_srm_version_stream.str(); + } else if (query_token == QUERY_KEY_SRM_UPDATE_SUPPORT) { + bool is_srm_update_supported = crypto_session.IsSrmUpdateSupported(); + *query_response = + is_srm_update_supported ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE; + } else if (query_token == QUERY_KEY_WVCDM_VERSION) { + std::string cdm_version; + if (!Properties::GetWVCdmVersion(&cdm_version)) { + LOGW("CdmEngine::QueryStatus: GetWVCdmVersion failed"); + return UNKNOWN_ERROR; + } + + *query_response = cdm_version; } else { LOGW("CdmEngine::QueryStatus: Unknown status requested, token = %s", query_token.c_str()); @@ -1261,42 +1288,47 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) { usage_session_.reset(new CdmSession(file_system_)); usage_session_->Init(usage_property_set_.get()); - if (usage_session_->get_usage_support_type() == kUsageEntrySupport) { - std::vector usage_data; - if (!handle.RetrieveUsageInfo( - DeviceFiles::GetUsageInfoFileName(app_id), - &usage_data)) { - status = RELEASE_ALL_USAGE_INFO_ERROR_4; - } else { - for (size_t k = 0; k < usage_data.size(); ++k) { - CdmResponseType status2 = - usage_session_->DeleteUsageEntry(usage_data[k]); - if (status == NO_ERROR && status2 != NO_ERROR) - status = status2; + switch (usage_session_->get_usage_support_type()) { + case kUsageEntrySupport: { + std::vector usage_data; + if (!handle.RetrieveUsageInfo( + DeviceFiles::GetUsageInfoFileName(app_id), &usage_data)) { + status = RELEASE_ALL_USAGE_INFO_ERROR_4; + } else { + for (size_t k = 0; k < usage_data.size(); ++k) { + CdmResponseType status2 = usage_session_->DeleteUsageEntry( + usage_data[k].usage_entry_number); + if (status == NO_ERROR && status2 != NO_ERROR) + status = status2; + } } - } - std::vector provider_session_tokens; - if (!handle.DeleteAllUsageInfoForApp( - DeviceFiles::GetUsageInfoFileName(app_id), - &provider_session_tokens)) { - status = RELEASE_ALL_USAGE_INFO_ERROR_5; - } - } else if (usage_session_->get_usage_support_type() - == kUsageTableSupport) { - std::vector provider_session_tokens; - if (!handle.DeleteAllUsageInfoForApp( - DeviceFiles::GetUsageInfoFileName(app_id), - &provider_session_tokens)) { - LOGE("CdmEngine::ReleaseAllUsageInfo: failed to delete L%d secure" - "stops", j); - status = RELEASE_ALL_USAGE_INFO_ERROR_1; - } else { - CdmResponseType status2 = usage_session_-> - DeleteMultipleUsageInformation(provider_session_tokens); - if (status2 != NO_ERROR) { - status = status2; + + std::vector provider_session_tokens; + if (!handle.DeleteAllUsageInfoForApp( + DeviceFiles::GetUsageInfoFileName(app_id), + &provider_session_tokens)) { + status = RELEASE_ALL_USAGE_INFO_ERROR_5; } + break; } + case kUsageTableSupport: { + std::vector provider_session_tokens; + if (!handle.DeleteAllUsageInfoForApp( + DeviceFiles::GetUsageInfoFileName(app_id), + &provider_session_tokens)) { + LOGE("CdmEngine::ReleaseAllUsageInfo: failed to delete %d secure" + "stops", j); + status = RELEASE_ALL_USAGE_INFO_ERROR_1; + } else { + CdmResponseType status2 = usage_session_-> + DeleteMultipleUsageInformation(provider_session_tokens); + if (status2 != NO_ERROR) status = status2; + } + break; + } + default: + // Ignore + break; } } else { LOGE("CdmEngine::ReleaseAllUsageInfo: failed to initialize L%d device" @@ -1611,25 +1643,25 @@ void CdmEngine::OnTimerEvent() { for (CdmSessionList::iterator iter = sessions.begin(); iter != sessions.end(); ++iter) { (*iter)->reset_usage_flags(); - if ((*iter)->get_usage_support_type() == kUsageEntrySupport) - (*iter)->UpdateUsageEntryInformation(); - - if (!has_usage_been_updated) { - // usage is updated for all sessions so this needs to be - // called only once per update usage information period - if ((*iter)->get_usage_support_type() == kUsageTableSupport) { - CdmResponseType status; - M_TIME( - status = (*iter)->UpdateUsageTableInformation(), - (*iter)->GetMetrics(), - crypto_session_update_usage_information_, - status); - if (NO_ERROR != status) { - LOGW("Update usage information failed: %d", status); - } else { - has_usage_been_updated = true; + switch ((*iter)->get_usage_support_type()) { + case kUsageEntrySupport: + (*iter)->UpdateUsageEntryInformation(); + break; + case kUsageTableSupport: + if (!has_usage_been_updated) { + // usage is updated for all sessions so this needs to be + // called only once per update usage information period + CdmResponseType status = (*iter)->UpdateUsageTableInformation(); + if (NO_ERROR != status) { + LOGW("Update usage information failed: %d", status); + } else { + has_usage_been_updated = true; + } } - } + break; + default: + // Ignore + break; } } } diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index e51c9d55..d9a3190f 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -45,15 +45,6 @@ CdmSession::CdmSession(FileSystem* file_system) : usage_entry_number_(0), mock_license_parser_in_use_(false), mock_policy_engine_in_use_(false) { - CdmResponseType sts = - crypto_session_->GetUsageSupportType(&usage_support_type_); - - if (sts != NO_ERROR) { - LOGW("CdmSession::CdmSession: Failed to get usage support type"); - } - if (usage_support_type_ == kUsageEntrySupport) - usage_table_header_ = UsageTableHeader::GetInstance(file_system, - crypto_session_.get()); life_span_.Start(); } @@ -106,6 +97,13 @@ CdmResponseType CdmSession::Init( return SESSION_FILE_HANDLE_INIT_ERROR; } + if (crypto_session_->GetUsageSupportType(&usage_support_type_) == NO_ERROR) { + if (usage_support_type_ == kUsageEntrySupport) + usage_table_header_ = crypto_session_->GetUsageTableHeader(); + } else { + usage_support_type_ = kNonSecureUsageSupport; + } + // Device Provisioning state is not yet known. // If not using certificates, then Keybox is client token for license // requests. @@ -195,6 +193,9 @@ CdmResponseType CdmSession::Init( CdmResponseType CdmSession::RestoreOfflineSession( const CdmKeySetId& key_set_id, const CdmLicenseType license_type) { + if (!key_set_id_.empty()) { + file_handle_->UnreserveLicenseId(key_set_id_); + } key_set_id_ = key_set_id; DeviceFiles::LicenseState license_state; @@ -430,7 +431,8 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) { !provider_session_token.empty()) { if (sts != KEY_ADDED) { CdmResponseType sts = - usage_table_header_->DeleteEntry(usage_entry_number_); + usage_table_header_->DeleteEntry(usage_entry_number_, + file_handle_.get(), &metrics_); if (sts != NO_ERROR) { LOGW("CdmSession::AddKey: Delete usage entry failed = %d", sts); } @@ -446,7 +448,7 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) { license_parser_->provider_session_token().size(), license_parser_->provider_session_token().c_str()); - if (is_offline_ || !license_parser_->provider_session_token().empty()) { + if (is_offline_ || has_provider_session_token()) { if (usage_support_type_ == kUsageEntrySupport) usage_table_header_->UpdateEntry(crypto_session_.get(), &usage_entry_); @@ -556,8 +558,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) { } has_decrypted_since_last_report_ = true; if (!is_usage_update_needed_) { - is_usage_update_needed_ = - !license_parser_->provider_session_token().empty(); + is_usage_update_needed_ = has_provider_session_token(); } } else { Clock clock; @@ -576,7 +577,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) { CdmResponseType CdmSession::GenerateRenewalRequest( CdmKeyRequest* key_request) { CdmResponseType status = license_parser_->PrepareKeyUpdateRequest( - true, app_parameters_, &key_request->message, &key_request->url); + true, app_parameters_, NULL, &key_request->message, &key_request->url); key_request->type = kKeyRequestTypeRenewal; @@ -606,8 +607,8 @@ CdmResponseType CdmSession::GenerateReleaseRequest( CdmKeyRequest* key_request) { is_release_ = true; CdmResponseType status = license_parser_->PrepareKeyUpdateRequest( - false, app_parameters_, &key_request->message, - &key_request->url); + false, app_parameters_, usage_table_header_ == NULL ? NULL : this, + &key_request->message, &key_request->url); key_request->type = kKeyRequestTypeRelease; @@ -641,38 +642,53 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) { license_parser_->HandleKeyUpdateResponse(false, key_response); if (sts != KEY_ADDED) return (sts == KEY_ERROR) ? RELEASE_KEY_ERROR : sts; - if (is_offline_ || !license_parser_->provider_session_token().empty()) { + if (is_offline_ || has_provider_session_token()) { DeleteLicense(); - // Deletion of usage entry cannot occur while in use by a crypto session. - // So close and reopen after deletion. if (usage_support_type_ == kUsageEntrySupport) { - crypto_session_->Close(); - - CdmResponseType sts = usage_table_header_->DeleteEntry(usage_entry_number_); - if (sts != NO_ERROR) return sts; - - M_TIME( - sts = crypto_session_->Open(requested_security_level_), - &metrics_, - crypto_session_open_, - sts, - requested_security_level_); + sts = DeleteUsageEntry(usage_entry_number_); if (NO_ERROR != sts) return sts; } } return NO_ERROR; } -CdmResponseType CdmSession::DeleteUsageEntry( - const DeviceFiles::CdmUsageData& usage_data) { +CdmResponseType CdmSession::DeleteUsageEntry(uint32_t usage_entry_number) { if (usage_support_type_ != kUsageEntrySupport) { LOGE("CdmSession::DeleteUsageEntry: Unexpected usage type supported: %d", usage_support_type_); return INCORRECT_USAGE_SUPPORT_TYPE_1; } - return usage_table_header_->DeleteEntry(usage_data.usage_entry_number); + // The usage entry cannot be deleted if it has a crypto session handling + // it, so close and reopen session. + CdmResponseType sts; + crypto_session_->Close(); + crypto_session_.reset(new CryptoSession(&metrics_)); + M_TIME( + sts = crypto_session_->Open(requested_security_level_), + &metrics_, + crypto_session_open_, + sts, + requested_security_level_); + if (sts != NO_ERROR) return sts; + + usage_table_header_ = NULL; + if (crypto_session_->GetUsageSupportType(&usage_support_type_) == NO_ERROR) { + if (usage_support_type_ == kUsageEntrySupport) + usage_table_header_ = crypto_session_->GetUsageTableHeader(); + } else { + usage_support_type_ = kNonSecureUsageSupport; + } + + if (usage_table_header_ == NULL) { + LOGE("CdmSession::DeleteUsageEntry: Usage table header unavailable"); + return INCORRECT_USAGE_SUPPORT_TYPE_1; + } + + return usage_table_header_->DeleteEntry(usage_entry_number, + file_handle_.get(), + &metrics_); } bool CdmSession::IsKeyLoaded(const KeyId& key_id) { @@ -775,7 +791,7 @@ CdmResponseType CdmSession::ReleaseCrypto() { } bool CdmSession::DeleteLicense() { - if (!is_offline_ && license_parser_->provider_session_token().empty()) + if (!is_offline_ && !has_provider_session_token()) return false; if (is_offline_) { diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index ebe8e98b..0c6f2e7d 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -17,6 +17,7 @@ #include "properties.h" #include "pst_report.h" #include "string_conversions.h" +#include "usage_table_header.h" #include "wv_cdm_constants.h" namespace { @@ -41,6 +42,8 @@ Lock CryptoSession::crypto_lock_; bool CryptoSession::initialized_ = false; int CryptoSession::session_count_ = 0; uint64_t CryptoSession::request_id_index_ = 0; +UsageTableHeader* CryptoSession::usage_table_header_l1_ = NULL; +UsageTableHeader* CryptoSession::usage_table_header_l3_ = NULL; CryptoSession::CryptoSession(metrics::MetricsGroup* metrics) : metrics_(metrics), @@ -48,7 +51,9 @@ CryptoSession::CryptoSession(metrics::MetricsGroup* metrics) update_usage_table_after_close_session_(false), is_destination_buffer_type_valid_(false), requested_security_level_(kLevelDefault), - usage_support_type_(kUnknownUsageSupport), + is_usage_support_type_valid_(false), + usage_support_type_(kNonSecureUsageSupport), + usage_table_header_(NULL), request_id_base_(0), cipher_mode_(kCipherModeCtr) { Init(); @@ -121,6 +126,16 @@ void CryptoSession::Terminate() { if (OEMCrypto_SUCCESS != sts) { LOGE("OEMCrypto_Terminate failed: %d", sts); } + + if (usage_table_header_l1_ != NULL) { + delete usage_table_header_l1_; + usage_table_header_l1_ = NULL; + } + if (usage_table_header_l3_ != NULL) { + delete usage_table_header_l3_; + usage_table_header_l3_ = NULL; + } + initialized_ = false; } @@ -217,8 +232,7 @@ bool CryptoSession::GetProvisioningToken(std::string* token) { } CdmSecurityLevel CryptoSession::GetSecurityLevel() { - LOGV("CryptoSession::GetSecurityLevel: Lock"); - AutoLock auto_lock(crypto_lock_); + LOGV("CryptoSession::GetSecurityLevel"); if (!initialized_) { return kSecurityLevelUninitialized; } @@ -430,7 +444,8 @@ uint8_t CryptoSession::GetSecurityPatchLevel() { } CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { - LOGV("CryptoSession::Open: Lock"); + LOGV("CryptoSession::Open: Lock: requested_security_level: %d", + requested_security_level); AutoLock auto_lock(crypto_lock_); if (!initialized_) return UNKNOWN_ERROR; if (open_) return NO_ERROR; @@ -470,8 +485,35 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { random_sts, metrics::Pow2Bucket(sizeof(request_id_base_))); ++request_id_index_; + CdmUsageSupportType usage_support_type; - GetUsageSupportType(&usage_support_type); + if (GetUsageSupportType(&usage_support_type) == NO_ERROR) { + if (usage_support_type == kUsageEntrySupport) { + CdmSecurityLevel security_level = GetSecurityLevel(); + if (security_level == kSecurityLevelL1 || + security_level == kSecurityLevelL3) { + UsageTableHeader* header = security_level == kSecurityLevelL1 ? + usage_table_header_l1_ : usage_table_header_l3_; + if (header == NULL) { + header = new UsageTableHeader(); + // Ignore errors since we do not know when a session is opened, + // if it is intended to be used for offline/usage session related + // or otherwise. + if (!header->Init(security_level, this)) { + delete header; + usage_table_header_ = NULL; + return NO_ERROR; + } + if (security_level == kSecurityLevelL1) + usage_table_header_l1_ = header; + else + usage_table_header_l3_ = header; + } + usage_table_header_ = header; + } + } + } + return NO_ERROR; } @@ -1108,6 +1150,11 @@ CdmResponseType CryptoSession::UpdateUsageInformation() { AutoLock auto_lock(crypto_lock_); if (!initialized_) return UNKNOWN_ERROR; + if (usage_table_header_ != NULL) { + LOGV("UpdateUsageInformation: deprecated for OEMCrypto v13+"); + return NO_ERROR; + } + OEMCryptoResult status; M_TIME( status = OEMCrypto_UpdateUsageTable(), @@ -1264,6 +1311,11 @@ CdmResponseType CryptoSession::ReleaseUsageInformation( LOGV("ReleaseUsageInformation: id=%ld", (uint32_t)oec_session_id_); { AutoLock auto_lock(crypto_lock_); + if (usage_table_header_ != NULL) { + LOGW("ReleaseUsageInformation: deprecated for OEMCrypto v13+"); + return NO_ERROR; + } + const uint8_t* msg = reinterpret_cast(message.data()); const uint8_t* sig = reinterpret_cast(signature.data()); const uint8_t* pst = msg + GetOffset(message, provider_session_token); diff --git a/libwvdrmengine/cdm/core/src/device_files.cpp b/libwvdrmengine/cdm/core/src/device_files.cpp index b2534d2b..c9dfa1ae 100644 --- a/libwvdrmengine/cdm/core/src/device_files.cpp +++ b/libwvdrmengine/cdm/core/src/device_files.cpp @@ -858,6 +858,11 @@ bool DeviceFiles::ListUsageInfoFiles( return false; } + if (usage_info_file_names == NULL) { + LOGW("DeviceFiles::ListUsageInfoFiles: usage_info_file_names not provided"); + return false; + } + // Get list of filenames std::vector filenames; if (!ListFiles(&filenames)) { @@ -982,7 +987,7 @@ bool DeviceFiles::StoreUsageTableInfo( const CdmUsageTableHeader& usage_table_header, const std::vector& usage_entry_info) { if (!initialized_) { - LOGW("DeviceFiles::StoreUsageTableHeader: not initialized"); + LOGW("DeviceFiles::StoreUsageTableInfo: not initialized"); return false; } @@ -1009,7 +1014,7 @@ bool DeviceFiles::StoreUsageTableInfo( info->set_usage_info_file_name( usage_entry_info[i].usage_info_file_name); break; - case kStorageUnknown: + case kStorageTypeUnknown: default: info->set_storage( UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN); @@ -1081,7 +1086,7 @@ bool DeviceFiles::RetrieveUsageTableInfo( break; case UsageTableInfo_UsageEntryInfo_UsageEntryStorage_UNKNOWN: default: - (*usage_entry_info)[i].storage_type = kStorageUnknown; + (*usage_entry_info)[i].storage_type = kStorageTypeUnknown; break; } } diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 9ed06a8d..3143c098 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -7,6 +7,7 @@ #include #include "clock.h" +#include "cdm_session.h" #include "crypto_key.h" #include "crypto_session.h" #include "device_files.h" @@ -274,7 +275,8 @@ CdmResponseType CdmLicense::PrepareKeyRequest( CdmResponseType CdmLicense::PrepareKeyUpdateRequest( bool is_renewal, const CdmAppParameterMap& app_parameters, - CdmKeyMessage* signed_request, std::string* server_url) { + CdmSession* cdm_session, CdmKeyMessage* signed_request, + std::string* server_url) { if (!initialized_) { LOGE("CdmLicense::PrepareKeyUpdateRequest: not initialized"); return LICENSE_PARSER_NOT_INITIALIZED_1; @@ -330,6 +332,12 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest( if (NO_ERROR != status) return status; } + // TODO(rfrias): Refactor to avoid needing to call CdmSession + if (cdm_session) { + CdmResponseType status = cdm_session->UpdateUsageEntryInformation(); + if (NO_ERROR != status) return status; + } + std::string usage_report; CdmResponseType status = crypto_session_->GenerateUsageReport( provider_session_token_, &usage_report, &usage_duration_status, diff --git a/libwvdrmengine/cdm/core/src/privacy_crypto_openssl.cpp b/libwvdrmengine/cdm/core/src/privacy_crypto_openssl.cpp index c489cb25..d5d85df5 100644 --- a/libwvdrmengine/cdm/core/src/privacy_crypto_openssl.cpp +++ b/libwvdrmengine/cdm/core/src/privacy_crypto_openssl.cpp @@ -29,14 +29,15 @@ RSA* GetKey(const std::string& serialized_key) { 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)); + BIO_free(bio); return NULL; } + BIO_free(bio); return key; } diff --git a/libwvdrmengine/cdm/core/src/usage_table_header.cpp b/libwvdrmengine/cdm/core/src/usage_table_header.cpp index 8eb1a81a..8a82244c 100644 --- a/libwvdrmengine/cdm/core/src/usage_table_header.cpp +++ b/libwvdrmengine/cdm/core/src/usage_table_header.cpp @@ -5,6 +5,7 @@ #include "crypto_session.h" #include "license.h" #include "log.h" +#include "metrics_group.h" namespace { std::string kEmptyString; @@ -12,78 +13,65 @@ std::string kEmptyString; namespace wvcdm { -UsageTableHeader* UsageTableHeader::usage_table_header_l1_ = NULL; -UsageTableHeader* UsageTableHeader::usage_table_header_l3_ = NULL; - -Lock UsageTableHeader::initialization_lock_; - -UsageTableHeader* UsageTableHeader::GetInstance(FileSystem* file_system, - CryptoSession* crypto_session) { - LOGV("UsageTableHeader::GetInstance"); - AutoLock auto_lock(initialization_lock_); - CdmSecurityLevel security_level = crypto_session->GetSecurityLevel(); - switch (security_level) { - case kSecurityLevelL1: - if (usage_table_header_l1_ != NULL) - return usage_table_header_l1_; - break; - case kSecurityLevelL3: - if (usage_table_header_l3_ != NULL) - return usage_table_header_l3_; - break; - default: - LOGE("UsageTableHeader::GetInstance: unsupported security level: %d", - security_level); - return NULL; - } - - UsageTableHeader* header = - new UsageTableHeader(file_system, crypto_session, security_level); - if (!header->is_inited()) { - delete header; - return NULL; - } - - if (security_level == kSecurityLevelL1) - usage_table_header_l1_ = header; - else - usage_table_header_l3_ = header; - return header; +UsageTableHeader::UsageTableHeader() + : security_level_(kSecurityLevelUninitialized), + requested_security_level_(kLevelDefault), + is_inited_(false) { + file_handle_.reset(new DeviceFiles(file_system_.get())); } -UsageTableHeader::UsageTableHeader(FileSystem* file_system, - CryptoSession* crypto_session, - CdmSecurityLevel security_level) - : file_handle_(new DeviceFiles(file_system)), - security_level_(security_level), - is_inited_(false) { - LOGV("UsageTableHeader::UsageTablerHeader: security level: %d", - security_level); +bool UsageTableHeader::Init(CdmSecurityLevel security_level, + CryptoSession* crypto_session) { + LOGV("UsageTableHeader::Init: security level: %d", security_level); + if (crypto_session == NULL) { + LOGE("UsageTableHeader::Init: no crypto session provided"); + return false; + } + + switch (security_level) { + case kSecurityLevelL1: + case kSecurityLevelL3: + break; + default: + LOGE("UsageTableHeader::Init: invalid security level provided: %d", + security_level); + return false; + } + + security_level_ = security_level; + + if (!file_handle_->Init(security_level)) { + LOGE("UsageTableHeader::Init: device files initialization failed"); + return false; + } if (!file_handle_->RetrieveUsageTableInfo(&usage_table_header_, &usage_entry_info_)) { CdmResponseType status = crypto_session->CreateUsageTableHeader(&usage_table_header_); - if (status != NO_ERROR) return; + if (status != NO_ERROR) return false; + file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_); } else { CdmResponseType status = crypto_session->LoadUsageTableHeader(usage_table_header_); if (status != NO_ERROR) { LOGE( - "UsageTableHeader::UsageTablerHeader: load usage table failed, " - "security level: %d", + "UsageTableHeader::Init: load usage table failed, security level: %d", security_level); - return; + return false; } } + requested_security_level_ = + security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault; is_inited_ = true; + return true; } CdmResponseType UsageTableHeader::AddEntry( CryptoSession* crypto_session, bool persistent_license, const CdmKeySetId& key_set_id, const std::string& usage_info_file_name, uint32_t* usage_entry_number) { - LOGV("UsageTableHeader::AddEntry"); + LOGV("UsageTableHeader::AddEntry: Lock"); AutoLock auto_lock(usage_table_header_lock_); CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number); @@ -101,7 +89,7 @@ CdmResponseType UsageTableHeader::AddEntry( size_t number_of_entries = usage_entry_info_.size(); usage_entry_info_.resize(*usage_entry_number + 1); for (size_t i = number_of_entries; i < usage_entry_info_.size() - 1; ++i) { - usage_entry_info_[i].storage_type = kStorageUnknown; + usage_entry_info_[i].storage_type = kStorageTypeUnknown; usage_entry_info_[i].key_set_id.clear(); usage_entry_info_[i].usage_info_file_name.clear(); } @@ -120,15 +108,17 @@ CdmResponseType UsageTableHeader::AddEntry( return NO_ERROR; } -CdmResponseType UsageTableHeader::LoadEntry( - CryptoSession* crypto_session, const CdmUsageEntry& usage_entry, - uint32_t usage_entry_number) { - LOGV("UsageTableHeader::LoadEntry"); +CdmResponseType UsageTableHeader::LoadEntry(CryptoSession* crypto_session, + const CdmUsageEntry& usage_entry, + uint32_t usage_entry_number) { + LOGV("UsageTableHeader::LoadEntry: Lock"); AutoLock auto_lock(usage_table_header_lock_); if (usage_entry_number >= usage_entry_info_.size()) { - LOGE("UsageTableHeader::LoadEntry: usage entry number %d larger than table size: %d", - usage_entry_number, usage_entry_info_.size()); + LOGE( + "UsageTableHeader::LoadEntry: usage entry number %d larger than table " + "size: %d", + usage_entry_number, usage_entry_info_.size()); return USAGE_INVALID_LOAD_ENTRY; } return crypto_session->LoadUsageEntry(usage_entry_number, usage_entry); @@ -136,20 +126,21 @@ CdmResponseType UsageTableHeader::LoadEntry( CdmResponseType UsageTableHeader::UpdateEntry(CryptoSession* crypto_session, CdmUsageEntry* usage_entry) { - LOGV("UsageTableHeader::UpdateEntry"); + LOGV("UsageTableHeader::UpdateEntryL: Lock"); AutoLock auto_lock(usage_table_header_lock_); - CdmUsageTableHeader usage_table_header; CdmResponseType status = crypto_session->UpdateUsageEntry(&usage_table_header_, usage_entry); if (status != NO_ERROR) return status; - file_handle_->StoreUsageTableInfo(usage_table_header, usage_entry_info_); + file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_); return NO_ERROR; } -CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number) { - LOGV("UsageTableHeader::DeleteEntry"); +CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number, + DeviceFiles* handle, + metrics::MetricsGroup* metrics) { + LOGV("UsageTableHeader::DeleteEntry: Lock"); AutoLock auto_lock(usage_table_header_lock_); if (usage_entry_number >= usage_entry_info_.size()) return USAGE_INVALID_PARAMETERS_1; @@ -159,50 +150,67 @@ CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number) { CdmUsageEntry swap_usage_entry; bool swap_usage_entry_valid = false; - for (; !swap_usage_entry_valid && swap_entry_number > usage_entry_number; - --swap_entry_number) { + while (!swap_usage_entry_valid && swap_entry_number > usage_entry_number) { switch (usage_entry_info_[swap_entry_number].storage_type) { case kStorageLicense: case kStorageUsageInfo: { - CdmResponseType status = GetEntry(swap_entry_number, &swap_usage_entry); + CdmResponseType status = + GetEntry(swap_entry_number, handle, &swap_usage_entry); if (status == NO_ERROR) swap_usage_entry_valid = true; break; } - case kStorageUnknown: + case kStorageTypeUnknown: default: break; } + if (!swap_usage_entry_valid) --swap_entry_number; } - uint32_t new_usage_table_size = 0; + uint32_t number_of_entries_to_be_deleted = + usage_entry_info_.size() - usage_entry_number; if (swap_usage_entry_valid) { - MoveEntry(swap_entry_number, swap_usage_entry, usage_entry_number); - new_usage_table_size = swap_entry_number; - } else { - // No valid usage entries before entry to be deleted - new_usage_table_size = usage_entry_number; + CdmResponseType status = MoveEntry(swap_entry_number, swap_usage_entry, + usage_entry_number, handle, metrics); + // If unable to move entry, unset storage type of entry to be deleted and + // resize |usage_entry_info_| so that swap usage entry is the last entry. + if (status != NO_ERROR) { + usage_entry_info_[usage_entry_number].storage_type = kStorageTypeUnknown; + usage_entry_info_[usage_entry_number].key_set_id.clear(); + if (usage_entry_info_.size() - 1 == swap_entry_number) { + file_handle_->StoreUsageTableInfo(usage_table_header_, + usage_entry_info_); + } else { + Shrink(metrics, usage_entry_info_.size() - swap_entry_number - 1); + } + return NO_ERROR; + } + number_of_entries_to_be_deleted = + usage_entry_info_.size() - swap_entry_number; } - usage_entry_info_.resize(new_usage_table_size); - CryptoSession crypto_session(&metrics_); - crypto_session.Open(GetSecurityLevel()); - crypto_session.ShrinkUsageTableHeader(new_usage_table_size, - &usage_table_header_); - file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_); - return NO_ERROR; + + return Shrink(metrics, number_of_entries_to_be_deleted); } CdmResponseType UsageTableHeader::MoveEntry( uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry, - uint32_t to_usage_entry_number) { + uint32_t to_usage_entry_number, DeviceFiles* handle, + metrics::MetricsGroup* metrics) { LOGV("UsageTableHeader::MoveEntry"); - AutoLock auto_lock(usage_table_header_lock_); - CryptoSession crypto_session(&metrics_); - crypto_session.Open(GetSecurityLevel()); + // crypto_session points to an object whose scope is this method or a test + // object whose scope is the lifetime of this class + scoped_ptr scoped_crypto_session; + CryptoSession* crypto_session = test_crypto_session_.get(); + if (crypto_session == NULL) { + scoped_crypto_session.reset((new CryptoSession(metrics))); + crypto_session = scoped_crypto_session.get(); + } + + crypto_session->Open(requested_security_level_); CdmResponseType status = - crypto_session.LoadUsageEntry(from_usage_entry_number, from_usage_entry); + crypto_session->LoadUsageEntry(from_usage_entry_number, from_usage_entry); if (status != NO_ERROR) { LOGE("UsageTableHeader::MoveEntry: Failed to load usage entry: %d", @@ -210,7 +218,7 @@ CdmResponseType UsageTableHeader::MoveEntry( return status; } - status = crypto_session.MoveUsageEntry(to_usage_entry_number); + status = crypto_session->MoveUsageEntry(to_usage_entry_number); if (status != NO_ERROR) { LOGE("UsageTableHeader::MoveEntry: Failed to move usage entry: %d->%d", @@ -222,7 +230,7 @@ CdmResponseType UsageTableHeader::MoveEntry( usage_entry_info_[from_usage_entry_number]; CdmUsageEntry usage_entry; - status = crypto_session.UpdateUsageEntry(&usage_table_header_, &usage_entry); + status = crypto_session->UpdateUsageEntry(&usage_table_header_, &usage_entry); if (status != NO_ERROR) { LOGE("UsageTableHeader::MoveEntry: Failed to update usage entry: %d", @@ -232,12 +240,13 @@ CdmResponseType UsageTableHeader::MoveEntry( file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_); - StoreEntry(to_usage_entry_number, usage_entry); + StoreEntry(to_usage_entry_number, handle, usage_entry); return NO_ERROR; } CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number, + DeviceFiles* handle, CdmUsageEntry* usage_entry) { uint32_t entry_number; switch (usage_entry_info_[usage_entry_number].storage_type) { @@ -247,7 +256,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number, std::string key_renewal_response, release_server_url; int64_t playback_start_time, last_playback_time, grace_period_end_time; CdmAppParameterMap app_parameters; - if (!file_handle_->RetrieveLicense( + if (!handle->RetrieveLicense( usage_entry_info_[usage_entry_number].key_set_id, &license_state, &init_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, @@ -263,7 +272,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number, CdmKeyMessage license_request; CdmKeyResponse license_response; - if (!file_handle_->RetrieveUsageInfoByKeySetId( + if (!handle->RetrieveUsageInfoByKeySetId( usage_entry_info_[usage_entry_number].usage_info_file_name, usage_entry_info_[usage_entry_number].key_set_id, &provider_session_token, &license_request, &license_response, @@ -274,7 +283,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number, } break; } - case kStorageUnknown: + case kStorageTypeUnknown: default: LOGE( "UsageTableHeader::GetEntry: Attempting to retrieve usage " @@ -293,6 +302,7 @@ CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number, } CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, + DeviceFiles* handle, const CdmUsageEntry& usage_entry) { uint32_t entry_number; switch (usage_entry_info_[usage_entry_number].storage_type) { @@ -303,7 +313,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, int64_t playback_start_time, last_playback_time, grace_period_end_time; CdmAppParameterMap app_parameters; CdmUsageEntry entry; - if (!file_handle_->RetrieveLicense( + if (!handle->RetrieveLicense( usage_entry_info_[usage_entry_number].key_set_id, &license_state, &init_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, @@ -312,7 +322,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, LOGE("UsageTableHeader::StoreEntry: Failed to retrieve license"); return USAGE_STORE_ENTRY_RETRIEVE_LICENSE_FAILED; } - if (!file_handle_->StoreLicense( + if (!handle->StoreLicense( usage_entry_info_[usage_entry_number].key_set_id, license_state, init_data, key_request, key_response, key_renewal_request, key_renewal_response, release_server_url, playback_start_time, @@ -327,7 +337,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, CdmUsageEntry entry; std::string provider_session_token, init_data, key_request, key_response, key_renewal_request; - if (!file_handle_->RetrieveUsageInfoByKeySetId( + if (!handle->RetrieveUsageInfoByKeySetId( usage_entry_info_[usage_entry_number].usage_info_file_name, usage_entry_info_[usage_entry_number].key_set_id, &provider_session_token, &key_request, &key_response, &entry, @@ -337,10 +347,10 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, "information"); return USAGE_STORE_ENTRY_RETRIEVE_USAGE_INFO_FAILED; } - file_handle_->DeleteUsageInfo( + handle->DeleteUsageInfo( usage_entry_info_[usage_entry_number].usage_info_file_name, provider_session_token); - if (!file_handle_->StoreUsageInfo( + if (!handle->StoreUsageInfo( provider_session_token, key_request, key_response, usage_entry_info_[usage_entry_number].usage_info_file_name, usage_entry_info_[usage_entry_number].key_set_id, usage_entry, @@ -350,7 +360,7 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, } break; } - case kStorageUnknown: + case kStorageTypeUnknown: default: LOGE( "UsageTableHeader::GetUsageEntry: Attempting to retrieve usage " @@ -361,41 +371,56 @@ CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number, return NO_ERROR; } -bool UsageTableHeader::DeleteLastEntry() { +CdmResponseType UsageTableHeader::Shrink( + metrics::MetricsGroup* metrics, + uint32_t number_of_usage_entries_to_delete) { if (usage_entry_info_.empty()) { - LOGW( - "UsageTableHeader::DeleteLastEntry: usage entry info table " - "unexpectedly empty"); - return false; + LOGE("UsageTableHeader::Shrink: usage entry info table unexpectedly empty"); + return NO_USAGE_ENTRIES; } - usage_entry_info_.resize(usage_entry_info_.size() - 1); + if (usage_entry_info_.size() < number_of_usage_entries_to_delete) { + LOGW( + "UsageTableHeader::Shrink: cannot delete %d entries when usage entry " + "table size is %d", number_of_usage_entries_to_delete, + usage_entry_info_.size()); + return NO_ERROR; + } + + if (number_of_usage_entries_to_delete == 0) return NO_ERROR; + + usage_entry_info_.resize(usage_entry_info_.size() - + number_of_usage_entries_to_delete); + + // crypto_session points to an object whose scope is this method or a test + // object whose scope is the lifetime of this class + scoped_ptr scoped_crypto_session; + CryptoSession* crypto_session = test_crypto_session_.get(); + if (crypto_session == NULL) { + scoped_crypto_session.reset((new CryptoSession(metrics))); + crypto_session = scoped_crypto_session.get(); + } + + CdmResponseType status = crypto_session->Open(requested_security_level_); + if (status != NO_ERROR) return status; + + status = crypto_session->ShrinkUsageTableHeader(usage_entry_info_.size(), + &usage_table_header_); + if (status != NO_ERROR) return status; - CryptoSession crypto_session(&metrics_); - crypto_session.Open(GetSecurityLevel()); - crypto_session.ShrinkUsageTableHeader(usage_entry_info_.size(), - &usage_table_header_); file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_); - return true; -} - -CdmResponseType UsageTableHeader::UpgradeFromUsageTable() { - CryptoSession crypto_session(&metrics_); - CdmResponseType status = crypto_session.Open(GetSecurityLevel()); - - if (status != NO_ERROR) return status; - - status = crypto_session.CreateUsageTableHeader(&usage_table_header_); - if (status != NO_ERROR) return status; - - crypto_session.Close(); - - UpgradeLicensesFromUsageTable(); - UpgradeUsageInfoFromUsageTable(); return NO_ERROR; } -bool UsageTableHeader::UpgradeLicensesFromUsageTable() { +CdmResponseType UsageTableHeader::UpgradeFromUsageTable( + DeviceFiles* handle, metrics::MetricsGroup* metrics) { + UpgradeLicensesFromUsageTable(handle, metrics); + UpgradeUsageInfoFromUsageTable(handle, metrics); + return NO_ERROR; +} + +bool UsageTableHeader::UpgradeLicensesFromUsageTable( + DeviceFiles* handle, metrics::MetricsGroup* metrics) { // Fetch the key set IDs for each offline license. For each license // * retrieve the provider session token, // * create a new usage entry @@ -403,18 +428,14 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() { // * update the usage header table and entry numbers // * save the usage table header and store the usage entry number and // usage entry along with the license to persistent memory - // On errors, continue to the next license, but indicate on return that not - // all licenses may have been upgraded. std::vector key_set_ids; - if (file_handle_->ListLicenses(&key_set_ids)) { - LOGE( + if (handle->ListLicenses(&key_set_ids)) { + LOGW( "UpgradeUsageTableHeader::UpgradeLicensesFromUsageTable: unable to " "retrieve list of licenses"); return false; } - bool result = true; - for (size_t i = 0; i < key_set_ids.size(); ++i) { DeviceFiles::LicenseState license_state; std::string init_data, key_request, key_response, key_renewal_request; @@ -423,7 +444,7 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() { CdmAppParameterMap app_parameters; CdmUsageEntry usage_entry; uint32_t usage_entry_number; - if (!file_handle_->RetrieveLicense( + if (!handle->RetrieveLicense( key_set_ids[i], &license_state, &init_data, &key_request, &key_response, &key_renewal_request, &key_renewal_response, &release_server_url, &playback_start_time, &last_playback_time, @@ -432,7 +453,6 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() { LOGW( "UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to " "retrieve license"); - result = false; continue; } @@ -442,37 +462,26 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() { LOGW( "UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to " "retrieve provider session token"); - result = false; continue; } - if (provider_session_token.empty()) { - result = false; - continue; - } + if (provider_session_token.empty()) continue; - CryptoSession crypto_session(&metrics_); - CdmResponseType status = crypto_session.Open(GetSecurityLevel()); + CryptoSession crypto_session(metrics); + CdmResponseType status = crypto_session.Open(requested_security_level_); - if (status != NO_ERROR) { - result = false; - continue; - } + if (status != NO_ERROR) continue; status = AddEntry(&crypto_session, true /* persistent license */, key_set_ids[i], kEmptyString, &usage_entry_number); - if (status != NO_ERROR) { - result = false; - continue; - } + if (status != NO_ERROR) continue; status = crypto_session.CopyOldUsageEntry(provider_session_token); if (status != NO_ERROR) { crypto_session.Close(); - DeleteLastEntry(); - result = false; + Shrink(metrics, 1); continue; } @@ -480,26 +489,27 @@ bool UsageTableHeader::UpgradeLicensesFromUsageTable() { if (status != NO_ERROR) { crypto_session.Close(); - DeleteLastEntry(); - result = false; + Shrink(metrics, 1); continue; } - if (!file_handle_->StoreLicense( + if (!handle->StoreLicense( key_set_ids[i], license_state, init_data, key_request, key_response, key_renewal_request, key_renewal_response, release_server_url, playback_start_time, last_playback_time, grace_period_end_time, app_parameters, usage_entry, usage_entry_number)) { - LOGW("UsageTableHeader::StoreEntry: Failed to store license"); - result = false; + LOGE( + "UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to store " + "license"); continue; } } - return result; + return NO_ERROR; } -bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() { +bool UsageTableHeader::UpgradeUsageInfoFromUsageTable( + DeviceFiles* handle, metrics::MetricsGroup* metrics) { // Fetch all usage files. For each file retrieve all the usage info records // within the file. For each piece of usage information // * create a new usage entry @@ -509,27 +519,21 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() { // * once done processing all the usage records from a file, save the usage // information to persistent memory along with usage entry number and usage // entry. - // On errors, continue to the next usage record, but indicate on return - // that not all usage records may have been upgraded. std::vector usage_info_file_names; - if (file_handle_->ListUsageInfoFiles(&usage_info_file_names)) { - LOGE( + if (handle->ListUsageInfoFiles(&usage_info_file_names)) { + LOGW( "UpgradeUsageTableHeader::UpgradeUsageInfoFromUsageTable: Unable to " "retrieve list of usage info file names"); return false; } - bool result = true; - for (size_t i = 0; i < usage_info_file_names.size(); ++i) { std::vector usage_data; - if (!file_handle_->RetrieveUsageInfo(usage_info_file_names[i], - &usage_data)) { + if (!handle->RetrieveUsageInfo(usage_info_file_names[i], &usage_data)) { LOGW( "UsageTableHeader::UpgradeUsageInfoFromUsageTable: Failed to " "retrieve usage records from %s", usage_info_file_names[i].c_str()); - result = false; continue; } @@ -538,17 +542,13 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() { LOGW( "UsageTableHeader::UpgradeUsageInfoFromUsageTable: Provider " "session id empty"); - result = false; continue; } - CryptoSession crypto_session(&metrics_); - CdmResponseType status = crypto_session.Open(GetSecurityLevel()); + CryptoSession crypto_session(metrics); + CdmResponseType status = crypto_session.Open(requested_security_level_); - if (status != NO_ERROR) { - result = false; - continue; - } + if (status != NO_ERROR) continue; // TODO(rfrias): We need to fill in the app id, but it is hashed // and we have no way to extract. Use the hased filename instead? @@ -556,18 +556,14 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() { usage_data[j].key_set_id, kEmptyString, &(usage_data[i].usage_entry_number)); - if (status != NO_ERROR) { - result = false; - continue; - } + if (status != NO_ERROR) continue; status = crypto_session.CopyOldUsageEntry( usage_data[i].provider_session_token); if (status != NO_ERROR) { crypto_session.Close(); - DeleteLastEntry(); - result = false; + Shrink(metrics, 1); continue; } @@ -575,23 +571,21 @@ bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() { if (status != NO_ERROR) { crypto_session.Close(); - DeleteLastEntry(); - result = false; + Shrink(metrics, 1); continue; } } - if (!file_handle_->StoreUsageInfo(usage_info_file_names[i], usage_data)) { - LOGW( + if (!handle->StoreUsageInfo(usage_info_file_names[i], usage_data)) { + LOGE( "UsageTableHeader::StoreUsageInfo: Failed to store usage records to " "%s", usage_info_file_names[i].c_str()); - result = false; continue; } } - return result; + return NO_ERROR; } } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp index 438cbe58..0957a560 100644 --- a/libwvdrmengine/cdm/core/test/device_files_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/device_files_unittest.cpp @@ -17,12 +17,7 @@ namespace { const uint32_t kCertificateLen = 700; const uint32_t kWrappedKeyLen = 500; -const uint32_t kProtobufEstimatedOverhead = 75; -const uint32_t kLicenseRequestLen = 300; -const uint32_t kLicenseLen = 500; -const uint32_t kProviderSessionTokenLen = 128; -const uint32_t kKeySetIdLen = 20; -const uint32_t kUsageEntryLen = 50; +const uint32_t kProtobufEstimatedOverhead = 200; const std::string kEmptyString; @@ -1155,299 +1150,702 @@ LicenseInfo license_app_parameters_backwards_compatibility_test_data = { "365400048001220CD0599C2B85D9F2D573AC7893CE77CB5A10B326828BA8C89047505" "A8C9B606AC")}; +struct DeviceFilesTestListUsageInfoData { + std::string file_name; + bool is_usage_info_file; +}; + +DeviceFilesTestListUsageInfoData kTestListUsageInfoData[] = { + {"ksid056fe6e9c.lic", false}, {"usage.bin", true}, + {"cert.bin", false}, {"usage345agdf==.bin", true}, + {"usageyd6e.lic", false}, {"usgtable.bin", false}, + {"usaget3ED.bin", true}, +}; + struct UsageInfo { - std::string provider_session_token; - std::string license_request; - std::string license; - std::string usage_entry; - uint32_t usage_entry_number; + std::string app_id; + DeviceFiles::CdmUsageData usage_data; std::string file_data; }; +std::string kEmptyUsageInfoFileData = a2bs_hex( + "0A06080310012A001220468A9A97B23D0E17147416276CB133175F0A18534155C6FFEF024A" + "D80371D7C4"); + UsageInfo kUsageInfoTestData[] = { - {"", "", "", "", 0, // 0 usage info records - a2bs_hex("0A06080210012A00122095053501C5FA405B7EF01DA94685C6B20CB36493" - "A9CF1653B720E2BEA3B77929")}, - {// 1 usage info record + // test vector 0, app id: "", usage entry 0 + {"", + { + a2bs_hex("b8e7f26b6b8b59babf05b5a1f8927b412a85bc8551a928f00856329814ae" + "5a82"), + a2bs_hex("4463dc57079c27e34ae115c6f65b08f6311c4ea604a6512c42470b6f692a" + "76ea769d60d0b6bcf8d565ef31eb925f38e2095039c9f2f113ecee020f11" + "26eb30165372d538b551ebd7bae5cf0bbeebb3cdb6f180d42868051aab8f" + "f4947460dd96f0f8259fc6001059c998d2eb6902c064f9ae08e6cd3c7807" + "e50379507b41620d15dd76c0b1e7ed9417efd6825959b5077f464e6429a4" + "dee467a1ba2b05d38049912d5539f1ee9f5d8a569aa1c384384f847ed64f" + "6ffc101036da70e69c06e4916493e82e9fe3f65d85254c8c14f6ca0579bf" + "b3eaa86b2d7bb5ff572eccfd70f2ea4695f326beadf241ae4311e428c7c1" + "2a0d4d1915cd0537ff0f62cf13eb2fa2"), + a2bs_hex( + "bbe6b4b60da9d9bc34dcc8502fb81d8fd5fdbc8fa89605c86205f2b8c6530ff64" + "c8c31f579bd8eca603dfd5e397ac35e48931fd330351d01361bb31caaa7dbf816" + "a6144a12b6c22d1dceba20669ed635a40831066abd8071342119d7da11c43696b" + "2898d3df3b36beb8da013d9dc145343494b19d6da085f4a41e421d3def2ad8b72" + "dffffb6e79bbceaf8594045d16a62eed16904a3569860c531a32eaa5abb868b1d" + "d6a0b03d69c1a3f8336af80eb80badbbc7b80ca5943bd5b374302147052201fae" + "d30e9ffa99fc00b47f7eeb469512a413e873f91d959cccacccd3585b7f00ed8d4" + "685022101713c3adc439f27512a45926c1d2473477662c4bace72f380d105ddc9" + "f7be49ed71991b3d9e29a2038201373f98a845a57624a692f44ebd316d26c48fe" + "e82b655583317eca4aaa4dac841524a2dca111749629637ef29fa7e72645a8759" + "57fb3d98a5e6c8065b1349cfa23011cd6349d911c535475fed50be9eacb6a1ff3" + "ea7458823f0229f2fa90b7a7099e8ec349d3d0fe0277cba5157ca62c8fbaa893f" + "37b8c8cea2a0d2d2912caccf92d31aa17439479711b4a5b77445cc02c18bfe019" + "5ce8f1fe59e317214005cee5e25904c9fb0af7e2b6b4dccdf78e61e179a9f9399" + "6ec3c76f6da9b5a291bf08a73032b37edcbbbdd20cff94088a489167c56e5e75b" + "376874e9750212fe94d7656d9cd835db3b771ba5b58d2b255"), + "ksid854c8a60a5a547e122c24fca", + a2bs_hex("7d2b905e5eafd4b28aeeb7633283579e48add21a68eb26cc8c3b2e344579" + "003b12a38554336305525fa6ab70f024a18c73631bb1531eca3f0782c72d" + "ba017311b3f1e98c739632e305e4bc0b2561ae2b"), + 5, + }, a2bs_hex( - "924B035FBDA56AE5EF0ED05A08DE7AECC8ABE1835E0C4A548F7803937F4C3B4520EB7" - "F3334FFCDFA00DE56408F09D5019FCE87072D0DC6789817468974B2EA51EE3944B8D7" - "E0A88E4F16EBB80F03BD845231A01E6146841CBAEF0134DCD9300DB2D92732992C0F2" - "310D8E386FB31C67B9477010DEF9D99C4272589572A26A17E"), + "0AA407080310012A9D070A9A070A20B8E7F26B6B8B59BABF05B5A1F8927B412A85BC8" + "551A928F00856329814AE5A821280024463DC57079C27E34AE115C6F65B08F6311C4E" + "A604A6512C42470B6F692A76EA769D60D0B6BCF8D565EF31EB925F38E2095039C9F2F" + "113ECEE020F1126EB30165372D538B551EBD7BAE5CF0BBEEBB3CDB6F180D42868051A" + "AB8FF4947460DD96F0F8259FC6001059C998D2EB6902C064F9AE08E6CD3C7807E5037" + "9507B41620D15DD76C0B1E7ED9417EFD6825959B5077F464E6429A4DEE467A1BA2B05" + "D38049912D5539F1EE9F5D8A569AA1C384384F847ED64F6FFC101036DA70E69C06E49" + "16493E82E9FE3F65D85254C8C14F6CA0579BFB3EAA86B2D7BB5FF572ECCFD70F2EA46" + "95F326BEADF241AE4311E428C7C12A0D4D1915CD0537FF0F62CF13EB2FA21A8004BBE" + "6B4B60DA9D9BC34DCC8502FB81D8FD5FDBC8FA89605C86205F2B8C6530FF64C8C31F5" + "79BD8ECA603DFD5E397AC35E48931FD330351D01361BB31CAAA7DBF816A6144A12B6C" + "22D1DCEBA20669ED635A40831066ABD8071342119D7DA11C43696B2898D3DF3B36BEB" + "8DA013D9DC145343494B19D6DA085F4A41E421D3DEF2AD8B72DFFFFB6E79BBCEAF859" + "4045D16A62EED16904A3569860C531A32EAA5ABB868B1DD6A0B03D69C1A3F8336AF80" + "EB80BADBBC7B80CA5943BD5B374302147052201FAED30E9FFA99FC00B47F7EEB46951" + "2A413E873F91D959CCCACCCD3585B7F00ED8D4685022101713C3ADC439F27512A4592" + "6C1D2473477662C4BACE72F380D105DDC9F7BE49ED71991B3D9E29A2038201373F98A" + "845A57624A692F44EBD316D26C48FEE82B655583317ECA4AAA4DAC841524A2DCA1117" + "49629637EF29FA7E72645A875957FB3D98A5E6C8065B1349CFA23011CD6349D911C53" + "5475FED50BE9EACB6A1FF3EA7458823F0229F2FA90B7A7099E8EC349D3D0FE0277CBA" + "5157CA62C8FBAA893F37B8C8CEA2A0D2D2912CACCF92D31AA17439479711B4A5B7744" + "5CC02C18BFE0195CE8F1FE59E317214005CEE5E25904C9FB0AF7E2B6B4DCCDF78E61E" + "179A9F93996EC3C76F6DA9B5A291BF08A73032B37EDCBBBDD20CFF94088A489167C56" + "E5E75B376874E9750212FE94D7656D9CD835DB3B771BA5B58D2B255221C6B73696438" + "35346338613630613561353437653132326332346663612A507D2B905E5EAFD4B28AE" + "EB7633283579E48ADD21A68EB26CC8C3B2E344579003B12A38554336305525FA6AB70" + "F024A18C73631BB1531ECA3F0782C72DBA017311B3F1E98C739632E305E4BC0B2561A" + "E2B30051220BCA71B49A97A2CFD5A3C4619807FE9EFCB68F9C69C4D63254FF10B22F1" + "13FA82")}, + // test vector 1, app id: "", usage entry 1 + {"", + { + a2bs_hex("5d637be37a9722aa35c23d346470851aca7d2edcd1a27edf124ea6"), + a2bs_hex("bc96d6878e3086c33624821f1f3ece23f27e58222c2bb8d1615476a11792" + "63b58f6427e92911d961fc7a3afd947aed8c9aead1f08457925d2ce4e0f6" + "18b21942baa60b231eae864048f94f74ffa700e5777f812adb6f0cb6ba6f" + "0d145e3951191eb217140c32f2c7565053222131ff823bc36d80b24b561c" + "cbea9d397fe00942e7ff73b8152cdc083b63a9f9c4a77056a0d79f44f267" + "da0ed629d9c902f7e838957ea41aa442221c3aa9410db58302b468c6d7f2" + "113663809f0dcf187c108ced"), + a2bs_hex("f6fb3693413cc1d7d5e3459b856e4156c78f8d85d548939fd00474c8cded" + "c46835cc981758500fe61cc79383b4d9f87c3e33d19c2d25d7d15dd0f3d2" + "b1af4583b71e90c59886d297e78e929c2f3840c82c626914a4eb537b3a51" + "61d963472b6592c0fa1e415556bc009c2da22bcf743ac434e22f8a33b432" + "10dfd8aa09fe86105610f366e6fb7da18996cf7c7db425a9bb50e4a13190" + "a680b9f82d37d09658585abe3bf9f009a5c1ce38a7cefe17f71fb402768b" + "2d66b4ca523ed06729349695d7864d7cf7a1cc11d0da2b8a43db834d10b4" + "7d9579ec9e46986a133277b92c636cb2a6a823afe73317266c9c0601ddba" + "db76e1d254d6183b93a1ea91a7e6c567331b3ee3a5ab1484af91fd0f8dac" + "5fd980a67d8f33cc1d6cf20ee4c24582d03967ed48b6f28e7514e4d18f38" + "c8cb1e54fba59af7d6a79c6c5a7ab06baac964c7958d201910adca018022" + "fbeb8535b64f5ce83d3c"), + "ksid2f2e85ce8a677f60047d7024e07b5ae6", + a2bs_hex("b74880fbddc5bb9db82f09bc7de3ffd95a0a671b979d4c1f0564eaf63eb6" + "b5a8c3f16d9f964afbd011e2326f9c27afbe74536f3f0601a71d9c1c422f" + "335611bf3bf1a1c89e2dea27c17a9d9a58a74121e840b002e8a6fb590072" + "45be786c1f64"), + 9, + }, a2bs_hex( - "1E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315DB32B6D3FDD1A8E8A09" - "4174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E154BC1548FC40EC70927" - "75531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6BE37645E6800F053B1D" - "A9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D344A419C0F0034A1B5" - "F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410F218E52A853AD214FD" - "05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3BCBAE42DF9EA65E42E" - "151827086EADE71C138B972CC3992CF9ADA944C063816352ED8658D3FA07BE0F32239" - "E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E510445294F44E511BD9B1A" - "F19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E"), + "0AE80C080310012AE10C0A9A070A20B8E7F26B6B8B59BABF05B5A1F8927B412A85BC8" + "551A928F00856329814AE5A821280024463DC57079C27E34AE115C6F65B08F6311C4E" + "A604A6512C42470B6F692A76EA769D60D0B6BCF8D565EF31EB925F38E2095039C9F2F" + "113ECEE020F1126EB30165372D538B551EBD7BAE5CF0BBEEBB3CDB6F180D42868051A" + "AB8FF4947460DD96F0F8259FC6001059C998D2EB6902C064F9AE08E6CD3C7807E5037" + "9507B41620D15DD76C0B1E7ED9417EFD6825959B5077F464E6429A4DEE467A1BA2B05" + "D38049912D5539F1EE9F5D8A569AA1C384384F847ED64F6FFC101036DA70E69C06E49" + "16493E82E9FE3F65D85254C8C14F6CA0579BFB3EAA86B2D7BB5FF572ECCFD70F2EA46" + "95F326BEADF241AE4311E428C7C12A0D4D1915CD0537FF0F62CF13EB2FA21A8004BBE" + "6B4B60DA9D9BC34DCC8502FB81D8FD5FDBC8FA89605C86205F2B8C6530FF64C8C31F5" + "79BD8ECA603DFD5E397AC35E48931FD330351D01361BB31CAAA7DBF816A6144A12B6C" + "22D1DCEBA20669ED635A40831066ABD8071342119D7DA11C43696B2898D3DF3B36BEB" + "8DA013D9DC145343494B19D6DA085F4A41E421D3DEF2AD8B72DFFFFB6E79BBCEAF859" + "4045D16A62EED16904A3569860C531A32EAA5ABB868B1DD6A0B03D69C1A3F8336AF80" + "EB80BADBBC7B80CA5943BD5B374302147052201FAED30E9FFA99FC00B47F7EEB46951" + "2A413E873F91D959CCCACCCD3585B7F00ED8D4685022101713C3ADC439F27512A4592" + "6C1D2473477662C4BACE72F380D105DDC9F7BE49ED71991B3D9E29A2038201373F98A" + "845A57624A692F44EBD316D26C48FEE82B655583317ECA4AAA4DAC841524A2DCA1117" + "49629637EF29FA7E72645A875957FB3D98A5E6C8065B1349CFA23011CD6349D911C53" + "5475FED50BE9EACB6A1FF3EA7458823F0229F2FA90B7A7099E8EC349D3D0FE0277CBA" + "5157CA62C8FBAA893F37B8C8CEA2A0D2D2912CACCF92D31AA17439479711B4A5B7744" + "5CC02C18BFE0195CE8F1FE59E317214005CEE5E25904C9FB0AF7E2B6B4DCCDF78E61E" + "179A9F93996EC3C76F6DA9B5A291BF08A73032B37EDCBBBDD20CFF94088A489167C56" + "E5E75B376874E9750212FE94D7656D9CD835DB3B771BA5B58D2B255221C6B73696438" + "35346338613630613561353437653132326332346663612A507D2B905E5EAFD4B28AE" + "EB7633283579E48ADD21A68EB26CC8C3B2E344579003B12A38554336305525FA6AB70" + "F024A18C73631BB1531ECA3F0782C72DBA017311B3F1E98C739632E305E4BC0B2561A" + "E2B30050AC1050A1B5D637BE37A9722AA35C23D346470851ACA7D2EDCD1A27EDF124E" + "A612C001BC96D6878E3086C33624821F1F3ECE23F27E58222C2BB8D1615476A117926" + "3B58F6427E92911D961FC7A3AFD947AED8C9AEAD1F08457925D2CE4E0F618B21942BA" + "A60B231EAE864048F94F74FFA700E5777F812ADB6F0CB6BA6F0D145E3951191EB2171" + "40C32F2C7565053222131FF823BC36D80B24B561CCBEA9D397FE00942E7FF73B8152C" + "DC083B63A9F9C4A77056A0D79F44F267DA0ED629D9C902F7E838957EA41AA442221C3" + "AA9410DB58302B468C6D7F2113663809F0DCF187C108CED1AD402F6FB3693413CC1D7" + "D5E3459B856E4156C78F8D85D548939FD00474C8CDEDC46835CC981758500FE61CC79" + "383B4D9F87C3E33D19C2D25D7D15DD0F3D2B1AF4583B71E90C59886D297E78E929C2F" + "3840C82C626914A4EB537B3A5161D963472B6592C0FA1E415556BC009C2DA22BCF743" + "AC434E22F8A33B43210DFD8AA09FE86105610F366E6FB7DA18996CF7C7DB425A9BB50" + "E4A13190A680B9F82D37D09658585ABE3BF9F009A5C1CE38A7CEFE17F71FB402768B2" + "D66B4CA523ED06729349695D7864D7CF7A1CC11D0DA2B8A43DB834D10B47D9579EC9E" + "46986A133277B92C636CB2A6A823AFE73317266C9C0601DDBADB76E1D254D6183B93A" + "1EA91A7E6C567331B3EE3A5AB1484AF91FD0F8DAC5FD980A67D8F33CC1D6CF20EE4C2" + "4582D03967ED48B6F28E7514E4D18F38C8CB1E54FBA59AF7D6A79C6C5A7AB06BAAC96" + "4C7958D201910ADCA018022FBEB8535B64F5CE83D3C22246B73696432663265383563" + "653861363737663630303437643730323465303762356165362A60B74880FBDDC5BB9" + "DB82F09BC7DE3FFD95A0A671B979D4C1F0564EAF63EB6B5A8C3F16D9F964AFBD011E2" + "326F9C27AFBE74536F3F0601A71D9C1C422F335611BF3BF1A1C89E2DEA27C17A9D9A5" + "8A74121E840B002E8A6FB59007245BE786C1F6430091220B9626315C7601BC2BD1E1C" + "88F752C956261CE7509669B2AEAA1E7F1304017941")}, + // test vector 2, app id: "app_1", usage entry 0 + {"app_1", + { + a2bs_hex("bb3370ccd3c3c49573d6b74386d1886d9888bd81fe3241bcd2bac9407d1a" + "834e"), + a2bs_hex("dc0e51cfa5863f6c0b32a4ad7fa40625dadcc2dcde9e7fa3983b8804d996" + "6803181682fc8ae831472e0b2fc26276242fbce624d286eedecce5555804" + "913b4f8f86c5ae86160b8434b109169a63da04c5265102d772c1180543ef" + "226d2140357aca6cf87da3f7e370dfc08ca92a1f7c7d314eab36292a9170" + "8f6c6ad84b37ee1c7dfafb99289206cb752d063f330efd85885f4b72ba1c" + "a5823eed865a461345e3d6417872bf3b0608b3d9e1004c11e7326d3ed406" + "192e13455d0ec4e1f558a147"), + a2bs_hex("f42a68ca3a14fb68f5992e4519f57970c3dae73f8da1d5b0b1da3eff7a95" + "4012a0dc634357f3f5477a820e182182f24ae8e835ab10c18386cc8a0727" + "d3f38b628639bfbd69a94d4053eab1c31e075e014cc578b226cfe24d6b42" + "db242972def8f23a4aae88451307c2abaf54c1803ae54e3f1149aa6e6d42" + "88cc7d474e876be07954e8b2deff4ade4bf30229fb6c92df4d66cd463f68" + "6b4754b940210eb59f1581d658ddf8de8389e0e2d123e2cae3c2be6eb194" + "8ccc896dd4cdf45f9090c96dfb925795cfb4ccda83e3eb4f745577b17fc1" + "66bf5f4103c9085134cad7863a41b04f32ef20201e54b55f1817ce589619" + "b096c254fd2c2fa4a06f4de35ccfd23e"), + "kside11109bf20cde544083ef4ee", + a2bs_hex("ea106c124476b753d39368a5966972a2729bb8bbea734a2b3e812b705eac" + "e016c8a03c9a406094d80059ef4ca26f1928fa2daa5de9a6f22372e5c7a9" + "41e610d1efb56ed7ce2228a70e2e150afb66edc2da066d463aa90ba0caff" + "078fbfec05c8"), + 0, + }, + a2bs_hex("0AF404080310012AED040AEA040A20BB3370CCD3C3C49573D6B74386D1886D98" + "88BD81FE3241BCD2BAC9407D1A834E12C001DC0E51CFA5863F6C0B32A4AD7FA4" + "0625DADCC2DCDE9E7FA3983B8804D9966803181682FC8AE831472E0B2FC26276" + "242FBCE624D286EEDECCE5555804913B4F8F86C5AE86160B8434B109169A63DA" + "04C5265102D772C1180543EF226D2140357ACA6CF87DA3F7E370DFC08CA92A1F" + "7C7D314EAB36292A91708F6C6AD84B37EE1C7DFAFB99289206CB752D063F330E" + "FD85885F4B72BA1CA5823EED865A461345E3D6417872BF3B0608B3D9E1004C11" + "E7326D3ED406192E13455D0EC4E1F558A1471A8002F42A68CA3A14FB68F5992E" + "4519F57970C3DAE73F8DA1D5B0B1DA3EFF7A954012A0DC634357F3F5477A820E" + "182182F24AE8E835AB10C18386CC8A0727D3F38B628639BFBD69A94D4053EAB1" + "C31E075E014CC578B226CFE24D6B42DB242972DEF8F23A4AAE88451307C2ABAF" + "54C1803AE54E3F1149AA6E6D4288CC7D474E876BE07954E8B2DEFF4ADE4BF302" + "29FB6C92DF4D66CD463F686B4754B940210EB59F1581D658DDF8DE8389E0E2D1" + "23E2CAE3C2BE6EB1948CCC896DD4CDF45F9090C96DFB925795CFB4CCDA83E3EB" + "4F745577B17FC166BF5F4103C9085134CAD7863A41B04F32EF20201E54B55F18" + "17CE589619B096C254FD2C2FA4A06F4DE35CCFD23E221C6B7369646531313130" + "396266323063646535343430383365663465652A60EA106C124476B753D39368" + "A5966972A2729BB8BBEA734A2B3E812B705EACE016C8A03C9A406094D80059EF" + "4CA26F1928FA2DAA5DE9A6F22372E5C7A941E610D1EFB56ED7CE2228A70E2E15" + "0AFB66EDC2DA066D463AA90BA0CAFF078FBFEC05C8300012203384AAAFD3A883" + "17E6ED20BB88B0B3C01388AB1DF721547AE6FCB586659BC437")}, + // test vector 3, app id: "app_2", usage entry 0 + {"app_2", + { + a2bs_hex( + "9212a6926f21c6727c1ee89d5607047a1636f206f70e21fda86e01b6a4b5"), + a2bs_hex("ef947abed64078edf5b21fe6d3fb65384595d63a6d03e4d1d397c5019dee" + "b6890d3ef8773002b91e255af0820fb594069df55d8abf96498e493f5c70" + "f6b85f50e12a1ed3c039ad0cd838fe44d3fa9e2bbddeb2919041203111ed" + "7778701b04d6b15f41d0bde799e20a38b27bf96fdbe844f10364baeb5935" + "96220993c608ac793de76c237ca350931a7e216538074dbd83ddf262d9f1" + "8acd91e1ea5372f7e773c5b64333"), + a2bs_hex("7709721b3aa48597e88c99e82eaf7dff07e87e0318d9d7cec29096ec5918" + "26aa7a359316d6de1d1329b408543e237de84c986987ead1bb6a0c38817e" + "93013e5c989d366f49590b834453ec64b7433bf0b3335b9e222bad4caf55" + "4d69575c58595283166fea42e89645fc7e2d3ac9e0c1399b096cf3fed1e5" + "deb1bc4e0ee894f0ae3f929dd7dba4530e5655edbbf6041df430482eb2e8" + "91b6a93af84d3c16dbad92733ffd34e8f4ce24506bead578d20cd3e291c2" + "fc2f811db875f49abc21a24277d2ba474fe6af6c14021cfead5513e0999e" + "094020ce08209bbc08f13fe2b96d7ba8213c8e9c85b6a623788d34da794e" + "17e4cd3bd65680b97fb30bad64ddc42b1bcfb0b83e5dda3501a5902ca609" + "f41837a0d5cd096e0659b67c"), + "ksid62d88ed7b292217b0238be", + a2bs_hex("5422463fd2e4dd47626e97dd6b4ee0b89523aaebe8d11e7e7be703ef01e4" + "9b17eaf020cede0a9e0e7b5d91e4db7abdce445936cb2deecdefefdb14b7" + "8f67b7ca5c733c9e88446fd814584584b86becbf6eb2b0e3d5603e8b"), + 25, + }, a2bs_hex( - "40FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C029F" - "D2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B037" - "72BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA991C8" - "BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C592436C8" - "B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2EFC6" - "780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A660" - "2B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F4C3" - "5FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24B06" - "53A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6374" - "D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6FB1A" - "C91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB8904A5" - "999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267ACA2" - "E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82989" - "C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A771" - "F561B165987E552824B0C914E708E425C3"), + "0AE604080310012ADF040ADC040A1E9212A6926F21C6727C1EE89D5607047A1636F20" + "6F70E21FDA86E01B6A4B512A401EF947ABED64078EDF5B21FE6D3FB65384595D63A6D" + "03E4D1D397C5019DEEB6890D3EF8773002B91E255AF0820FB594069DF55D8ABF96498" + "E493F5C70F6B85F50E12A1ED3C039AD0CD838FE44D3FA9E2BBDDEB2919041203111ED" + "7778701B04D6B15F41D0BDE799E20A38B27BF96FDBE844F10364BAEB593596220993C" + "608AC793DE76C237CA350931A7E216538074DBD83DDF262D9F18ACD91E1EA5372F7E7" + "73C5B643331A9A027709721B3AA48597E88C99E82EAF7DFF07E87E0318D9D7CEC2909" + "6EC591826AA7A359316D6DE1D1329B408543E237DE84C986987EAD1BB6A0C38817E93" + "013E5C989D366F49590B834453EC64B7433BF0B3335B9E222BAD4CAF554D69575C585" + "95283166FEA42E89645FC7E2D3AC9E0C1399B096CF3FED1E5DEB1BC4E0EE894F0AE3F" + "929DD7DBA4530E5655EDBBF6041DF430482EB2E891B6A93AF84D3C16DBAD92733FFD3" + "4E8F4CE24506BEAD578D20CD3E291C2FC2F811DB875F49ABC21A24277D2BA474FE6AF" + "6C14021CFEAD5513E0999E094020CE08209BBC08F13FE2B96D7BA8213C8E9C85B6A62" + "3788D34DA794E17E4CD3BD65680B97FB30BAD64DDC42B1BCFB0B83E5DDA3501A5902C" + "A609F41837A0D5CD096E0659B67C221A6B73696436326438386564376232393232313" + "7623032333862652A585422463FD2E4DD47626E97DD6B4EE0B89523AAEBE8D11E7E7B" + "E703EF01E49B17EAF020CEDE0A9E0E7B5D91E4DB7ABDCE445936CB2DEECDEFEFDB14B" + "78F67B7CA5C733C9E88446FD814584584B86BECBF6EB2B0E3D5603E8B30191220E964" + "7EB0AC28F0CB11C85111D69B5FA74E80015F4A07FB5C144E6CFE0E8E3709")}, + // test vector 4, app id: "app_2", usage entry 1 + {"app_2", + { + a2bs_hex("831fad51e52a403524539eab6a1b201e46674ca3b9167b1c1b53f5e5e3"), + a2bs_hex("36d83acbc5e4ed027ed583e3b2169d98f4abedda15b781408e68efa14fef" + "a9f3f0309bcb5a9fff6580636ebe3548e5acb43b76cfeb29a9c86324e62a" + "eb40556005c6686e718f9bf61b0681d43b5b1e88084b3aea27a6b0e844e5" + "500b6fcfacf2ee44d6af7f64154ab3fd4fbd0b8056cf63971076a1eb3642" + "b78d5e76b84f4ed9f6220089863f8a4911691e79feffc9f804c4c36c7f85" + "e45b1d276c85875875267eb65da70fd2d5e9176d6914"), + a2bs_hex("317bd7063bfb9fae1b2e46f4cf15b7bc8c92517ff5c32cbb52ae4b67afc5" + "d569cb66a462def7a18a7d0acebf9f6e8a604356ade2c81450c5466a4728" + "90b03eefcf65388f060e24551c67b7d46ae5d4d841d5cc63d137fd543fae" + "2c771756590b90e480ca0126f1fc0090ace62499e47569fc52196c788f80" + "139755bdf12a7acb29fd6e23a46a4c036f04ff1ed6cd714094253bf1c587" + "62c93f0ddf8a73c4be927ffec2723a16d8ffe5128851f58537461275f6aa" + "1976e3b399b7243919207e040ec16c5328e8ab082278fce0e5d3df5c5f92" + "dba51fa6613587d4ece31f2c001b49bfaed434f9512e895c2e09c88ddbf1" + "84bfafe4d82e5d05a26ac06cde29faf6ab05b96685649c923779ce5ef7f3" + "16531ada8e74e45ab1dc1d75648aa2de052674728867e87639ff9b782a3" + "3"), + "kside1d30b33b55f2deb4716", + a2bs_hex("d44a9d70a7c582559f089b1c0fdfcbdaf5e26b672fca5d58e889b407a0ba" + "8599079cde11fadfab23aa1b97622839f3b7e1a96f8332bec5fbcbc9eb64" + "fd5ed05887b8fa3bfd6ecc7bc91e621342732062d2f4411b763e20328af6" + "f8ef5030e2f8027aef9e"), + 6, + }, a2bs_hex( - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" - "22232425262728292a2b2c2d2e2f"), - 6, + "0AE809080310012AE1090ADC040A1E9212A6926F21C6727C1EE89D5607047A1636F20" + "6F70E21FDA86E01B6A4B512A401EF947ABED64078EDF5B21FE6D3FB65384595D63A6D" + "03E4D1D397C5019DEEB6890D3EF8773002B91E255AF0820FB594069DF55D8ABF96498" + "E493F5C70F6B85F50E12A1ED3C039AD0CD838FE44D3FA9E2BBDDEB2919041203111ED" + "7778701B04D6B15F41D0BDE799E20A38B27BF96FDBE844F10364BAEB593596220993C" + "608AC793DE76C237CA350931A7E216538074DBD83DDF262D9F18ACD91E1EA5372F7E7" + "73C5B643331A9A027709721B3AA48597E88C99E82EAF7DFF07E87E0318D9D7CEC2909" + "6EC591826AA7A359316D6DE1D1329B408543E237DE84C986987EAD1BB6A0C38817E93" + "013E5C989D366F49590B834453EC64B7433BF0B3335B9E222BAD4CAF554D69575C585" + "95283166FEA42E89645FC7E2D3AC9E0C1399B096CF3FED1E5DEB1BC4E0EE894F0AE3F" + "929DD7DBA4530E5655EDBBF6041DF430482EB2E891B6A93AF84D3C16DBAD92733FFD3" + "4E8F4CE24506BEAD578D20CD3E291C2FC2F811DB875F49ABC21A24277D2BA474FE6AF" + "6C14021CFEAD5513E0999E094020CE08209BBC08F13FE2B96D7BA8213C8E9C85B6A62" + "3788D34DA794E17E4CD3BD65680B97FB30BAD64DDC42B1BCFB0B83E5DDA3501A5902C" + "A609F41837A0D5CD096E0659B67C221A6B73696436326438386564376232393232313" + "7623032333862652A585422463FD2E4DD47626E97DD6B4EE0B89523AAEBE8D11E7E7B" + "E703EF01E49B17EAF020CEDE0A9E0E7B5D91E4DB7ABDCE445936CB2DEECDEFEFDB14B" + "78F67B7CA5C733C9E88446FD814584584B86BECBF6EB2B0E3D5603E8B30190AFF040A" + "1D831FAD51E52A403524539EAB6A1B201E46674CA3B9167B1C1B53F5E5E312AC0136D" + "83ACBC5E4ED027ED583E3B2169D98F4ABEDDA15B781408E68EFA14FEFA9F3F0309BCB" + "5A9FFF6580636EBE3548E5ACB43B76CFEB29A9C86324E62AEB40556005C6686E718F9" + "BF61B0681D43B5B1E88084B3AEA27A6B0E844E5500B6FCFACF2EE44D6AF7F64154AB3" + "FD4FBD0B8056CF63971076A1EB3642B78D5E76B84F4ED9F6220089863F8A4911691E7" + "9FEFFC9F804C4C36C7F85E45B1D276C85875875267EB65DA70FD2D5E9176D69141AAC" + "02317BD7063BFB9FAE1B2E46F4CF15B7BC8C92517FF5C32CBB52AE4B67AFC5D569CB6" + "6A462DEF7A18A7D0ACEBF9F6E8A604356ADE2C81450C5466A472890B03EEFCF65388F" + "060E24551C67B7D46AE5D4D841D5CC63D137FD543FAE2C771756590B90E480CA0126F" + "1FC0090ACE62499E47569FC52196C788F80139755BDF12A7ACB29FD6E23A46A4C036F" + "04FF1ED6CD714094253BF1C58762C93F0DDF8A73C4BE927FFEC2723A16D8FFE512885" + "1F58537461275F6AA1976E3B399B7243919207E040EC16C5328E8AB082278FCE0E5D3" + "DF5C5F92DBA51FA6613587D4ECE31F2C001B49BFAED434F9512E895C2E09C88DDBF18" + "4BFAFE4D82E5D05A26AC06CDE29FAF6AB05B96685649C923779CE5EF7F316531ADA8E" + "74E45AB1DC1D75648AA2DE052674728867E87639FF9B782A3322186B7369646531643" + "3306233336235356632646562343731362A64D44A9D70A7C582559F089B1C0FDFCBDA" + "F5E26B672FCA5D58E889B407A0BA8599079CDE11FADFAB23AA1B97622839F3B7E1A96" + "F8332BEC5FBCBC9EB64FD5ED05887B8FA3BFD6ECC7BC91E621342732062D2F4411B76" + "3E20328AF6F8EF5030E2F8027AEF9E300612203F1EEC1DDC56EE480AC744C1D72379E" + "AFFD4675FF15A7D53BD56AC9736D62FC1")}, + // test vector 5, app id: "app_1", usage entry 1 + {"app_1", + { + a2bs_hex("eace80e30bfda213f1ce4dbcfd9d4d24b8e2ae00054d167d9d7ae9954706" + "2b9113"), + a2bs_hex("68a7665a21348fc0590328608dc520be40f5b749328568fe383ef69c1a58" + "7ab2446cf9c41d821373d0856a883b316519a42218f80e7bd5764d16bac9" + "a9b427a7278f5940e563fcf6dee0ff3aadbb702ebf2c54ec354ae7acc84e" + "e6a54bca1f30e38ef71c44a81d0009b1484feaf4f1a56f58c35bb2372c80" + "c6dfb389e6de60bdd3d46c03975715260f6fdbe42facb64c22eda9635c04" + "da79434e1c41fbd2fdbbab6598283226c0278e8e0a96d780d3436523efd" + "1"), + a2bs_hex("ff6fecf7157828812a2d6dcb15383a6d9af4519ef804c6053a10c436002d" + "e3a4efcc017755f4ad1101bdc813e2d211732418dee529cbb413c48aa588" + "4c76a5c6f556a715055560d4247f5bf310956949a3a171a4aa608a484468" + "84e7676d558ff64d392b84e617805693d90f1e9b7b540c383d384d7f7ce0" + "6c23618681bd838ceb1a514047f1c562c43159cc5e21588fbfce8a354111" + "160f1a1e2bd3d798a000579bdfdb977252809ee1502df8045972fe8aac84" + "0211c2f8d9e4d5be18509c327c647d654c4b6cc430b98f1ff37c96fab087" + "fb561b8cc18480f877c873594d3148ff74b0e3c6327c27ca876dae742239" + "8fc5e85269cba49ad099"), + "ksid8e80350cbef6463a0025e6cc", + a2bs_hex("7ccc7ce96055e16a52fa192ea2cf3c9df3e89b9133a52286f71e6c6d82d0" + "435f6b2155dfde590b347d8c86f62d7dfbaae640c237256f609e5da9cc6c" + "103465fe3441612bbdfdf4d1c24b2147feb8565cef4993e439c9d564a39a" + "4ac5bb1da69acb44da06e4522c9a93d310cdda5dac1e1e0b91abff41e4e2" + "edda4001"), + 7, + }, a2bs_hex( - "0AB307080210012AAC070AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE" - "1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D" - "0DC6789817468974B2EA51EE3944B8D7E0A88E4F16EBB80F03BD845231A01E6146841" - "CBAEF0134DCD9300DB2D92732992C0F2310D8E386FB31C67B9477010DEF9D99C42725" - "89572A26A17E12AC021E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315D" - "B32B6D3FDD1A8E8A094174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E15" - "4BC1548FC40EC7092775531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6B" - "E37645E6800F053B1DA9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D" - "344A419C0F0034A1B5F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410" - "F218E52A853AD214FD05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3" - "BCBAE42DF9EA65E42E151827086EADE71C138B972CC3992CF9ADA944C063816352ED8" - "658D3FA07BE0F32239E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E5104" - "45294F44E511BD9B1AF19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E1AF" - "40340FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C0" - "29FD2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B" - "03772BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA99" - "1C8BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C59243" - "6C8B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2E" - "FC6780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A" - "6602B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F" - "4C35FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24" - "B0653A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6" - "374D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6F" - "B1AC91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB890" - "4A5999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267A" - "CA2E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82" - "989C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A" - "771F561B165987E552824B0C914E708E425C3122051C8F84C5713500997DC5B325BAE" - "D208B224DFAEB2B034E58046A62F503FED6E")}, - {// 2 usage info records + "0AEC09080310012AE5090AEA040A20BB3370CCD3C3C49573D6B74386D1886D9888BD8" + "1FE3241BCD2BAC9407D1A834E12C001DC0E51CFA5863F6C0B32A4AD7FA40625DADCC2" + "DCDE9E7FA3983B8804D9966803181682FC8AE831472E0B2FC26276242FBCE624D286E" + "EDECCE5555804913B4F8F86C5AE86160B8434B109169A63DA04C5265102D772C11805" + "43EF226D2140357ACA6CF87DA3F7E370DFC08CA92A1F7C7D314EAB36292A91708F6C6" + "AD84B37EE1C7DFAFB99289206CB752D063F330EFD85885F4B72BA1CA5823EED865A46" + "1345E3D6417872BF3B0608B3D9E1004C11E7326D3ED406192E13455D0EC4E1F558A14" + "71A8002F42A68CA3A14FB68F5992E4519F57970C3DAE73F8DA1D5B0B1DA3EFF7A9540" + "12A0DC634357F3F5477A820E182182F24AE8E835AB10C18386CC8A0727D3F38B62863" + "9BFBD69A94D4053EAB1C31E075E014CC578B226CFE24D6B42DB242972DEF8F23A4AAE" + "88451307C2ABAF54C1803AE54E3F1149AA6E6D4288CC7D474E876BE07954E8B2DEFF4" + "ADE4BF30229FB6C92DF4D66CD463F686B4754B940210EB59F1581D658DDF8DE8389E0" + "E2D123E2CAE3C2BE6EB1948CCC896DD4CDF45F9090C96DFB925795CFB4CCDA83E3EB4" + "F745577B17FC166BF5F4103C9085134CAD7863A41B04F32EF20201E54B55F1817CE58" + "9619B096C254FD2C2FA4A06F4DE35CCFD23E221C6B736964653131313039626632306" + "3646535343430383365663465652A60EA106C124476B753D39368A5966972A2729BB8" + "BBEA734A2B3E812B705EACE016C8A03C9A406094D80059EF4CA26F1928FA2DAA5DE9A" + "6F22372E5C7A941E610D1EFB56ED7CE2228A70E2E150AFB66EDC2DA066D463AA90BA0" + "CAFF078FBFEC05C830000AF5040A21EACE80E30BFDA213F1CE4DBCFD9D4D24B8E2AE0" + "0054D167D9D7AE99547062B911312B40168A7665A21348FC0590328608DC520BE40F5" + "B749328568FE383EF69C1A587AB2446CF9C41D821373D0856A883B316519A42218F80" + "E7BD5764D16BAC9A9B427A7278F5940E563FCF6DEE0FF3AADBB702EBF2C54EC354AE7" + "ACC84EE6A54BCA1F30E38EF71C44A81D0009B1484FEAF4F1A56F58C35BB2372C80C6D" + "FB389E6DE60BDD3D46C03975715260F6FDBE42FACB64C22EDA9635C04DA79434E1C41" + "FBD2FDBBAB6598283226C0278E8E0A96D780D3436523EFD11AFA01FF6FECF71578288" + "12A2D6DCB15383A6D9AF4519EF804C6053A10C436002DE3A4EFCC017755F4AD1101BD" + "C813E2D211732418DEE529CBB413C48AA5884C76A5C6F556A715055560D4247F5BF31" + "0956949A3A171A4AA608A48446884E7676D558FF64D392B84E617805693D90F1E9B7B" + "540C383D384D7F7CE06C23618681BD838CEB1A514047F1C562C43159CC5E21588FBFC" + "E8A354111160F1A1E2BD3D798A000579BDFDB977252809EE1502DF8045972FE8AAC84" + "0211C2F8D9E4D5BE18509C327C647D654C4B6CC430B98F1FF37C96FAB087FB561B8CC" + "18480F877C873594D3148FF74B0E3C6327C27CA876DAE7422398FC5E85269CBA49AD0" + "99221C6B7369643865383033353063626566363436336130303235653663632A7C7CC" + "C7CE96055E16A52FA192EA2CF3C9DF3E89B9133A52286F71E6C6D82D0435F6B2155DF" + "DE590B347D8C86F62D7DFBAAE640C237256F609E5DA9CC6C103465FE3441612BBDFDF" + "4D1C24B2147FEB8565CEF4993E439C9D564A39A4AC5BB1DA69ACB44DA06E4522C9A93" + "D310CDDA5DAC1E1E0B91ABFF41E4E2EDDA40013007122062B0F22E176F77881114844" + "DABC6F0EB0F80381D8A06ECDF09913A5CF8E85B3F")}, + // test vector 6, app id: "", usage entry 2 + {"", + { + a2bs_hex("1fbf0a1d2432805a0f8292ff627a9a7c60b733a51b365892c832261d71"), + a2bs_hex("1ad116a26f423c7019fa8dca226c2d2bdeec91beb1fd38d6890e32745a4d" + "bb9409b65fe834c2522d92621b265a9d526b4fcadcacf4c4deb364661118" + "494fd1561621392bf4450e6833be290d49e59e665a031375ee56ad1f3392" + "436ba213abc5ac10a199e73123f84f7644282137da24cbde30c10a6eb847" + "ca72b8b311ad329d2c9cb0909c2ecbe3fbaf88e81bb5aeaa6480fff67e87" + "77fa00c783aa160f1e211cb9bf3835fa8f82923c05895c359cf306f5cb90" + "a73b8ce2ce9ed210485e1c57"), + a2bs_hex("0bf120627d01690d14321fa967d81997b959b35ed7745dee9e885dd402df" + "83c3b8f52999b16c2d1d47bf4724a9ced984175eb8a032d613294c148020" + "74154c34fd40fe6ea74fa830fdcb9cc7e0799a75aadaf41ddda3d0038896" + "da966b1a67ff4e6c7403debfdbe7d1d48f1a3304124f04c974bfa0eff4d0" + "b1733a84aa6f89ec74c89dad2168da4706f6dfcfd980502b573d0f7b3791" + "252cc918394e8b3a3e1ef37ce48b7fd6a2040db5915f55809f284ce4ec24" + "4149f53038b432964705e26c3bb6535461b7fff27ac8eff679dce8e5bfe1" + "d000b69a22d9efc1f310ba2f0115c96b00bc15888fbb3edd230834458491" + "eede2440550dd59c613dc8433efe979c71e9"), + "ksida5d27d7b0ccd433203e157", + a2bs_hex("1be7cd47cefdef69576348ef9a143be2311041a5f80259938fa886139679" + "4eabcc985a695be2ef4a8361d86979859c490922d92d3ed0484e1666270a" + "a96388bf6be3c4f4f0b7e2f59efc6b8e965d8fadd5ab86b2bb816d2573ec" + "36eb42b571297681be152d40639d"), + 0, + }, a2bs_hex( - "7290396E183156BDF830B7BF31BA762CB2675528C9004FD24A61DAFB587ABCF1D36F8" - "7795EE0B3DA0B425616A66C82349B2E3BB8841C1335536865F919ED2AE671487B608B" - "21A362D888E0AB4F7AB7175B82F108617C3503F175435788AECAF7FFBFE76995D93CD" - "79424A843A247A8D8A6054A5B5404C9C057AACAD91A203229"), + "0ADA11080310012AD3110A9A070A20B8E7F26B6B8B59BABF05B5A1F8927B412A85BC8" + "551A928F00856329814AE5A821280024463DC57079C27E34AE115C6F65B08F6311C4E" + "A604A6512C42470B6F692A76EA769D60D0B6BCF8D565EF31EB925F38E2095039C9F2F" + "113ECEE020F1126EB30165372D538B551EBD7BAE5CF0BBEEBB3CDB6F180D42868051A" + "AB8FF4947460DD96F0F8259FC6001059C998D2EB6902C064F9AE08E6CD3C7807E5037" + "9507B41620D15DD76C0B1E7ED9417EFD6825959B5077F464E6429A4DEE467A1BA2B05" + "D38049912D5539F1EE9F5D8A569AA1C384384F847ED64F6FFC101036DA70E69C06E49" + "16493E82E9FE3F65D85254C8C14F6CA0579BFB3EAA86B2D7BB5FF572ECCFD70F2EA46" + "95F326BEADF241AE4311E428C7C12A0D4D1915CD0537FF0F62CF13EB2FA21A8004BBE" + "6B4B60DA9D9BC34DCC8502FB81D8FD5FDBC8FA89605C86205F2B8C6530FF64C8C31F5" + "79BD8ECA603DFD5E397AC35E48931FD330351D01361BB31CAAA7DBF816A6144A12B6C" + "22D1DCEBA20669ED635A40831066ABD8071342119D7DA11C43696B2898D3DF3B36BEB" + "8DA013D9DC145343494B19D6DA085F4A41E421D3DEF2AD8B72DFFFFB6E79BBCEAF859" + "4045D16A62EED16904A3569860C531A32EAA5ABB868B1DD6A0B03D69C1A3F8336AF80" + "EB80BADBBC7B80CA5943BD5B374302147052201FAED30E9FFA99FC00B47F7EEB46951" + "2A413E873F91D959CCCACCCD3585B7F00ED8D4685022101713C3ADC439F27512A4592" + "6C1D2473477662C4BACE72F380D105DDC9F7BE49ED71991B3D9E29A2038201373F98A" + "845A57624A692F44EBD316D26C48FEE82B655583317ECA4AAA4DAC841524A2DCA1117" + "49629637EF29FA7E72645A875957FB3D98A5E6C8065B1349CFA23011CD6349D911C53" + "5475FED50BE9EACB6A1FF3EA7458823F0229F2FA90B7A7099E8EC349D3D0FE0277CBA" + "5157CA62C8FBAA893F37B8C8CEA2A0D2D2912CACCF92D31AA17439479711B4A5B7744" + "5CC02C18BFE0195CE8F1FE59E317214005CEE5E25904C9FB0AF7E2B6B4DCCDF78E61E" + "179A9F93996EC3C76F6DA9B5A291BF08A73032B37EDCBBBDD20CFF94088A489167C56" + "E5E75B376874E9750212FE94D7656D9CD835DB3B771BA5B58D2B255221C6B73696438" + "35346338613630613561353437653132326332346663612A507D2B905E5EAFD4B28AE" + "EB7633283579E48ADD21A68EB26CC8C3B2E344579003B12A38554336305525FA6AB70" + "F024A18C73631BB1531ECA3F0782C72DBA017311B3F1E98C739632E305E4BC0B2561A" + "E2B30050AC1050A1B5D637BE37A9722AA35C23D346470851ACA7D2EDCD1A27EDF124E" + "A612C001BC96D6878E3086C33624821F1F3ECE23F27E58222C2BB8D1615476A117926" + "3B58F6427E92911D961FC7A3AFD947AED8C9AEAD1F08457925D2CE4E0F618B21942BA" + "A60B231EAE864048F94F74FFA700E5777F812ADB6F0CB6BA6F0D145E3951191EB2171" + "40C32F2C7565053222131FF823BC36D80B24B561CCBEA9D397FE00942E7FF73B8152C" + "DC083B63A9F9C4A77056A0D79F44F267DA0ED629D9C902F7E838957EA41AA442221C3" + "AA9410DB58302B468C6D7F2113663809F0DCF187C108CED1AD402F6FB3693413CC1D7" + "D5E3459B856E4156C78F8D85D548939FD00474C8CDEDC46835CC981758500FE61CC79" + "383B4D9F87C3E33D19C2D25D7D15DD0F3D2B1AF4583B71E90C59886D297E78E929C2F" + "3840C82C626914A4EB537B3A5161D963472B6592C0FA1E415556BC009C2DA22BCF743" + "AC434E22F8A33B43210DFD8AA09FE86105610F366E6FB7DA18996CF7C7DB425A9BB50" + "E4A13190A680B9F82D37D09658585ABE3BF9F009A5C1CE38A7CEFE17F71FB402768B2" + "D66B4CA523ED06729349695D7864D7CF7A1CC11D0DA2B8A43DB834D10B47D9579EC9E" + "46986A133277B92C636CB2A6A823AFE73317266C9C0601DDBADB76E1D254D6183B93A" + "1EA91A7E6C567331B3EE3A5AB1484AF91FD0F8DAC5FD980A67D8F33CC1D6CF20EE4C2" + "4582D03967ED48B6F28E7514E4D18F38C8CB1E54FBA59AF7D6A79C6C5A7AB06BAAC96" + "4C7958D201910ADCA018022FBEB8535B64F5CE83D3C22246B73696432663265383563" + "653861363737663630303437643730323465303762356165362A60B74880FBDDC5BB9" + "DB82F09BC7DE3FFD95A0A671B979D4C1F0564EAF63EB6B5A8C3F16D9F964AFBD011E2" + "326F9C27AFBE74536F3F0601A71D9C1C422F335611BF3BF1A1C89E2DEA27C17A9D9A5" + "8A74121E840B002E8A6FB59007245BE786C1F6430090AEF040A1D1FBF0A1D2432805A" + "0F8292FF627A9A7C60B733A51B365892C832261D7112C0011AD116A26F423C7019FA8" + "DCA226C2D2BDEEC91BEB1FD38D6890E32745A4DBB9409B65FE834C2522D92621B265A" + "9D526B4FCADCACF4C4DEB364661118494FD1561621392BF4450E6833BE290D49E59E6" + "65A031375EE56AD1F3392436BA213ABC5AC10A199E73123F84F7644282137DA24CBDE" + "30C10A6EB847CA72B8B311AD329D2C9CB0909C2ECBE3FBAF88E81BB5AEAA6480FFF67" + "E8777FA00C783AA160F1E211CB9BF3835FA8F82923C05895C359CF306F5CB90A73B8C" + "E2CE9ED210485E1C571A82020BF120627D01690D14321FA967D81997B959B35ED7745" + "DEE9E885DD402DF83C3B8F52999B16C2D1D47BF4724A9CED984175EB8A032D613294C" + "14802074154C34FD40FE6EA74FA830FDCB9CC7E0799A75AADAF41DDDA3D0038896DA9" + "66B1A67FF4E6C7403DEBFDBE7D1D48F1A3304124F04C974BFA0EFF4D0B1733A84AA6F" + "89EC74C89DAD2168DA4706F6DFCFD980502B573D0F7B3791252CC918394E8B3A3E1EF" + "37CE48B7FD6A2040DB5915F55809F284CE4EC244149F53038B432964705E26C3BB653" + "5461B7FFF27AC8EFF679DCE8E5BFE1D000B69A22D9EFC1F310BA2F0115C96B00BC158" + "88FBB3EDD230834458491EEDE2440550DD59C613DC8433EFE979C71E9221A6B736964" + "613564323764376230636364343333323033653135372A681BE7CD47CEFDEF6957634" + "8EF9A143BE2311041A5F80259938FA8861396794EABCC985A695BE2EF4A8361D86979" + "859C490922D92D3ED0484E1666270AA96388BF6BE3C4F4F0B7E2F59EFC6B8E965D8FA" + "DD5AB86B2BB816D2573EC36EB42B571297681BE152D40639D3000122076CFC9DBA6CD" + "93FFC6BB74D61C1B644CC32121553C50817A9F6F00633575E659")}, + // test vector 7, app id: "app_2", usage entry 2 + {"app_2", + { + a2bs_hex("8f922e955b269458ed1345bde9a24516520a536817e8e8612154a1"), + a2bs_hex("d4acc596a52055cee710e1fec44796dbf3ae6b017ab156d9bff7bfdb8f1e" + "6352bfbe453034968f940c36ac18800e22bb2ff71268053702ef3fce3fb2" + "d607a078e0d1449fcc9d0675d41b1a65f78e3c02370d18112aae1e2577ff" + "9087825a45125db5dee8e27bd14ea8666b4e8e6aba6811c40b585aabb9c9" + "185209a48d11130ff690316916961f28286c71c3e985d7dc3352166e414b" + "89da2c17cc5b69fc9c00990697f5"), + a2bs_hex("169d3c432f9c2f8b99e11632bd7d6a63f3d57679c567bedcb2e596ace105" + "0453732040cb468e9c43f6009b430ca4a4046d017e67a4badd5b71c0c9fc" + "e2274817f0bcda311a4f8703e6dc32aedf30e6f9abd40e249fc8b0a5045c" + "c1e47e60a60b4893ef92602f5584e1162f4ff3ee6d906228f97b442ace1f" + "b175d113b671bdbe4ceffdd98f2bb094c0dfac03b79541a44d8affdc987f" + "4268706b5a554e998907eb7126e8c6bc07c837d8aeebea3249e37b4b7dd7" + "327300fe7e62c15981cf73a13e806d065bcadc2c747256907a5493592b07" + "a0c07f9cd805fcdc0d30f70e4c4b2959a0f52385c6bd3e6eeb4e3d81fdc1" + "a9dc3c76faf1bfed913d58567fa9b296d27dff5217c583e7c134a642601f" + "8237"), + "kside684918d6c39bfa652a40ad936", + a2bs_hex("703f69807c8f4d140168874b924a625132eb3b896a381d617b8fb83c7314" + "a6b634d840925f711ae330599f0e0863800902b05d201a8a87b88a4bc170" + "65a1a8a556c34bf86b53afcc9951be15bea9ab55"), + 27, + }, a2bs_hex( - "3478A2D76DEB90BE713B03A11037EA7C305D1AF65099E3F2B92C4D4443A8F481C1177" - "DEF0A3CB49BA5F1448A10AF1207AD2D361B4A1F961B4B1F215B76A9A5005B414EF45E" - "AFBCF2636ABFC01413B27DD11871103579F8C041A799E22888D9ADB798E92A5E29BC4" - "6DECBC90991C65FE151C49F18068C1B65D0E90A9ECDA9248B87C120D5FD8EC81D4D36" - "B529FB2DAD39E0D39578B13B158E2B07C752D86F1A9D8160C93930C1F4F9E1D0D8E2C" - "5AB308732EB27722A6BF8BE852624C2BE3E4FE85819B89BEBA6535FCFBE85FA63A57B" - "D0FBAF284C64FFD97A146B76B3F37B576FC091C03E2222FBD24C2211344B7E2417EFC" - "36C4A54DCCC460CF810E7EA8AC6386D6AB567C819FED88A22CE55EF9BBE62C2CBC7AE" - "EDE5E5A69FF3472418CE2F4514496C59D26E72F3BFE0131F"), + "0AB60E080310012AAF0E0ADC040A1E9212A6926F21C6727C1EE89D5607047A1636F20" + "6F70E21FDA86E01B6A4B512A401EF947ABED64078EDF5B21FE6D3FB65384595D63A6D" + "03E4D1D397C5019DEEB6890D3EF8773002B91E255AF0820FB594069DF55D8ABF96498" + "E493F5C70F6B85F50E12A1ED3C039AD0CD838FE44D3FA9E2BBDDEB2919041203111ED" + "7778701B04D6B15F41D0BDE799E20A38B27BF96FDBE844F10364BAEB593596220993C" + "608AC793DE76C237CA350931A7E216538074DBD83DDF262D9F18ACD91E1EA5372F7E7" + "73C5B643331A9A027709721B3AA48597E88C99E82EAF7DFF07E87E0318D9D7CEC2909" + "6EC591826AA7A359316D6DE1D1329B408543E237DE84C986987EAD1BB6A0C38817E93" + "013E5C989D366F49590B834453EC64B7433BF0B3335B9E222BAD4CAF554D69575C585" + "95283166FEA42E89645FC7E2D3AC9E0C1399B096CF3FED1E5DEB1BC4E0EE894F0AE3F" + "929DD7DBA4530E5655EDBBF6041DF430482EB2E891B6A93AF84D3C16DBAD92733FFD3" + "4E8F4CE24506BEAD578D20CD3E291C2FC2F811DB875F49ABC21A24277D2BA474FE6AF" + "6C14021CFEAD5513E0999E094020CE08209BBC08F13FE2B96D7BA8213C8E9C85B6A62" + "3788D34DA794E17E4CD3BD65680B97FB30BAD64DDC42B1BCFB0B83E5DDA3501A5902C" + "A609F41837A0D5CD096E0659B67C221A6B73696436326438386564376232393232313" + "7623032333862652A585422463FD2E4DD47626E97DD6B4EE0B89523AAEBE8D11E7E7B" + "E703EF01E49B17EAF020CEDE0A9E0E7B5D91E4DB7ABDCE445936CB2DEECDEFEFDB14B" + "78F67B7CA5C733C9E88446FD814584584B86BECBF6EB2B0E3D5603E8B30190AFF040A" + "1D831FAD51E52A403524539EAB6A1B201E46674CA3B9167B1C1B53F5E5E312AC0136D" + "83ACBC5E4ED027ED583E3B2169D98F4ABEDDA15B781408E68EFA14FEFA9F3F0309BCB" + "5A9FFF6580636EBE3548E5ACB43B76CFEB29A9C86324E62AEB40556005C6686E718F9" + "BF61B0681D43B5B1E88084B3AEA27A6B0E844E5500B6FCFACF2EE44D6AF7F64154AB3" + "FD4FBD0B8056CF63971076A1EB3642B78D5E76B84F4ED9F6220089863F8A4911691E7" + "9FEFFC9F804C4C36C7F85E45B1D276C85875875267EB65DA70FD2D5E9176D69141AAC" + "02317BD7063BFB9FAE1B2E46F4CF15B7BC8C92517FF5C32CBB52AE4B67AFC5D569CB6" + "6A462DEF7A18A7D0ACEBF9F6E8A604356ADE2C81450C5466A472890B03EEFCF65388F" + "060E24551C67B7D46AE5D4D841D5CC63D137FD543FAE2C771756590B90E480CA0126F" + "1FC0090ACE62499E47569FC52196C788F80139755BDF12A7ACB29FD6E23A46A4C036F" + "04FF1ED6CD714094253BF1C58762C93F0DDF8A73C4BE927FFEC2723A16D8FFE512885" + "1F58537461275F6AA1976E3B399B7243919207E040EC16C5328E8AB082278FCE0E5D3" + "DF5C5F92DBA51FA6613587D4ECE31F2C001B49BFAED434F9512E895C2E09C88DDBF18" + "4BFAFE4D82E5D05A26AC06CDE29FAF6AB05B96685649C923779CE5EF7F316531ADA8E" + "74E45AB1DC1D75648AA2DE052674728867E87639FF9B782A3322186B7369646531643" + "3306233336235356632646562343731362A64D44A9D70A7C582559F089B1C0FDFCBDA" + "F5E26B672FCA5D58E889B407A0BA8599079CDE11FADFAB23AA1B97622839F3B7E1A96" + "F8332BEC5FBCBC9EB64FD5ED05887B8FA3BFD6ECC7BC91E621342732062D2F4411B76" + "3E20328AF6F8EF5030E2F8027AEF9E30060ACB040A1B8F922E955B269458ED1345BDE" + "9A24516520A536817E8E8612154A112A401D4ACC596A52055CEE710E1FEC44796DBF3" + "AE6B017AB156D9BFF7BFDB8F1E6352BFBE453034968F940C36AC18800E22BB2FF7126" + "8053702EF3FCE3FB2D607A078E0D1449FCC9D0675D41B1A65F78E3C02370D18112AAE" + "1E2577FF9087825A45125DB5DEE8E27BD14EA8666B4E8E6ABA6811C40B585AABB9C91" + "85209A48D11130FF690316916961F28286C71C3E985D7DC3352166E414B89DA2C17CC" + "5B69FC9C00990697F51A9002169D3C432F9C2F8B99E11632BD7D6A63F3D57679C567B" + "EDCB2E596ACE1050453732040CB468E9C43F6009B430CA4A4046D017E67A4BADD5B71" + "C0C9FCE2274817F0BCDA311A4F8703E6DC32AEDF30E6F9ABD40E249FC8B0A5045CC1E" + "47E60A60B4893EF92602F5584E1162F4FF3EE6D906228F97B442ACE1FB175D113B671" + "BDBE4CEFFDD98F2BB094C0DFAC03B79541A44D8AFFDC987F4268706B5A554E998907E" + "B7126E8C6BC07C837D8AEEBEA3249E37B4B7DD7327300FE7E62C15981CF73A13E806D" + "065BCADC2C747256907A5493592B07A0C07F9CD805FCDC0D30F70E4C4B2959A0F5238" + "5C6BD3E6EEB4E3D81FDC1A9DC3C76FAF1BFED913D58567FA9B296D27DFF5217C583E7" + "C134A642601F8237221E6B73696465363834393138643663333962666136353261343" + "061643933362A50703F69807C8F4D140168874B924A625132EB3B896A381D617B8FB8" + "3C7314A6B634D840925F711AE330599F0E0863800902B05D201A8A87B88A4BC17065A" + "1A8A556C34BF86B53AFCC9951BE15BEA9AB55301B122002206F46D9D05740AD34B99F" + "10C21A2FA23B8E45DCB00713E32D5CECF239D0A8")}, + // test vector 8, app id: "app_1", usage entry 2 + {"app_1", + { + a2bs_hex("d0b9a07ad7ffeec13784bd60da011be3589f3e450227fd36b1a3f6786cdb" + "fe8f"), + a2bs_hex("a419c5687a592099dc67da8bc4f5ef238c80fe4ce3e2fcb025392efb1438" + "4b581b595a0e8fa95de637fb2184719eb36ad6539ee9df0f67697f91d018" + "6e04552e811196029cf4e256518ddf3215af8ec61442c17d6753b93f9d3a" + "9240bae39bacf5563659cf47d3a611ce20ed3ebbf86cddad60cc2847c459" + "5dcfd934d012ce205960052158461d7c5d480de2e597876e64e8f8de6928" + "29a3"), + a2bs_hex("f7c19357e50fc474437c1a635c5bae8f6f51afa20750766db19457dff7ae" + "f2cae78848a225cc6a088bbcffead5be6aab6fc8af091bf459c3bd9bcfa1" + "8de53ef76db1b4826cf0b8ff7b2d7c44bbadb3cd7aedd8f639d1f38c52a5" + "8611a9782aeace72be69a73d2e091a1120dc63f7ba6f1cb6cddd69e9a236" + "232ed8c14cee665756ba51f1d2e2530ab3662ce1b6efba91c5f10c53abc8" + "86d6f25b5dc40417e54270843f3b454c8c047fc366249e30379b0fbe0174" + "fcab8b8405ae7f20f6f2b81f11082ff0e270b75f1e1aa7ed5806f4e65b46" + "b872dbcb703d7bf20b9ecaa481425a5218d85a49595f3ed268d61f1be8e3" + "8e6126eb075fa6b7ae80431c8521c4bc2ce701e45d33bfca9a5b0b66b550" + "aab21eae41f84cadfd2517dee9a2c139ad475c387d25"), + "ksid321bb636f8a3f5cd5d54a236", + a2bs_hex("c3cb027611397b5d70cc0b08e0f5249cd19996da674e33722902173d45d7" + "09914a3d7e898d93170317bfcff34861c0d687048cc93542a75a2c99b232" + "3fafea1ee0c3e3d24edf2633"), + 7, + }, a2bs_hex( - "C45FDCB3296A0EBE24FF381E027E6E2EF1AC289C67D3B858330669A81E8131583D2F1" - "40FD64615BDED0ED8316ABFD9C7E887433E1CAA6EA8E0C4F87ADB2A7FC3CF6FF87A7F" - "02AFF03BF5DB640AD8DDB572C41532E673618DCD8C33EF2BFE4E25EE821DF7D742B09" - "90398543B16EFCDBB03C6327B79D3664CED442E894020F4410ECC178C92AAEDFE39DC" - "563AC226FE9E0EF22E1C896C4F2835CDFDCD50B6C4DBA2B27A3B65DE3963D0A5F6E44" - "2A3C32008AB9D1ACBE4F366990EB43F8EE213B71E98DA090282680ABDD649BECA8970" - "0764561379F1DD23490CE967632ECA349AF8E1CBFA1F3A4F39F453614C8FFB5A17975" - "6243CB1FDB515834229BC64917C47A2F2E1116FAAC13368015312C31FD41215106469" - "BEE77D0EF2FE10CF645B3E82902EAF53A676933D0EC433949C1833BE52E76602CC3E4" - "E784C002E20624BCE0F38F9CBC478439899DA7F15554D0ACADEC140C00C8FA8FC9886" - "2D9933938781B30CB9C76899B3A48DBF170DDA0A18ED37D77F048ABBC85CB19469638" - "C2A32AA3180CF3943BD6B8C5CB26F2EA70868F18B0707C882054141086997A1AE5B70" - "9D4D0AA2B358990F244BA76C8E40791D29A0C63C9EF620B97FDFFA9B671E5A65AFCC1" - "C94CAACE0443E9D91F14028935BEA3988831BEBBFD3EB7C3A5AC9605B3534712A0912" - "4345ACB09665E357E58946871BC140D365"), - a2bs_hex( - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" - "22232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"), - 14, - a2bs_hex( - "0ADF0E080210012AD80E0AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE" - "1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D" - "0DC6789817468974B2EA51EE3944B8D7E0A88E4F16EBB80F03BD845231A01E6146841" - "CBAEF0134DCD9300DB2D92732992C0F2310D8E386FB31C67B9477010DEF9D99C42725" - "89572A26A17E12AC021E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315D" - "B32B6D3FDD1A8E8A094174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E15" - "4BC1548FC40EC7092775531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6B" - "E37645E6800F053B1DA9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D" - "344A419C0F0034A1B5F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410" - "F218E52A853AD214FD05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3" - "BCBAE42DF9EA65E42E151827086EADE71C138B972CC3992CF9ADA944C063816352ED8" - "658D3FA07BE0F32239E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E5104" - "45294F44E511BD9B1AF19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E1AF" - "40340FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C0" - "29FD2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B" - "03772BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA99" - "1C8BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C59243" - "6C8B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2E" - "FC6780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A" - "6602B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F" - "4C35FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24" - "B0653A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6" - "374D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6F" - "B1AC91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB890" - "4A5999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267A" - "CA2E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82" - "989C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A" - "771F561B165987E552824B0C914E708E425C30AA9070A80017290396E183156BDF830" - "B7BF31BA762CB2675528C9004FD24A61DAFB587ABCF1D36F87795EE0B3DA0B425616A" - "66C82349B2E3BB8841C1335536865F919ED2AE671487B608B21A362D888E0AB4F7AB7" - "175B82F108617C3503F175435788AECAF7FFBFE76995D93CD79424A843A247A8D8A60" - "54A5B5404C9C057AACAD91A20322912AC023478A2D76DEB90BE713B03A11037EA7C30" - "5D1AF65099E3F2B92C4D4443A8F481C1177DEF0A3CB49BA5F1448A10AF1207AD2D361" - "B4A1F961B4B1F215B76A9A5005B414EF45EAFBCF2636ABFC01413B27DD11871103579" - "F8C041A799E22888D9ADB798E92A5E29BC46DECBC90991C65FE151C49F18068C1B65D" - "0E90A9ECDA9248B87C120D5FD8EC81D4D36B529FB2DAD39E0D39578B13B158E2B07C7" - "52D86F1A9D8160C93930C1F4F9E1D0D8E2C5AB308732EB27722A6BF8BE852624C2BE3" - "E4FE85819B89BEBA6535FCFBE85FA63A57BD0FBAF284C64FFD97A146B76B3F37B576F" - "C091C03E2222FBD24C2211344B7E2417EFC36C4A54DCCC460CF810E7EA8AC6386D6AB" - "567C819FED88A22CE55EF9BBE62C2CBC7AEEDE5E5A69FF3472418CE2F4514496C59D2" - "6E72F3BFE0131F1AF403C45FDCB3296A0EBE24FF381E027E6E2EF1AC289C67D3B8583" - "30669A81E8131583D2F140FD64615BDED0ED8316ABFD9C7E887433E1CAA6EA8E0C4F8" - "7ADB2A7FC3CF6FF87A7F02AFF03BF5DB640AD8DDB572C41532E673618DCD8C33EF2BF" - "E4E25EE821DF7D742B0990398543B16EFCDBB03C6327B79D3664CED442E894020F441" - "0ECC178C92AAEDFE39DC563AC226FE9E0EF22E1C896C4F2835CDFDCD50B6C4DBA2B27" - "A3B65DE3963D0A5F6E442A3C32008AB9D1ACBE4F366990EB43F8EE213B71E98DA0902" - "82680ABDD649BECA89700764561379F1DD23490CE967632ECA349AF8E1CBFA1F3A4F3" - "9F453614C8FFB5A179756243CB1FDB515834229BC64917C47A2F2E1116FAAC1336801" - "5312C31FD41215106469BEE77D0EF2FE10CF645B3E82902EAF53A676933D0EC433949" - "C1833BE52E76602CC3E4E784C002E20624BCE0F38F9CBC478439899DA7F15554D0ACA" - "DEC140C00C8FA8FC98862D9933938781B30CB9C76899B3A48DBF170DDA0A18ED37D77" - "F048ABBC85CB19469638C2A32AA3180CF3943BD6B8C5CB26F2EA70868F18B0707C882" - "054141086997A1AE5B709D4D0AA2B358990F244BA76C8E40791D29A0C63C9EF620B97" - "FDFFA9B671E5A65AFCC1C94CAACE0443E9D91F14028935BEA3988831BEBBFD3EB7C3A" - "5AC9605B3534712A09124345ACB09665E357E58946871BC140D3651220464E4A1BB23" - "1A5B0287888B34CA0A8CF5396EB2B8313377DC5ED5C41A9B389A9")}, - {// 3 usage info records - a2bs_hex( - "983358221FB8DBF892047F00AA661F217EEC4E7A1626E8F98E025509E4D65A685E7D9" - "B169B98B16934F6E43E0E0E854A3FA9EB8E9A9D08E9D9B3A6C766AA44F7C655879BA2" - "DF5F38732FB7EDCA66D8C13A855B15E32CC9389B7DD119BA1F2417825FF1F52970F8E" - "985D34DD353D2AC8B24267353E5B8406C098427C4559A90CC"), - a2bs_hex( - "483EAC68243092009D06FAB41DB594ACB22E068C9524810758ECFF8BAB7E1B1ACA988" - "C3987023F01EFEC11529C7326279742E805E755A08EBBD9AA322F305805BE1166AB45" - "CB156FB0A9E6734371F4028707EE01CF2FB08465707E7E5613DD90D74B0D02536E26C" - "F1261CDDA8713943F3620ECC54095C76F8CD3CE31948C3CC0C9EB5582A4D087A54B39" - "1B4CDCBC98E35830B5932F6CF8D16427EF115CFF0A99499513702DD54C758E53248BB" - "5D195F2A2DD1DB18F97562F1F9034E223CEDB1E09ED1B0FE26089C20ED43B5D87B51F" - "6FC6C9F86255FBF70DF233F2665D604355BF9740A3B755521102E0B485C5CCCA607A9" - "A1BEB757BEDEF12327C637D17D6401E3756719F99BBE69B9CE4C8E47C2AC771F35A8E" - "E3FC4D58B2B2269CF85728E4DA7231BC8F0FD7C50E2A1EE9"), - a2bs_hex( - "5826D3A95F78879292612BCE06D845D64285CD45A7EAA6C87A9DBC3290B0B6AC95315" - "809F8CC7938768F9BD342C62CD4CE055866394489D955247CB0535001D50EFF4FEDF0" - "9501C58569B1EB9AA2305A113A5F4D4524AD34148A2DC48D2F522937F44A57FC76F57" - "EB1D4819C438EA42C7F8974FC7D2FE61CAAB3E1F27172FE6B8675DF4CCF1329A6EFB3" - "1F686FB0DC0F8B552D78970708D50C82ADBE333B585F6DE5A0D01D106F8232EB9ED45" - "42A2DC5AA031CC44652E8A42EDCA5AB08B0B5CA61A922E69A119E556F6014642522EA" - "1550F6D6E63EB25ACC03A4DD3F22F4686ED525F994FABA87629AF5939C16BA68C0F09" - "3EFE033CD319180BF69FCB72AC5123EBCB9DCF1AF00F0A68E31FF5B18FA8CFF3DFBB7" - "DA45413799105D67FA78217710D2F6C33394DD4088100013295FF43CF0598E6FE5C05" - "F03417CCD031F01CF63BECD444C750DF198345F155AB2B2AB94394A3C0C0AE05E386D" - "E6CC565AE82398BD0E377D6ABE103B9D5E84582C3772584B759891FC4B121A113370E" - "2DF5372DD81FB6358C64B0F6EB8F26193CA119E4D9D3D38036FA450EE2047CB2CE265" - "0FF37DF85BE23D58C17379FEC08DC0648236A107AE66178EEBF78F05F3B898424FA02" - "668B51F838AFA90D367B5CB425372D8CC3790BEA8AFB8795251FA09340D85A7F0B003" - "134C838F08BB1054D18404C3F69130700E"), - a2bs_hex( - "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021" - "22232425262728292a2b2c2d2e2f"), - 19, - a2bs_hex( - "0A8B16080210012A84160AA9070A8001924B035FBDA56AE5EF0ED05A08DE7AECC8ABE" - "1835E0C4A548F7803937F4C3B4520EB7F3334FFCDFA00DE56408F09D5019FCE87072D" - "0DC6789817468974B2EA51EE3944B8D7E0A88E4F16EBB80F03BD845231A01E6146841" - "CBAEF0134DCD9300DB2D92732992C0F2310D8E386FB31C67B9477010DEF9D99C42725" - "89572A26A17E12AC021E6FFBE66FC6153E7749906EC8F684E819467E16CAF317F315D" - "B32B6D3FDD1A8E8A094174D92D063B88E4835EAB78BD09541EA7FE72F132EB7364E15" - "4BC1548FC40EC7092775531508C95F9ED5D76F36BC0C198C3A33A1F9415B343905D6B" - "E37645E6800F053B1DA9A20286EFCBBC320424ADF7FB6E3D5D8E86C35E576A1A2A37D" - "344A419C0F0034A1B5F767D3C61D90DCA1119E5024C34EDE8FA7DD128696D8C435410" - "F218E52A853AD214FD05D0F8B3CB4832CFCD97FE159E6DEE64CE82CDAEC0321AE71B3" - "BCBAE42DF9EA65E42E151827086EADE71C138B972CC3992CF9ADA944C063816352ED8" - "658D3FA07BE0F32239E74A65932B069AAC4E8386DB59154AF9AEF71448128C66E5104" - "45294F44E511BD9B1AF19D4D67E99363093BE888D4B2AB841CAFF252CAD13EDF8E1AF" - "40340FC62339728520E6C0C09907C26F3FB78287231661952A8B699E47AE241B999C0" - "29FD2067836DC4BC64F66998A3ECD197DAE36F808A2E5A4C5BF25DD580E52B1C39A8B" - "03772BF82D58929766F2DA04F0E616F92B3A0EB75661B8FF5DE1EB807C990F9E6BA99" - "1C8BAD5EB63B37E8663A4E22AA9DB2015D3DF8BED1C8313F85F13B9483C7A39C59243" - "6C8B13C23F78F55CE812795335059F7F527CA580306A0AEE5A6D957A91F498F64AA2E" - "FC6780716400E17C7EEA30B2E6523B902986995E003C2D919A7DC7C0122CE9410037A" - "6602B59A63B5C89473D4E02DE35C1F01B12ADB48A3D94D43693F08268FECCC78DAF6F" - "4C35FA32C538CD73FBF3CEA274B01179C02473486311956E5A0C78E44C59B2F34FF24" - "B0653A6379A2F5F6F51467CAE26D55CC5BBDCFC9BCFA7B8C5CBF82EBE7BD340C3DAE6" - "374D0692052C529AA33D7A6799C8F1F59C78575E51F707013026CC4F83F6B3328EE6F" - "B1AC91929A4491338E93D10EE6193014A73BA241A9A833EA835217894EB4FD4BDB890" - "4A5999928325D0AC31B6D58609EDD9D85E88F74B5BD6FA7BDD83C51EEB91633ED267A" - "CA2E103904BBE4C031A6483858FBAD74DACD01711F7B882749FFFBA0DB6C7D7109D82" - "989C7D4DB5A0F1E7506AC24C89CECAF231EFF99F96AD76E57DABDD3C2DFBA7BAA869A" - "771F561B165987E552824B0C914E708E425C30AA9070A80017290396E183156BDF830" - "B7BF31BA762CB2675528C9004FD24A61DAFB587ABCF1D36F87795EE0B3DA0B425616A" - "66C82349B2E3BB8841C1335536865F919ED2AE671487B608B21A362D888E0AB4F7AB7" - "175B82F108617C3503F175435788AECAF7FFBFE76995D93CD79424A843A247A8D8A60" - "54A5B5404C9C057AACAD91A20322912AC023478A2D76DEB90BE713B03A11037EA7C30" - "5D1AF65099E3F2B92C4D4443A8F481C1177DEF0A3CB49BA5F1448A10AF1207AD2D361" - "B4A1F961B4B1F215B76A9A5005B414EF45EAFBCF2636ABFC01413B27DD11871103579" - "F8C041A799E22888D9ADB798E92A5E29BC46DECBC90991C65FE151C49F18068C1B65D" - "0E90A9ECDA9248B87C120D5FD8EC81D4D36B529FB2DAD39E0D39578B13B158E2B07C7" - "52D86F1A9D8160C93930C1F4F9E1D0D8E2C5AB308732EB27722A6BF8BE852624C2BE3" - "E4FE85819B89BEBA6535FCFBE85FA63A57BD0FBAF284C64FFD97A146B76B3F37B576F" - "C091C03E2222FBD24C2211344B7E2417EFC36C4A54DCCC460CF810E7EA8AC6386D6AB" - "567C819FED88A22CE55EF9BBE62C2CBC7AEEDE5E5A69FF3472418CE2F4514496C59D2" - "6E72F3BFE0131F1AF403C45FDCB3296A0EBE24FF381E027E6E2EF1AC289C67D3B8583" - "30669A81E8131583D2F140FD64615BDED0ED8316ABFD9C7E887433E1CAA6EA8E0C4F8" - "7ADB2A7FC3CF6FF87A7F02AFF03BF5DB640AD8DDB572C41532E673618DCD8C33EF2BF" - "E4E25EE821DF7D742B0990398543B16EFCDBB03C6327B79D3664CED442E894020F441" - "0ECC178C92AAEDFE39DC563AC226FE9E0EF22E1C896C4F2835CDFDCD50B6C4DBA2B27" - "A3B65DE3963D0A5F6E442A3C32008AB9D1ACBE4F366990EB43F8EE213B71E98DA0902" - "82680ABDD649BECA89700764561379F1DD23490CE967632ECA349AF8E1CBFA1F3A4F3" - "9F453614C8FFB5A179756243CB1FDB515834229BC64917C47A2F2E1116FAAC1336801" - "5312C31FD41215106469BEE77D0EF2FE10CF645B3E82902EAF53A676933D0EC433949" - "C1833BE52E76602CC3E4E784C002E20624BCE0F38F9CBC478439899DA7F15554D0ACA" - "DEC140C00C8FA8FC98862D9933938781B30CB9C76899B3A48DBF170DDA0A18ED37D77" - "F048ABBC85CB19469638C2A32AA3180CF3943BD6B8C5CB26F2EA70868F18B0707C882" - "054141086997A1AE5B709D4D0AA2B358990F244BA76C8E40791D29A0C63C9EF620B97" - "FDFFA9B671E5A65AFCC1C94CAACE0443E9D91F14028935BEA3988831BEBBFD3EB7C3A" - "5AC9605B3534712A09124345ACB09665E357E58946871BC140D3650AA9070A8001983" - "358221FB8DBF892047F00AA661F217EEC4E7A1626E8F98E025509E4D65A685E7D9B16" - "9B98B16934F6E43E0E0E854A3FA9EB8E9A9D08E9D9B3A6C766AA44F7C655879BA2DF5" - "F38732FB7EDCA66D8C13A855B15E32CC9389B7DD119BA1F2417825FF1F52970F8E985" - "D34DD353D2AC8B24267353E5B8406C098427C4559A90CC12AC02483EAC68243092009" - "D06FAB41DB594ACB22E068C9524810758ECFF8BAB7E1B1ACA988C3987023F01EFEC11" - "529C7326279742E805E755A08EBBD9AA322F305805BE1166AB45CB156FB0A9E673437" - "1F4028707EE01CF2FB08465707E7E5613DD90D74B0D02536E26CF1261CDDA8713943F" - "3620ECC54095C76F8CD3CE31948C3CC0C9EB5582A4D087A54B391B4CDCBC98E35830B" - "5932F6CF8D16427EF115CFF0A99499513702DD54C758E53248BB5D195F2A2DD1DB18F" - "97562F1F9034E223CEDB1E09ED1B0FE26089C20ED43B5D87B51F6FC6C9F86255FBF70" - "DF233F2665D604355BF9740A3B755521102E0B485C5CCCA607A9A1BEB757BEDEF1232" - "7C637D17D6401E3756719F99BBE69B9CE4C8E47C2AC771F35A8EE3FC4D58B2B2269CF" - "85728E4DA7231BC8F0FD7C50E2A1EE91AF4035826D3A95F78879292612BCE06D845D6" - "4285CD45A7EAA6C87A9DBC3290B0B6AC95315809F8CC7938768F9BD342C62CD4CE055" - "866394489D955247CB0535001D50EFF4FEDF09501C58569B1EB9AA2305A113A5F4D45" - "24AD34148A2DC48D2F522937F44A57FC76F57EB1D4819C438EA42C7F8974FC7D2FE61" - "CAAB3E1F27172FE6B8675DF4CCF1329A6EFB31F686FB0DC0F8B552D78970708D50C82" - "ADBE333B585F6DE5A0D01D106F8232EB9ED4542A2DC5AA031CC44652E8A42EDCA5AB0" - "8B0B5CA61A922E69A119E556F6014642522EA1550F6D6E63EB25ACC03A4DD3F22F468" - "6ED525F994FABA87629AF5939C16BA68C0F093EFE033CD319180BF69FCB72AC5123EB" - "CB9DCF1AF00F0A68E31FF5B18FA8CFF3DFBB7DA45413799105D67FA78217710D2F6C3" - "3394DD4088100013295FF43CF0598E6FE5C05F03417CCD031F01CF63BECD444C750DF" - "198345F155AB2B2AB94394A3C0C0AE05E386DE6CC565AE82398BD0E377D6ABE103B9D" - "5E84582C3772584B759891FC4B121A113370E2DF5372DD81FB6358C64B0F6EB8F2619" - "3CA119E4D9D3D38036FA450EE2047CB2CE2650FF37DF85BE23D58C17379FEC08DC064" - "8236A107AE66178EEBF78F05F3B898424FA02668B51F838AFA90D367B5CB425372D8C" - "C3790BEA8AFB8795251FA09340D85A7F0B003134C838F08BB1054D18404C3F6913070" - "0E12202FF1FBA9926A24A1F79970EC427DDF87B4421488F7952499BC33CEB282D9E48" - "A")}}; + "0ABD0E080310012AB60E0AEA040A20BB3370CCD3C3C49573D6B74386D1886D9888BD8" + "1FE3241BCD2BAC9407D1A834E12C001DC0E51CFA5863F6C0B32A4AD7FA40625DADCC2" + "DCDE9E7FA3983B8804D9966803181682FC8AE831472E0B2FC26276242FBCE624D286E" + "EDECCE5555804913B4F8F86C5AE86160B8434B109169A63DA04C5265102D772C11805" + "43EF226D2140357ACA6CF87DA3F7E370DFC08CA92A1F7C7D314EAB36292A91708F6C6" + "AD84B37EE1C7DFAFB99289206CB752D063F330EFD85885F4B72BA1CA5823EED865A46" + "1345E3D6417872BF3B0608B3D9E1004C11E7326D3ED406192E13455D0EC4E1F558A14" + "71A8002F42A68CA3A14FB68F5992E4519F57970C3DAE73F8DA1D5B0B1DA3EFF7A9540" + "12A0DC634357F3F5477A820E182182F24AE8E835AB10C18386CC8A0727D3F38B62863" + "9BFBD69A94D4053EAB1C31E075E014CC578B226CFE24D6B42DB242972DEF8F23A4AAE" + "88451307C2ABAF54C1803AE54E3F1149AA6E6D4288CC7D474E876BE07954E8B2DEFF4" + "ADE4BF30229FB6C92DF4D66CD463F686B4754B940210EB59F1581D658DDF8DE8389E0" + "E2D123E2CAE3C2BE6EB1948CCC896DD4CDF45F9090C96DFB925795CFB4CCDA83E3EB4" + "F745577B17FC166BF5F4103C9085134CAD7863A41B04F32EF20201E54B55F1817CE58" + "9619B096C254FD2C2FA4A06F4DE35CCFD23E221C6B736964653131313039626632306" + "3646535343430383365663465652A60EA106C124476B753D39368A5966972A2729BB8" + "BBEA734A2B3E812B705EACE016C8A03C9A406094D80059EF4CA26F1928FA2DAA5DE9A" + "6F22372E5C7A941E610D1EFB56ED7CE2228A70E2E150AFB66EDC2DA066D463AA90BA0" + "CAFF078FBFEC05C830000AF5040A21EACE80E30BFDA213F1CE4DBCFD9D4D24B8E2AE0" + "0054D167D9D7AE99547062B911312B40168A7665A21348FC0590328608DC520BE40F5" + "B749328568FE383EF69C1A587AB2446CF9C41D821373D0856A883B316519A42218F80" + "E7BD5764D16BAC9A9B427A7278F5940E563FCF6DEE0FF3AADBB702EBF2C54EC354AE7" + "ACC84EE6A54BCA1F30E38EF71C44A81D0009B1484FEAF4F1A56F58C35BB2372C80C6D" + "FB389E6DE60BDD3D46C03975715260F6FDBE42FACB64C22EDA9635C04DA79434E1C41" + "FBD2FDBBAB6598283226C0278E8E0A96D780D3436523EFD11AFA01FF6FECF71578288" + "12A2D6DCB15383A6D9AF4519EF804C6053A10C436002DE3A4EFCC017755F4AD1101BD" + "C813E2D211732418DEE529CBB413C48AA5884C76A5C6F556A715055560D4247F5BF31" + "0956949A3A171A4AA608A48446884E7676D558FF64D392B84E617805693D90F1E9B7B" + "540C383D384D7F7CE06C23618681BD838CEB1A514047F1C562C43159CC5E21588FBFC" + "E8A354111160F1A1E2BD3D798A000579BDFDB977252809EE1502DF8045972FE8AAC84" + "0211C2F8D9E4D5BE18509C327C647D654C4B6CC430B98F1FF37C96FAB087FB561B8CC" + "18480F877C873594D3148FF74B0E3C6327C27CA876DAE7422398FC5E85269CBA49AD0" + "99221C6B7369643865383033353063626566363436336130303235653663632A7C7CC" + "C7CE96055E16A52FA192EA2CF3C9DF3E89B9133A52286F71E6C6D82D0435F6B2155DF" + "DE590B347D8C86F62D7DFBAAE640C237256F609E5DA9CC6C103465FE3441612BBDFDF" + "4D1C24B2147FEB8565CEF4993E439C9D564A39A4AC5BB1DA69ACB44DA06E4522C9A93" + "D310CDDA5DAC1E1E0B91ABFF41E4E2EDDA400130070ACE040A20D0B9A07AD7FFEEC13" + "784BD60DA011BE3589F3E450227FD36B1A3F6786CDBFE8F129801A419C5687A592099" + "DC67DA8BC4F5EF238C80FE4CE3E2FCB025392EFB14384B581B595A0E8FA95DE637FB2" + "184719EB36AD6539EE9DF0F67697F91D0186E04552E811196029CF4E256518DDF3215" + "AF8EC61442C17D6753B93F9D3A9240BAE39BACF5563659CF47D3A611CE20ED3EBBF86" + "CDDAD60CC2847C4595DCFD934D012CE205960052158461D7C5D480DE2E597876E64E8" + "F8DE692829A31AA402F7C19357E50FC474437C1A635C5BAE8F6F51AFA20750766DB19" + "457DFF7AEF2CAE78848A225CC6A088BBCFFEAD5BE6AAB6FC8AF091BF459C3BD9BCFA1" + "8DE53EF76DB1B4826CF0B8FF7B2D7C44BBADB3CD7AEDD8F639D1F38C52A58611A9782" + "AEACE72BE69A73D2E091A1120DC63F7BA6F1CB6CDDD69E9A236232ED8C14CEE665756" + "BA51F1D2E2530AB3662CE1B6EFBA91C5F10C53ABC886D6F25B5DC40417E54270843F3" + "B454C8C047FC366249E30379B0FBE0174FCAB8B8405AE7F20F6F2B81F11082FF0E270" + "B75F1E1AA7ED5806F4E65B46B872DBCB703D7BF20B9ECAA481425A5218D85A49595F3" + "ED268D61F1BE8E38E6126EB075FA6B7AE80431C8521C4BC2CE701E45D33BFCA9A5B0B" + "66B550AAB21EAE41F84CADFD2517DEE9A2C139AD475C387D25221C6B7369643332316" + "262363336663861336635636435643534613233362A48C3CB027611397B5D70CC0B08" + "E0F5249CD19996DA674E33722902173D45D709914A3D7E898D93170317BFCFF34861C" + "0D687048CC93542A75A2C99B2323FAFEA1EE0C3E3D24EDF263330071220B174821B32" + "5B0A6A900AD8C660C755D3B0273CA6E81D70E2C548CDEC07BE53FA")}, +}; + +DeviceFiles::CdmUsageData kUsageInfoUpdateTestData = { + a2bs_hex("b8e7f26b6b83d6b74386d1886d9888bd81fe3241bca928f09407329814ae" + "5a82"), + a2bs_hex("4463dc57079c27e34ae115c6f65b08f6311c4ea604a6512c42470b6f692a" + "6803181682fc8ae831472e0b2fc26276242fbce624d286eedecce5555804" + "913b4f8f86c5ae86160b8434b109169a63da04c5265102d772c1180543ef" + "226d2140357aca6cf87da3f7e370dfc08ca92a1f7c7d314eab36292a9170" + "26eb30165372d538b551ebd7bae5cf0bbeebb3cdb6f180d42868051aab8f" + "e50379507b41620d15dd76c0b1e7ed9417efd6825959b5077f464e6429a4" + "6ffc101036da70e69c06e4916493e82e9fe3f65d85254c8c14f6ca0579bf" + "2a0d4d1915cd0537ff0f62cf13eb2fa2"), + a2bs_hex("bbe6b4b60da9d9bc34dcc8502fb81d8fd5fdbc8fa89605c86205f2b8c6530ff64" + "c84012a0dc634357f3f5477a820e182182f24ae8e835ab10c18386cc8a0727816" + "a6144a12b6c22d1dceba20669ed635a40831066abd8071342119d7da11c43696b" + "289d3f38b628639bfbd69a94d4053eab1c31e075e014cc578b226cfe24d6b4272" + "dffffb6e79bbceaf8594045d16a62eed16904a3569860c531a32eaa5abb868b1d" + "d6adb242972def8f23a4aae88451307c2abaf54c1803ae54e3f1149aa6e6d42ae" + "d30e9ffa99fc00b47f7eeb469512a413e873f91d959cccacccd3585b7f00ed8d4" + "685022101713c3adc439f27512a45926c1d2473477662c4bace72f380d105ddc9" + "f88cc7d474e876be07954e8b2deff4ade4bf30229fb6c92df4d66cd463f6848fe" + "e82b655583317eca4aaa4dac841524a2dca111749629637ef29fa7e72645a8759" + "57fb6b4754b940210eb59f1581d658ddf8de8389e0e2d123e2cae3c2be6eb1943" + "ea7458823f0229f2fa90b7a7099e8ec349d3d0fe0277cba5157ca62c8fbaa893f" + "37b8c8cea2a0d2d2912caccf92d31aa17439479711b4a5b77445cc02c18bfe019" + "5ce8ccc896dd4cdf45f9090c96dfb925795cfb4ccda83e3eb4f745577b17fc199" + "6ec66bf5f4103c9085134cad7863a41b04f32ef20201e54b55f1817ce5896195b" + "376874e9750212fe94d7656d9cd835db3b771ba5b58d2b255"), + "ksid854c89bf20cde54122c24fca", + a2bs_hex("7d2b905e368a5966972a2729bb8bbea734a2b21a68eb26cc8c3b2e344579" + "003b12a3855016c8a03c9a406094d80059ef4ca26f1928fa2a3f0782c72d" + "ba0e2228a70e2e150afb66e305e4bc0b2561ae2b"), + 6, +}; struct HlsAttributesInfo { std::string key_set_id; @@ -1655,6 +2053,10 @@ class DeviceFilesSecurityLevelTest : public DeviceFilesTest, public ::testing::WithParamInterface {}; +class DeviceFilesUsageInfoListTest + : public DeviceFilesTest, + public ::testing::WithParamInterface {}; + class DeviceFilesUsageInfoTest : public DeviceFilesTest, public ::testing::WithParamInterface {}; @@ -2218,215 +2620,304 @@ TEST_F(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem) { } } -TEST_P(DeviceFilesUsageInfoTest, Read) { +TEST_F(DeviceFilesUsageInfoTest, ListNullParam) { + MockFileSystem file_system; + MockFile file; + + DeviceFiles device_files(&file_system); + EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); + EXPECT_FALSE(device_files.ListUsageInfoFiles(NULL)); +} + +TEST_P(DeviceFilesUsageInfoListTest, UsageInfoList) { MockFileSystem file_system; MockFile file; - std::string app_id; // TODO(fredgc): add tests with multiple app_ids. - std::string path = - device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id); int index = GetParam(); - std::string data; - if (index >= 0) { - data = kUsageInfoTestData[index].file_data; - } - if (index >= 0) { - EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true)); - EXPECT_CALL(file_system, FileSize(StrEq(path))) - .WillRepeatedly(Return(data.size())); - EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); - EXPECT_CALL(file, Read(NotNull(), Eq(data.size()))) - .WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()), - Return(data.size()))); - EXPECT_CALL(file, Close()).Times(1); - } else { - EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(false)); - EXPECT_CALL(file_system, FileSize(_)).Times(0); - EXPECT_CALL(file_system, Open(_, _)).Times(0); + std::vector file_list; + std::vector expected_usage_file_list; + for (int i = 0; i <= index; ++i) { + file_list.push_back(kTestListUsageInfoData[i].file_name); + if (kTestListUsageInfoData[i].is_usage_info_file) + expected_usage_file_list.push_back(kTestListUsageInfoData[i].file_name); } - EXPECT_CALL(file, Write(_, _)).Times(0); + EXPECT_CALL(file_system, List(StrEq(device_base_path_), NotNull())) + .WillOnce(DoAll(SetArgPointee<1>(file_list), Return(true))); DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); - std::vector > license_info; - ASSERT_TRUE(device_files.RetrieveUsageInfo( - DeviceFiles::GetUsageInfoFileName(app_id), - &license_info)); - if (index >= 0) { - EXPECT_EQ(static_cast(index), license_info.size()); - for (size_t i = 0; i < license_info.size(); ++i) { - bool found = false; - for (size_t j = 0; j <= static_cast(index); ++j) { - if ((license_info[i].first.compare( - kUsageInfoTestData[j].license_request) == 0) && - (license_info[i].second.compare(kUsageInfoTestData[j].license) == - 0)) { - found = true; - } - } - EXPECT_TRUE(found); - } - } else { - EXPECT_EQ(0u, license_info.size()); - } + std::vector usage_info_file_names; + EXPECT_TRUE(device_files.ListUsageInfoFiles(&usage_info_file_names)); + EXPECT_EQ(expected_usage_file_list.size(), usage_info_file_names.size()); + EXPECT_THAT(usage_info_file_names, + ::testing::UnorderedElementsAreArray(expected_usage_file_list)); } +INSTANTIATE_TEST_CASE_P(UsageInfo, DeviceFilesUsageInfoListTest, + ::testing::Range(0, 7)); + TEST_P(DeviceFilesUsageInfoTest, Store) { MockFileSystem file_system; - std::string app_id; // TODO(fredgc): multiple app ids. - std::string pst(GenerateRandomData(kProviderSessionTokenLen)); - std::string license_request(GenerateRandomData(kLicenseRequestLen)); - std::string license(GenerateRandomData(kLicenseLen)); - std::string key_set_id(GenerateRandomData(kKeySetIdLen)); - std::string usage_entry(GenerateRandomData(kUsageEntryLen)); - uint32_t usage_entry_number = 16; - std::string path = - device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id); + MockFile file; int index = GetParam(); - std::string data; - if (index >= 0) { - data = kUsageInfoTestData[index].file_data; + + std::string app_id; + if (index >= 0) app_id = kUsageInfoTestData[index].app_id; + std::string file_name = DeviceFiles::GetUsageInfoFileName(app_id); + std::string path = device_base_path_ + file_name; + + size_t usage_data_fields_length = 0; + std::vector usage_data_fields; + std::vector usage_data_list; + + for (int i = 0; i <= index; ++i) { + if (kUsageInfoTestData[i].app_id == app_id) { + usage_data_list.push_back(kUsageInfoTestData[i].usage_data); + usage_data_fields.push_back( + kUsageInfoTestData[i].usage_data.provider_session_token); + usage_data_fields.push_back( + kUsageInfoTestData[i].usage_data.license_request); + usage_data_fields.push_back(kUsageInfoTestData[i].usage_data.license); + usage_data_fields.push_back(kUsageInfoTestData[i].usage_data.key_set_id); + usage_data_fields.push_back(kUsageInfoTestData[i].usage_data.usage_entry); + usage_data_fields_length += + kUsageInfoTestData[i].usage_data.provider_session_token.size() + + kUsageInfoTestData[i].usage_data.license_request.size() + + kUsageInfoTestData[i].usage_data.license.size() + + kUsageInfoTestData[i].usage_data.key_set_id.size() + + kUsageInfoTestData[i].usage_data.usage_entry.size(); + } } + EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); + EXPECT_CALL(file, Write(ContainsAllElementsInVector(usage_data_fields), + Gt(usage_data_fields_length))) + .WillOnce(ReturnArg<1>()); + EXPECT_CALL(file, Close()); + + DeviceFiles device_files(&file_system); + EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); + + EXPECT_TRUE(device_files.StoreUsageInfo(file_name, usage_data_list)); +} + +TEST_P(DeviceFilesUsageInfoTest, Retrieve) { + MockFileSystem file_system; MockFile file; - EXPECT_CALL(file_system, Exists(StrEq(path))) - .WillRepeatedly(Return(index >= 0)); + + int index = GetParam(); + + std::string app_id; + if (index >= 0) app_id = kUsageInfoTestData[index].app_id; + + std::string file_name = DeviceFiles::GetUsageInfoFileName(app_id); + std::string path = device_base_path_ + file_name; + std::string file_data = (index < 0) ? kEmptyUsageInfoFileData + : kUsageInfoTestData[index].file_data; if (index >= 0) { - EXPECT_CALL(file_system, FileSize(StrEq(path))) - .WillOnce(Return(data.size())); - EXPECT_CALL(file_system, Open(StrEq(path), _)) + EXPECT_CALL(file_system, Exists(StrEq(path))) .Times(2) - .WillRepeatedly(Return(&file)); - EXPECT_CALL(file, Read(NotNull(), Eq(data.size()))) - .WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()), - Return(data.size()))); - EXPECT_CALL(file, Close()).Times(2); - } else { - EXPECT_CALL(file_system, FileSize(_)).Times(0); - EXPECT_CALL(file_system, Open(_, _)).Times(1).WillOnce(Return(&file)); + .WillRepeatedly(Return(true)); + EXPECT_CALL(file_system, FileSize(StrEq(path))) + .Times(2) + .WillRepeatedly(Return(kUsageInfoTestData[index].file_data.size())); + EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); + EXPECT_CALL(file, + Read(NotNull(), Eq(kUsageInfoTestData[index].file_data.size()))) + .WillOnce(DoAll(SetArrayArgument<0>(file_data.begin(), file_data.end()), + Return(file_data.size()))); EXPECT_CALL(file, Close()); } + else { + EXPECT_CALL(file_system, Exists(StrEq(path))) + .WillOnce(Return(false)); + } - EXPECT_CALL(file, Write(Contains(pst, license_request, license, key_set_id, - usage_entry, data.size()), - Gt(pst.size() + license_request.size() + - license.size() + key_set_id.size()))) - .WillOnce(ReturnArg<1>()); + std::vector usage_data_list; + DeviceFiles device_files(&file_system); + EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); + + EXPECT_TRUE(device_files.RetrieveUsageInfo(file_name, &usage_data_list)); + + for (size_t i = 0; i < usage_data_list.size(); ++i) { + bool found = false; + int j = 0; + while (!found && j <= index) { + if (app_id == kUsageInfoTestData[j].app_id && + usage_data_list[i].provider_session_token == + kUsageInfoTestData[j].usage_data.provider_session_token) { + EXPECT_EQ(kUsageInfoTestData[j].usage_data.license_request, + usage_data_list[i].license_request); + EXPECT_EQ(kUsageInfoTestData[j].usage_data.license, + usage_data_list[i].license); + EXPECT_EQ(kUsageInfoTestData[j].usage_data.key_set_id, + usage_data_list[i].key_set_id); + EXPECT_EQ(kUsageInfoTestData[j].usage_data.usage_entry, + usage_data_list[i].usage_entry); + EXPECT_EQ(kUsageInfoTestData[j].usage_data.usage_entry_number, + usage_data_list[i].usage_entry_number); + found = true; + } + ++j; + } + EXPECT_TRUE(found); + } +} + +TEST_P(DeviceFilesUsageInfoTest, RetrieveByProviderSessionToken) { + MockFileSystem file_system; + MockFile file; + + int index = GetParam(); + + std::string app_id; + if (index >= 0) app_id = kUsageInfoTestData[index].app_id; + + std::string file_name = DeviceFiles::GetUsageInfoFileName(app_id); + std::string path = device_base_path_ + file_name; + + size_t max_index_by_app_id = 0; + for (size_t i = 0; i <= sizeof(kUsageInfoTestData) / sizeof(UsageInfo); ++i) { + if (app_id == kUsageInfoTestData[i].app_id) max_index_by_app_id = i; + } + std::string file_data = + (index < 0) ? kEmptyUsageInfoFileData + : kUsageInfoTestData[max_index_by_app_id].file_data; + std::string provider_session_token = kUsageInfoTestData[index < 0 ? 0 : index] + .usage_data.provider_session_token; + + EXPECT_CALL(file_system, Exists(StrEq(path))).WillOnce(Return(true)); + EXPECT_CALL(file_system, FileSize(StrEq(path))) + .WillOnce(Return(file_data.size())); + EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); + EXPECT_CALL(file, Read(NotNull(), Eq(file_data.size()))) + .WillOnce(DoAll(SetArrayArgument<0>(file_data.begin(), file_data.end()), + Return(file_data.size()))); + EXPECT_CALL(file, Close()); DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); - ASSERT_TRUE(device_files.StoreUsageInfo( - pst, license_request, license, - DeviceFiles::GetUsageInfoFileName(app_id), - key_set_id, usage_entry, usage_entry_number)); + DeviceFiles::CdmUsageData usage_data; + + if (index < 0) { + EXPECT_FALSE(device_files.RetrieveUsageInfo( + file_name, provider_session_token, &usage_data)); + } else { + EXPECT_TRUE(device_files.RetrieveUsageInfo( + file_name, provider_session_token, &usage_data)); + + EXPECT_EQ(kUsageInfoTestData[index].usage_data.provider_session_token, + usage_data.provider_session_token); + EXPECT_EQ(kUsageInfoTestData[index].usage_data.license_request, + usage_data.license_request); + EXPECT_EQ(kUsageInfoTestData[index].usage_data.license, usage_data.license); + EXPECT_EQ(kUsageInfoTestData[index].usage_data.key_set_id, + usage_data.key_set_id); + EXPECT_EQ(kUsageInfoTestData[index].usage_data.usage_entry, + usage_data.usage_entry); + EXPECT_EQ(kUsageInfoTestData[index].usage_data.usage_entry_number, + usage_data.usage_entry_number); + } } -TEST_P(DeviceFilesUsageInfoTest, Delete) { +TEST_P(DeviceFilesUsageInfoTest, UpdateUsageInfo) { MockFileSystem file_system; MockFile file; - std::string app_id; // TODO(fredgc): expand tests. - std::string path = - device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id); int index = GetParam(); - if (index < 0) return; - std::string data, pst, prev_data, prev_pst, prev_license; - if (index >= 0) { - data = kUsageInfoTestData[index].file_data; - if (index >= 1) { - pst = kUsageInfoTestData[index].provider_session_token; - prev_data = kUsageInfoTestData[index - 1].file_data; - prev_pst = kUsageInfoTestData[index - 1].provider_session_token; - prev_license = kUsageInfoTestData[index - 1].license; + std::string app_id; + if (index >= 0) app_id = kUsageInfoTestData[index].app_id; + + std::string file_name = DeviceFiles::GetUsageInfoFileName(app_id); + std::string path = device_base_path_ + file_name; + + size_t usage_data_fields_length = 0; + std::vector usage_data_fields; + + size_t max_index_by_app_id = 0; + for (size_t i = 0; i <= sizeof(kUsageInfoTestData) / sizeof(UsageInfo); ++i) { + if (app_id == kUsageInfoTestData[i].app_id) { + max_index_by_app_id = i; + + if ((int)i != index) { + usage_data_fields.push_back( + kUsageInfoTestData[i].usage_data.provider_session_token); + usage_data_fields.push_back( + kUsageInfoTestData[i].usage_data.license_request); + usage_data_fields.push_back(kUsageInfoTestData[i].usage_data.license); + usage_data_fields.push_back( + kUsageInfoTestData[i].usage_data.key_set_id); + usage_data_fields.push_back( + kUsageInfoTestData[i].usage_data.usage_entry); + usage_data_fields_length += + kUsageInfoTestData[i].usage_data.provider_session_token.size() + + kUsageInfoTestData[i].usage_data.license_request.size() + + kUsageInfoTestData[i].usage_data.license.size() + + kUsageInfoTestData[i].usage_data.key_set_id.size() + + kUsageInfoTestData[i].usage_data.usage_entry.size(); + } } } - EXPECT_CALL(file_system, Exists(StrEq(path))).WillOnce(Return(index >= 0)); + if (index >= 0) { + usage_data_fields.push_back( + kUsageInfoTestData[index].usage_data.provider_session_token); + usage_data_fields.push_back(kUsageInfoUpdateTestData.license_request); + usage_data_fields.push_back(kUsageInfoUpdateTestData.license); + usage_data_fields.push_back(kUsageInfoUpdateTestData.key_set_id); + usage_data_fields.push_back(kUsageInfoUpdateTestData.usage_entry); + usage_data_fields_length += + kUsageInfoTestData[index].usage_data.provider_session_token.size() + + kUsageInfoUpdateTestData.license_request.size() + + kUsageInfoUpdateTestData.license.size() + + kUsageInfoUpdateTestData.key_set_id.size() + + kUsageInfoUpdateTestData.usage_entry.size(); + } - EXPECT_CALL(file_system, FileSize(StrEq(path))).WillOnce(Return(data.size())); - if (index >= 1) { + std::string file_data = + (index < 0) ? kEmptyUsageInfoFileData + : kUsageInfoTestData[max_index_by_app_id].file_data; + std::string provider_session_token = kUsageInfoTestData[index < 0 ? 0 : index] + .usage_data.provider_session_token; + + EXPECT_CALL(file_system, Exists(StrEq(path))) + .Times(2) + .WillRepeatedly(Return(true)); + EXPECT_CALL(file_system, FileSize(StrEq(path))) + .WillOnce(Return(file_data.size())); + EXPECT_CALL(file, Read(NotNull(), Eq(file_data.size()))) + .WillOnce(DoAll(SetArrayArgument<0>(file_data.begin(), file_data.end()), + Return(file_data.size()))); + + if (index < 0) { + EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); + EXPECT_CALL(file, Close()); + } else { EXPECT_CALL(file_system, Open(StrEq(path), _)) .Times(2) .WillRepeatedly(Return(&file)); - EXPECT_CALL(file, Write(Contains(prev_pst, prev_license, prev_data.size()), - Gt(prev_pst.size() + prev_license.size()))) + EXPECT_CALL(file, Write(ContainsAllElementsInVector(usage_data_fields), + Gt(usage_data_fields_length))) .WillOnce(ReturnArg<1>()); EXPECT_CALL(file, Close()).Times(2); - } else { - EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); - EXPECT_CALL(file, Write(_, _)).Times(0); - EXPECT_CALL(file, Close()).Times(1); - } - EXPECT_CALL(file, Read(NotNull(), Eq(data.size()))) - .WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()), - Return(data.size()))); - - DeviceFiles device_files(&file_system); - EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); - - if (index >= 1) { - ASSERT_TRUE(device_files.DeleteUsageInfo( - DeviceFiles::GetUsageInfoFileName(app_id), - pst)); - } else { - ASSERT_FALSE(device_files.DeleteUsageInfo( - DeviceFiles::GetUsageInfoFileName(app_id), - pst)); - } -} - -TEST_P(DeviceFilesUsageInfoTest, DeleteAll) { - MockFileSystem file_system; - MockFile file; - std::string app_id; // TODO(fredgc): expand tests. - std::string path = - device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id); - - int index = GetParam(); - EXPECT_CALL(file, Write(_, _)).Times(0); - - std::string data; - if (index < 0) { - EXPECT_CALL(file_system, Exists(StrEq(path))).WillOnce(Return(false)); - } else { - data = kUsageInfoTestData[index].file_data; - EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true)); - EXPECT_CALL(file_system, FileSize(StrEq(path))) - .WillOnce(Return(data.size())); - EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file)); - EXPECT_CALL(file, Read(NotNull(), Eq(data.size()))) - .WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()), - Return(data.size()))); - EXPECT_CALL(file, Close()).Times(1); - EXPECT_CALL(file_system, Remove(StrEq(path))).WillOnce(Return(true)); } DeviceFiles device_files(&file_system); EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); - std::vector psts; - ASSERT_TRUE(device_files.DeleteAllUsageInfoForApp( - DeviceFiles::GetUsageInfoFileName(app_id), - &psts)); - if (index < 0) { - EXPECT_EQ(0u, psts.size()); - } else { - // DeleteAllUsageInfoForApp returns a list of all psts that - // should be deleted by oemcrypto. - EXPECT_EQ(static_cast(index), psts.size()); - for (int i = 0; i < index; i++) { - EXPECT_EQ(kUsageInfoTestData[i + 1].provider_session_token, psts[i]); - } - } + bool expected_result = index >= 0; + EXPECT_EQ(expected_result, + device_files.UpdateUsageInfo(file_name, provider_session_token, + kUsageInfoUpdateTestData)); } INSTANTIATE_TEST_CASE_P(UsageInfo, DeviceFilesUsageInfoTest, - ::testing::Range(-1, 4)); + ::testing::Range(-1, 9)); TEST_P(DeviceFilesHlsAttributesTest, Read) { MockFileSystem file_system; diff --git a/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp b/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp index 56bae583..493992d7 100644 --- a/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/usage_table_header_unittest.cpp @@ -1,11 +1,9 @@ // Copyright 2017 Google Inc. All Rights Reserved. #include "usage_table_header.h" - #include #include #include - #include "crypto_session.h" #include "device_files.h" #include "file_store.h" @@ -52,58 +50,10 @@ const CdmUsageEntryInfo kUsageEntryInfoStorageTypeUnknown = { .storage_type = kStorageTypeUnknown, .key_set_id = "", .usage_info_file_name = ""}; - -const std::vector kEmptyLicenseList; - -const std::string kLicenseArray[] = { - kUsageEntryInfoOfflineLicense1.key_set_id, - kUsageEntryInfoOfflineLicense2.key_set_id, - kUsageEntryInfoOfflineLicense3.key_set_id, -}; -const size_t kLicenseArraySize = sizeof(kLicenseArray)/ - sizeof(kLicenseArray[0]); -std::vector kLicenseList; - -const std::vector kEmptyUsageInfoFilesList; - -const std::string kUsageInfoFileArray[] = { - kUsageEntryInfoSecureStop1.usage_info_file_name, - kUsageEntryInfoSecureStop2.usage_info_file_name, - kUsageEntryInfoSecureStop3.usage_info_file_name, -}; -const size_t kUsageInfoFileArraySize = sizeof(kUsageInfoFileArray)/ - sizeof(kUsageInfoFileArray[0]); -std::vector kUsageInfoFileList; - -const DeviceFiles::CdmUsageData kCdmUsageData1 = { - .provider_session_token = "provider_session_token_1", - .license_request = "license_request_1", - .license = "license_1", - .key_set_id = "key_set_id_1", - .usage_entry = "usage_entry_1", - .usage_entry_number = 0, -}; -const DeviceFiles::CdmUsageData kCdmUsageData2 = { - .provider_session_token = "provider_session_token_2", - .license_request = "license_request_2", - .license = "license_2", - .key_set_id = "key_set_id_2", - .usage_entry = "usage_entry_2", - .usage_entry_number = 0, -}; -const DeviceFiles::CdmUsageData kCdmUsageData3 = { - .provider_session_token = "provider_session_token_3", - .license_request = "license_request_3", - .license = "license_3", - .key_set_id = "key_set_id_3", - .usage_entry = "usage_entry_3", - .usage_entry_number = 0, -}; -const std::vector kEmptyUsageInfoUsageDataList; - const std::vector kEmptyUsageEntryInfoVector; -std::vector kUsageEntryInfoVector; - +const std::vector kUsageEntryInfoVector = { + kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1, + kUsageEntryInfoStorageTypeUnknown}; const DeviceFiles::LicenseState kActiveLicenseState = DeviceFiles::kLicenseStateActive; const CdmInitData kPsshData = "pssh data"; @@ -118,36 +68,6 @@ int64_t kPlaybackStartTime = 1030005; int64_t kPlaybackDuration = 300; int64_t kGracePeriodEndTime = 60; -namespace { - -void InitVectorConstants() { - kUsageEntryInfoVector.clear(); - kUsageEntryInfoVector.push_back(kUsageEntryInfoOfflineLicense1); - kUsageEntryInfoVector.push_back(kUsageEntryInfoSecureStop1); - kUsageEntryInfoVector.push_back(kUsageEntryInfoStorageTypeUnknown); - - kUsageInfoFileList.clear(); - for (size_t i = 0; i < kUsageInfoFileArraySize; i++) { - kUsageInfoFileList.push_back(kUsageInfoFileArray[i]); - } - - kLicenseList.clear(); - for (size_t i = 0; i < kLicenseArraySize; i++) { - kLicenseList.push_back(kLicenseArray[i]); - } -} - -void ToVector(std::vector& vec, - const CdmUsageEntryInfo* arr, size_t total_size) { - size_t max = total_size / sizeof(CdmUsageEntryInfo); - vec.clear(); - for (size_t i = 0; i < max; i++) { - vec.push_back(arr[i]); - } -} - -}; // namespace - class MockDeviceFiles : public DeviceFiles { public: MockDeviceFiles() : DeviceFiles(&file_system_) { Init(kSecurityLevelL1); } @@ -162,17 +82,12 @@ class MockDeviceFiles : public DeviceFiles { bool(const std::string&, const std::string&, std::string*, CdmKeyMessage*, CdmKeyResponse*, CdmUsageEntry*, uint32_t*)); - MOCK_METHOD0(DeleteAllLicenses, bool()); MOCK_METHOD7(StoreUsageInfo, bool(const std::string&, const CdmKeyMessage&, const CdmKeyResponse&, const std::string&, const std::string&, const CdmUsageEntry&, uint32_t)); MOCK_METHOD2(RetrieveUsageInfo, bool(const std::string&, std::vector*)); - MOCK_METHOD1(ListLicenses, - bool(std::vector* key_set_ids)); - MOCK_METHOD1(ListUsageInfoFiles, - bool(std::vector* usage_info_files)); private: FileSystem file_system_; @@ -180,8 +95,7 @@ class MockDeviceFiles : public DeviceFiles { class MockCryptoSession : public CryptoSession { public: - MockCryptoSession(metrics::CryptoMetrics* metrics) - : CryptoSession(metrics) {} + MockCryptoSession() : CryptoSession(NULL) {} MOCK_METHOD1(Open, CdmResponseType(SecurityLevel)); MOCK_METHOD1(LoadUsageTableHeader, CdmResponseType(const CdmUsageTableHeader&)); @@ -207,16 +121,11 @@ using ::testing::UnorderedElementsAre; using ::testing::UnorderedElementsAreArray; class UsageTableHeaderTest : public ::testing::Test { - public: - static void SetUpTestCase() { - InitVectorConstants(); - } - protected: virtual void SetUp() { // UsageTableHeader will take ownership of the pointer device_files_ = new MockDeviceFiles(); - crypto_session_ = new MockCryptoSession(&crypto_metrics_); + crypto_session_ = new MockCryptoSession(); usage_table_header_ = new UsageTableHeader(); // usage_table_header_ object takes ownership of these objects @@ -242,7 +151,6 @@ class UsageTableHeaderTest : public ::testing::Test { } MockDeviceFiles* device_files_; - metrics::CryptoMetrics crypto_metrics_; MockCryptoSession* crypto_session_; UsageTableHeader* usage_table_header_; }; @@ -259,86 +167,21 @@ TEST_F(UsageTableHeaderTest, InitError) { class UsageTableHeaderInitializationTest : public UsageTableHeaderTest, - public ::testing::WithParamInterface { - public: - static void SetUpTestCase() { - InitVectorConstants(); - } - -}; + public ::testing::WithParamInterface {}; TEST_P(UsageTableHeaderInitializationTest, CreateUsageTableHeader) { + std::vector empty_usage_entry_info; + EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull())) .WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), SetArgPointee<1>(kEmptyUsageEntryInfoVector), Return(false))); - EXPECT_CALL(*device_files_, ListLicenses(NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kEmptyLicenseList), - Return(false))); - EXPECT_CALL(*device_files_, ListUsageInfoFiles(NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageInfoFilesList), - Return(false))); EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull())) .WillOnce( DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR))); EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader, kEmptyUsageEntryInfoVector)) - .Times(2) - .WillRepeatedly(Return(true)); - - EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_)); -} - -TEST_P(UsageTableHeaderInitializationTest, Upgrade_UnableToRetrieveLicenses) { - EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), - SetArgPointee<1>(kEmptyUsageEntryInfoVector), - Return(false))); - EXPECT_CALL(*device_files_, ListLicenses(NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kLicenseList), - Return(true))); - EXPECT_CALL(*device_files_, ListUsageInfoFiles(NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageInfoFilesList), - Return(false))); - EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull())) - .WillOnce( - DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR))); - // TODO: Why not being called? - //EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true)); - EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader, - kEmptyUsageEntryInfoVector)) - .Times(2) - .WillRepeatedly(Return(true)); - - for (size_t i = 0; i < kLicenseList.size(); ++i) - device_files_->DeleteLicense(kLicenseList[i]); - EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_)); -} - -TEST_P(UsageTableHeaderInitializationTest, Upgrade_UnableToRetrieveUsageInfo) { - EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), - SetArgPointee<1>(kEmptyUsageEntryInfoVector), - Return(false))); - EXPECT_CALL(*device_files_, ListLicenses(NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kEmptyLicenseList), - Return(false))); - EXPECT_CALL(*device_files_, ListUsageInfoFiles(NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kUsageInfoFileList), - Return(true))); - EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull())) - .WillOnce( - DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader, - kEmptyUsageEntryInfoVector)) - .Times(2) - .WillRepeatedly(Return(true)); - for (size_t i = 0; i < kUsageInfoFileList.size(); ++i) { - EXPECT_CALL(*device_files_, - RetrieveUsageInfo(kUsageInfoFileList[i], NotNull())) - .WillOnce(DoAll(SetArgPointee<1>(kEmptyUsageInfoUsageDataList), - Return(false))); - } + .WillOnce(Return(true)); EXPECT_TRUE(usage_table_header_->Init(GetParam(), crypto_session_)); } @@ -552,7 +395,7 @@ TEST_F(UsageTableHeaderTest, UpdateEntry) { TEST_F(UsageTableHeaderTest, DeleteEntry_InvalidUsageEntryNumber) { Init(kSecurityLevelL1, kUsageTableHeader, kUsageEntryInfoVector); uint32_t usage_entry_number = kUsageEntryInfoVector.size(); - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_NE(NO_ERROR, usage_table_header_->DeleteEntry( usage_entry_number, device_files_, &metrics)); @@ -576,17 +419,14 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_InvalidUsageEntryNumber) { // // # of usage entries 4 4 TEST_F(UsageTableHeaderTest, DeleteEntry_CryptoSessionError) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense2}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense2 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL( @@ -615,17 +455,14 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_CryptoSessionError) { // // # of usage entries 4 3 TEST_F(UsageTableHeaderTest, DeleteEntry_LastOfflineEntry) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense2}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense2 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL( @@ -663,17 +500,14 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastOfflineEntry) { // // # of usage entries 4 3 TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntry) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop2}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop2 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL( @@ -716,19 +550,17 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntry) { // # of usage entries 5 2 TEST_F(UsageTableHeaderTest, DeleteEntry_LastOfflineEntriesHaveMissingLicenses) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; + device_files_->DeleteAllLicenses(); EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL( *crypto_session_, @@ -768,18 +600,15 @@ TEST_F(UsageTableHeaderTest, // // # of usage entries 5 2 TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntriesAreMissing) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2, kUsageEntryInfoSecureStop3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL( @@ -834,18 +663,15 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntriesAreMissing) { // # of usage entries 5 2 TEST_F(UsageTableHeaderTest, DeleteEntry_LastOfflineEntriesHaveIncorrectUsageEntryNumber) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_TRUE(device_files_->StoreLicense( usage_entry_info_vector[usage_entry_info_vector.size() - 1].key_set_id, @@ -903,20 +729,17 @@ TEST_F(UsageTableHeaderTest, // # of usage entries 5 2 TEST_F(UsageTableHeaderTest, DeleteEntry_LastSecureStopEntriesHaveIncorrectUsageEntryNumber) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2, kUsageEntryInfoSecureStop3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1 uint32_t usage_entry_number_after_deleted_entry = usage_entry_number_to_be_deleted + 1; - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL( @@ -981,18 +804,15 @@ TEST_F(UsageTableHeaderTest, // // # of usage entries 7 4 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreStorageTypeUnknown) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoSecureStop1, kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoStorageTypeUnknown}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL( @@ -1037,20 +857,17 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreStorageTypeUnknown) { // # of usage entries 5 5 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsOffline_MoveOfflineEntryFailed) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1 uint32_t last_usage_entry_number = usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_TRUE(device_files_->StoreLicense( usage_entry_info_vector[last_usage_entry_number].key_set_id, @@ -1106,20 +923,17 @@ TEST_F(UsageTableHeaderTest, // # of usage entries 5 5 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsSecureStop_MoveSecureStopEntryFailed) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2, kUsageEntryInfoSecureStop3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1 uint32_t last_usage_entry_number = usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)).WillOnce(Return(NO_ERROR)); EXPECT_CALL(*crypto_session_, @@ -1182,21 +996,18 @@ TEST_F(UsageTableHeaderTest, // # of usage entries 7 5 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreOfflineAndUnknown_MoveOfflineEntryFailed) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoStorageTypeUnknown}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1 uint32_t last_valid_usage_entry_number = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_TRUE(device_files_->StoreLicense( usage_entry_info_vector[last_valid_usage_entry_number].key_set_id, @@ -1263,21 +1074,18 @@ TEST_F(UsageTableHeaderTest, // # of usage entries 7 5 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreSecureStopAndUnknown_MoveOfflineEntryFailed) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2, kUsageEntryInfoSecureStop3, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoStorageTypeUnknown}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1 uint32_t last_valid_usage_entry_number = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) .Times(2) @@ -1339,20 +1147,17 @@ TEST_F(UsageTableHeaderTest, // // # of usage entries 5 4 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsOffline) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense1 uint32_t last_usage_entry_number = usage_entry_info_vector.size() - 1; // kUsageEntryInfoOfflineLicense3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_TRUE(device_files_->StoreLicense( usage_entry_info_vector[last_usage_entry_number].key_set_id, @@ -1456,20 +1261,17 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsOffline) { // // # of usage entries 5 4 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsSecureStop) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2, kUsageEntryInfoSecureStop3}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop1 uint32_t last_usage_entry_number = usage_entry_info_vector.size() - 1; // kUsageEntryInfoSecureStop3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) .Times(2) @@ -1558,21 +1360,18 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntryIsSecureStop) { // // # of usage entries 7 4 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreOfflineAndUnknknown) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoSecureStop1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense1, kUsageEntryInfoOfflineLicense2, kUsageEntryInfoOfflineLicense3, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoStorageTypeUnknown}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 5; // kUsageEntryInfoOfflineLicense1 uint32_t last_valid_usage_entry_number = usage_entry_info_vector.size() - 3; // kUsageEntryInfoOfflineLicense3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_TRUE(device_files_->StoreLicense( usage_entry_info_vector[last_valid_usage_entry_number].key_set_id, @@ -1680,21 +1479,18 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreOfflineAndUnknknown) { // // # of usage entries 7 4 TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreSecureStopAndUnknknown) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { + const std::vector usage_entry_info_vector = { kUsageEntryInfoOfflineLicense1, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoSecureStop1, kUsageEntryInfoSecureStop2, kUsageEntryInfoSecureStop3, kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoStorageTypeUnknown}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); Init(kSecurityLevelL1, kUsageTableHeader, usage_entry_info_vector); uint32_t usage_entry_number_to_be_deleted = usage_entry_info_vector.size() - 5; // kUsageEntryInfoSecureStop1 uint32_t last_valid_usage_entry_number = usage_entry_info_vector.size() - 3; // kUsageEntryInfoSecureStop3 - metrics::CryptoMetrics metrics; + metrics::MetricsGroup metrics; EXPECT_CALL(*crypto_session_, Open(kLevelDefault)) .Times(2) @@ -1762,30 +1558,4 @@ TEST_F(UsageTableHeaderTest, DeleteEntry_LastEntriesAreSecureStopAndUnknknown) { device_files_, &metrics)); } -// If the crypto session says the usage table header is stale, init should fail. -TEST_F(UsageTableHeaderTest, StaleHeader) { - std::vector usage_entry_info_vector; - const CdmUsageEntryInfo usage_entry_info_array[] = { - kUsageEntryInfoOfflineLicense1, kUsageEntryInfoSecureStop1, - kUsageEntryInfoStorageTypeUnknown, kUsageEntryInfoOfflineLicense2}; - ToVector(usage_entry_info_vector, usage_entry_info_array, - sizeof(usage_entry_info_array)); - - EXPECT_CALL(*device_files_, RetrieveUsageTableInfo(NotNull(), NotNull())) - .WillOnce(DoAll(SetArgPointee<0>(kUsageTableHeader), - SetArgPointee<1>(usage_entry_info_vector), - Return(true))); - EXPECT_CALL(*crypto_session_, LoadUsageTableHeader(kUsageTableHeader)) - .WillOnce(Return(LOAD_USAGE_HEADER_GENERATION_SKEW)); - EXPECT_CALL(*crypto_session_, CreateUsageTableHeader(NotNull())) - .WillOnce( - DoAll(SetArgPointee<0>(kEmptyUsageTableHeader), Return(NO_ERROR))); - EXPECT_CALL(*device_files_, DeleteAllLicenses()).WillOnce(Return(true)); - EXPECT_CALL(*device_files_, StoreUsageTableInfo(kEmptyUsageTableHeader, - kEmptyUsageEntryInfoVector)) - .WillOnce(Return(true)); - - EXPECT_TRUE(usage_table_header_->Init(kSecurityLevelL1, crypto_session_)); -} - } // namespace wvcdm diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 08bf064e..47a15087 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -160,6 +160,11 @@ CdmResponseType WvContentDecryptionModule::AddKey( CdmEngine* cdm_engine = session_id.empty() ? GetCdmForSessionId(*key_set_id) : GetCdmForSessionId(session_id); if (!cdm_engine) return SESSION_NOT_FOUND_3; + // Save key_set_id, as CDM will return an empty key_set_id on release + CdmKeySetId release_key_set_id; + if (session_id.empty() && key_set_id != NULL) { + release_key_set_id = *key_set_id; + } CdmResponseType sts; M_TIME( sts = cdm_engine->AddKey( @@ -170,8 +175,8 @@ CdmResponseType WvContentDecryptionModule::AddKey( cdm_engine_add_key_, sts); if (sts == KEY_ADDED && session_id.empty()) { // license type release - cdm_engine->CloseKeySetSession(*key_set_id); - cdm_by_session_id_.erase(*key_set_id); + cdm_engine->CloseKeySetSession(release_key_set_id); + cdm_by_session_id_.erase(release_key_set_id); } return sts; } @@ -377,7 +382,10 @@ CdmResponseType WvContentDecryptionModule::Decrypt( cdm_engine->GetMetrics(), cdm_engine_find_session_for_key_, status); - if (!status) return KEY_NOT_FOUND_IN_SESSION; + if (!status && parameters.is_encrypted) { + LOGE("WvContentDecryptionModule::Decrypt: unable to find session"); + return KEY_NOT_FOUND_IN_SESSION; + } } CdmResponseType sts; M_TIME( diff --git a/libwvdrmengine/cdm/test/Android.mk b/libwvdrmengine/cdm/test/Android.mk index 32778eff..4dcc72c3 100644 --- a/libwvdrmengine/cdm/test/Android.mk +++ b/libwvdrmengine/cdm/test/Android.mk @@ -71,6 +71,10 @@ test_name := timer_unittest test_src_dir := . include $(LOCAL_PATH)/unit-test.mk +test_name := usage_table_header_unittest +test_src_dir := ../core/test +include $(LOCAL_PATH)/unit-test.mk + test_name := distribution_test test_src_dir := ../metrics/test include $(LOCAL_PATH)/unit-test.mk diff --git a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp index 04d6add8..f29714a5 100644 --- a/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp +++ b/libwvdrmengine/cdm/test/cdm_extended_duration_test.cpp @@ -983,6 +983,142 @@ TEST_F(WvCdmExtendedDurationTest, UsageOverflowTest) { } } +// This test verifies that sessions allocated internally during key release +// message generation are deallocated after their time to live period expires +// by timer events (if other sessions are open). +TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnTimerEvent) { + Unprovision(); + Provision(); + + // Leave session open to run the CDM timer + CdmSessionId streaming_session_id; + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &streaming_session_id); + + // override default settings unless configured through the command line + std::string key_id; + std::string client_auth; + GetOfflineConfiguration(&key_id, &client_auth); + + uint32_t initial_open_sessions = + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS); + + uint32_t max_sessions = + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS); + + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &session_id_); + GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline); + VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); + + EXPECT_FALSE(key_set_id_.empty()); + decryptor_.CloseSession(session_id_); + CdmKeySetId key_set_id = key_set_id_; + + session_id_.clear(); + key_set_id_.clear(); + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &session_id_); + EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id)); + decryptor_.CloseSession(session_id_); + + session_id_.clear(); + GenerateKeyRelease(key_set_id); + + uint32_t open_sessions = + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS); + + EXPECT_GT(open_sessions, initial_open_sessions); + + sleep(kMinute + kClockTolerance); + + open_sessions = + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS); + + EXPECT_EQ(open_sessions, initial_open_sessions); + + session_id_.clear(); + GenerateKeyRelease(key_set_id); + key_set_id_ = key_set_id; + VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); + decryptor_.CloseSession(streaming_session_id); +} + +// This test verifies that sessions allocated internally during key release +// message generation are deallocated after their time to live period expires +// when a new session is opened. +TEST_F(WvCdmExtendedDurationTest, AutomatedOfflineSessionReleaseOnOpenSession) { + Unprovision(); + Provision(); + + // override default settings unless configured through the command line + std::string key_id; + std::string client_auth; + GetOfflineConfiguration(&key_id, &client_auth); + + uint32_t initial_open_sessions = + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS); + + uint32_t max_sessions = + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS); + + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &session_id_); + GenerateKeyRequest(kOfflineClip4, kLicenseTypeOffline); + VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); + + EXPECT_FALSE(key_set_id_.empty()); + decryptor_.CloseSession(session_id_); + CdmKeySetId key_set_id = key_set_id_; + + session_id_.clear(); + key_set_id_.clear(); + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &session_id_); + EXPECT_EQ(wvcdm::KEY_ADDED, decryptor_.RestoreKey(session_id_, key_set_id)); + decryptor_.CloseSession(session_id_); + + session_id_.clear(); + GenerateKeyRelease(key_set_id); + + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &session_id_); + + EXPECT_GT( + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), + initial_open_sessions); + + decryptor_.CloseSession(session_id_); + + EXPECT_GT( + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), + initial_open_sessions); + + sleep(kMinute + kClockTolerance); + + EXPECT_GT( + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), + initial_open_sessions); + + decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, + &session_id_); + + EXPECT_GT( + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), + initial_open_sessions); + + decryptor_.CloseSession(session_id_); + + EXPECT_EQ( + QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS), + initial_open_sessions); + + session_id_.clear(); + GenerateKeyRelease(key_set_id); + key_set_id_ = key_set_id; + VerifyKeyRequestResponse(kUatLicenseServer, client_auth, false); +} + // This test verifies that sessions allocated internally during // key release message generation are deallocated after their // time to live period expires. diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 538e4176..d771e803 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -986,7 +986,7 @@ class TestWvCdmHlsEventListener : public WvCdmEventListener { class WvCdmRequestLicenseTest : public WvCdmTestBase { public: - WvCdmRequestLicenseTest() {} + WvCdmRequestLicenseTest() : license_type_(kLicenseTypeStreaming) {} ~WvCdmRequestLicenseTest() {} protected: @@ -1032,6 +1032,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { CdmClientPropertySet* property_set) { CdmKeyRequest key_request; std::string key_set_id; + license_type_ = license_type; EXPECT_EQ(expected_response, decryptor_.GenerateKeyRequest( session_id_, key_set_id, init_data_type, init_data, @@ -1075,6 +1076,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { void GenerateKeyRelease(CdmKeySetId key_set_id, CdmClientPropertySet* property_set, CdmKeyMessage* key_msg) { + license_type_ = kLicenseTypeRelease; CdmSessionId session_id; CdmInitData init_data; wvcdm::CdmAppParameterMap app_parameters; @@ -1168,26 +1170,34 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { } void VerifyKeyRequestResponse(const std::string& server_url, - const std::string& client_auth, - bool is_renewal) { + const std::string& client_auth) { std::string response; - VerifyKeyRequestResponse(server_url, client_auth, is_renewal, &response); + VerifyKeyRequestResponse(server_url, client_auth, false); + } + + void VerifyUsageKeyRequestResponse(const std::string& server_url, + const std::string& client_auth) { + std::string response; + VerifyKeyRequestResponse(server_url, client_auth, true); } void VerifyKeyRequestResponse(const std::string& server_url, - const std::string& client_auth, bool is_renewal, + const std::string& client_auth, + bool is_usage) { + std::string response; + VerifyKeyRequestResponse(server_url, client_auth, is_usage, &response); + } + + void VerifyKeyRequestResponse(const std::string& server_url, + const std::string& client_auth, + bool is_usage, std::string* response) { *response = GetKeyRequestResponse(server_url, client_auth); - if (is_renewal) { - // TODO application makes a license request, CDM will renew the license - // when appropriate - EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_), - wvcdm::KEY_ADDED); - } else { - EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_), - wvcdm::KEY_ADDED); - } + EXPECT_EQ(decryptor_.AddKey(session_id_, *response, &key_set_id_), + wvcdm::KEY_ADDED); + EXPECT_EQ(is_usage || license_type_ == kLicenseTypeOffline, + key_set_id_.size() > 0); } void Unprovision() { @@ -1295,6 +1305,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase { CdmKeyMessage key_msg_; CdmSessionId session_id_; CdmKeySetId key_set_id_; + CdmLicenseType license_type_; }; TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) { @@ -1608,7 +1619,7 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) { kDefaultCdmIdentifier, NULL, &session_id_)); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -1624,7 +1635,7 @@ TEST_F(WvCdmRequestLicenseTest, PrivacyModeTest) { EXPECT_EQ(decryptor_.AddKey(session_id_, resp, &key_set_id_), wvcdm::NEED_KEY); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -1637,7 +1648,7 @@ TEST_F(WvCdmRequestLicenseTest, PrivacyModeWithServiceCertificateTest) { decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -1682,7 +1693,7 @@ TEST_F(WvCdmRequestLicenseTest, AddStreamingKeyTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -1698,7 +1709,7 @@ TEST_F(WvCdmRequestLicenseTest, AddKeyOfflineTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); decryptor_.CloseSession(session_id_); } @@ -1714,7 +1725,7 @@ TEST_F(WvCdmRequestLicenseTest, RestoreOfflineKeyTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); @@ -1739,7 +1750,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); @@ -1756,7 +1767,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeyTest) { key_set_id_.clear(); GenerateKeyRelease(key_set_id); key_set_id_ = key_set_id; - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); } TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) { @@ -1775,7 +1786,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); @@ -1793,7 +1804,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseOfflineKeySessionUsageDisabledTest) { CdmKeyMessage key_msg; GenerateKeyRelease(key_set_id, NULL, &key_msg); key_set_id_ = key_set_id; - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); SignedMessage signed_message; EXPECT_TRUE(signed_message.ParseFromString(key_msg)); @@ -1830,7 +1841,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); @@ -1858,7 +1869,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryOfflineKeyTest) { key_set_id_.clear(); GenerateKeyRelease(key_set_id); key_set_id_ = key_set_id; - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); } TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) { @@ -1900,7 +1911,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) { decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline, &property_set); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); @@ -1928,7 +1939,7 @@ TEST_F(WvCdmRequestLicenseTest, ReleaseRetryL3OfflineKeyTest) { key_set_id_.clear(); GenerateKeyRelease(key_set_id, &property_set, NULL); key_set_id_ = key_set_id; - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); } TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) { @@ -1943,7 +1954,7 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); @@ -1976,7 +1987,7 @@ TEST_F(WvCdmRequestLicenseTest, ExpiryOnReleaseOfflineKeyTest) { AllOf(Each(Pair(_, kKeyStatusExpired)), Not(IsEmpty())), false)); GenerateKeyRelease(key_set_id); key_set_id_ = key_set_id; - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); decryptor_.CloseSession(restore_session_id); } @@ -1995,7 +2006,7 @@ TEST_F(WvCdmRequestLicenseTest, AutomatedOfflineSessionReleaseTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); @@ -2029,7 +2040,7 @@ TEST_F(WvCdmRequestLicenseTest, AutomatedOfflineSessionReleaseTest) { open_sessions, QueryStatus(kLevelDefault, wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS)); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); EXPECT_EQ( --open_sessions, @@ -2040,12 +2051,12 @@ TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewal) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); std::string license_server; GenerateRenewalRequest(kLicenseTypeStreaming, &license_server); if (license_server.empty()) license_server = g_license_server; - VerifyKeyRequestResponse(license_server, g_client_auth, true); + VerifyKeyRequestResponse(license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -2058,7 +2069,7 @@ TEST_F(WvCdmRequestLicenseTest, StreamingLicenseRenewalProhibited) { "08011a0d7769646576696e655f746573" // pssh data "74221073747265616d696e675f636c69703131"); GenerateKeyRequest(key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); std::string init_data; wvcdm::CdmAppParameterMap app_parameters; @@ -2084,12 +2095,12 @@ TEST_F(WvCdmRequestLicenseTest, OfflineLicenseRenewal) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); std::string license_server; GenerateRenewalRequest(kLicenseTypeOffline, &license_server); if (license_server.empty()) license_server = g_license_server; - VerifyKeyRequestResponse(license_server, client_auth, true); + VerifyKeyRequestResponse(license_server, client_auth); decryptor_.CloseSession(session_id_); } @@ -2098,7 +2109,7 @@ TEST_F(WvCdmRequestLicenseTest, RemoveKeys) { kDefaultCdmIdentifier, NULL, &session_id_)); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); ASSERT_EQ(NO_ERROR, decryptor_.RemoveKeys(session_id_)); ASSERT_EQ(NO_ERROR, decryptor_.CloseSession(session_id_)); } @@ -2217,7 +2228,7 @@ TEST_P(WvCdmStreamingLicenseRenewalTest, WithClientId) { 0u, license_renewal.encrypted_client_id().encrypted_client_id().size()); } - VerifyKeyRequestResponse(license_server, g_client_auth, true); + VerifyKeyRequestResponse(license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -2359,7 +2370,7 @@ TEST_P(WvCdmOfflineLicenseReleaseTest, WithClientId) { 0u, license_release.encrypted_client_id().encrypted_client_id().size()); } - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); decryptor_.CloseSession(session_id_); } @@ -2414,7 +2425,7 @@ TEST_P(WvCdmUsageTest, WithClientId) { &property_set); std::string key_response; - VerifyKeyRequestResponse(g_license_server, g_client_auth, false, + VerifyKeyRequestResponse(g_license_server, g_client_auth, true, &key_response); // Validate signed license @@ -2519,7 +2530,7 @@ TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) { "747265616d696e675f636c697033"); GenerateKeyRequest(key_id, kLicenseTypeStreaming, NULL); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyUsageKeyRequestResponse(g_license_server, g_client_auth); std::vector decrypt_buffer(data->encrypt_data.size()); CdmDecryptionParameters decryption_parameters( @@ -2611,7 +2622,12 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) { key_id.append(1, ch); GenerateKeyRequest(key_id, kLicenseTypeStreaming, property_set); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + + // TODO(rfrias): streaming_clip6 is a streaming license without a pst + if (ch == '6') + VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + else + VerifyUsageKeyRequestResponse(g_license_server, g_client_auth); std::vector decrypt_buffer(data->encrypt_data.size()); CdmDecryptionParameters decryption_parameters( @@ -2691,7 +2707,12 @@ TEST_F(WvCdmRequestLicenseTest, UsageReleaseAllTest) { key_id.append(1, ch); GenerateKeyRequest(key_id, kLicenseTypeStreaming, &property_set); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + + // TODO(rfrias): streaming_clip6 is a streaming license without a pst + if (ch == '6') + VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + else + VerifyUsageKeyRequestResponse(g_license_server, g_client_auth); std::vector decrypt_buffer(data->encrypt_data.size()); CdmDecryptionParameters decryption_parameters( @@ -2779,7 +2800,7 @@ TEST_F(WvCdmRequestLicenseTest, QueryKeyStatus) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); CdmQueryMap query_info; CdmQueryMap::iterator itr; @@ -3013,7 +3034,7 @@ TEST_F(WvCdmRequestLicenseTest, QueryOemCryptoSessionId) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); CdmQueryMap query_info; CdmQueryMap::iterator itr; @@ -3101,7 +3122,7 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); decryptor_.CloseSession(session_id_); @@ -3140,7 +3161,7 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); decryptor_.CloseSession(session_id_); if (security_level != kSecurityLevelL1) return; @@ -3165,7 +3186,7 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) { kDefaultCdmIdentifier, NULL, &session_id_)); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, client_auth, false); + VerifyKeyRequestResponse(g_license_server, client_auth); decryptor_.CloseSession(session_id_); } @@ -3173,7 +3194,7 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_OfflineLicenseDecryptionTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); /* // key 1, encrypted, 256b @@ -3227,7 +3248,7 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_RestoreOfflineLicenseDecryptionTest) { decryptor_.OpenSession(g_key_system, NULL, kDefaultCdmIdentifier, NULL, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeOffline); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); CdmKeySetId key_set_id = key_set_id_; EXPECT_FALSE(key_set_id_.empty()); decryptor_.CloseSession(session_id_); @@ -3289,7 +3310,7 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_RestoreOfflineLicenseDecryptionTest) { TEST_F(WvCdmRequestLicenseTest, KeyControlBlockDecryptionTest) { decryptor_.OpenSession(g_key_system, &session_id_); GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); DecryptionData data; @@ -3355,7 +3376,7 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) { NULL, &session_id_); CdmSessionId gp_session_id_1 = session_id_; GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); // TODO(rfrias): Move content information to ConfigTestEnv std::string gp_client_auth2 = @@ -3369,7 +3390,7 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) { NULL, &session_id_); CdmSessionId gp_session_id_2 = session_id_; GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, gp_client_auth2, false); + VerifyKeyRequestResponse(g_license_server, gp_client_auth2); SubSampleInfo* data = session_sharing_info->sub_sample; std::vector decrypt_buffer(data->encrypt_data.size()); @@ -3414,7 +3435,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) { NULL, &session_id_); CdmSessionId session_id1 = session_id_; GenerateKeyRequest(init_data1, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); // TODO(rfrias): Move content information to ConfigTestEnv std::string gp_client_auth2 = @@ -3428,7 +3449,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) { NULL, &session_id_); CdmSessionId session_id2 = session_id_; GenerateKeyRequest(init_data2, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, gp_client_auth2, false); + VerifyKeyRequestResponse(g_license_server, gp_client_auth2); SubSampleInfo* data = &single_encrypted_sub_sample_short_expiry; @@ -3450,7 +3471,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionSharingTest) { NULL, &session_id_); CdmSessionId session_id3 = session_id_; GenerateKeyRequest(init_data1, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id1, data->validate_key_id, decryption_parameters)); @@ -3475,7 +3496,7 @@ TEST_F(WvCdmRequestLicenseTest, DecryptionKeyExpiredTest) { &session_id_); if (data->retrieve_key) { GenerateKeyRequest(kCpKeyId, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); } std::vector decrypt_buffer(data->encrypt_data.size()); @@ -3516,7 +3537,7 @@ TEST_F(WvCdmRequestLicenseTest, SessionKeyChangeNotificationTest) { "0801121030313233343536373839616263646566"); // pssh data GenerateKeyRequest(kCpKeyId, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -3531,7 +3552,7 @@ TEST_P(WvCdmDecryptionTest, DecryptionTest) { &session_id_); if (data->retrieve_key) { GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); - VerifyKeyRequestResponse(g_license_server, g_client_auth, false); + VerifyKeyRequestResponse(g_license_server, g_client_auth); } uint32_t decrypt_sample_buffer_size = 0; @@ -3574,6 +3595,59 @@ INSTANTIATE_TEST_CASE_P(Cdm, WvCdmDecryptionTest, &switch_key_encrypted_sub_samples[0], &partial_encrypted_sub_samples[0])); +class WvCdmSessionSharingNoKeyTest + : public WvCdmRequestLicenseTest, + public ::testing::WithParamInterface {}; + +TEST_P(WvCdmSessionSharingNoKeyTest, DecryptionTest) { + SubSampleInfo* data = GetParam(); + + TestWvCdmClientPropertySet property_set; + property_set.set_session_sharing_mode(true); + + decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, + NULL, &session_id_); + CdmSessionId gp_session_id_1 = session_id_; + GenerateKeyRequest(g_key_id, kLicenseTypeStreaming); + + // TODO(rfrias): Move content information to ConfigTestEnv + std::string gp_client_auth2 = + "?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine"; + std::string gp_key_id2 = wvcdm::a2bs_hex( + "000000347073736800000000" // blob size and pssh + "edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id + "08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data + + decryptor_.OpenSession(g_key_system, &property_set, kDefaultCdmIdentifier, + NULL, &session_id_); + CdmSessionId gp_session_id_2 = session_id_; + GenerateKeyRequest(gp_key_id2, kLicenseTypeStreaming); + + std::vector decrypt_buffer(data->encrypt_data.size()); + CdmDecryptionParameters decryption_parameters( + &data->key_id, &data->encrypt_data.front(), data->encrypt_data.size(), + &data->iv, data->block_offset, &decrypt_buffer[0]); + decryption_parameters.is_encrypted = data->is_encrypted; + decryption_parameters.is_secure = data->is_secure; + decryption_parameters.subsample_flags = data->subsample_flags; + + EXPECT_EQ(data->is_encrypted ? KEY_NOT_FOUND_IN_SESSION : NO_ERROR, + decryptor_.Decrypt(gp_session_id_2, data->validate_key_id, + decryption_parameters)); + if (!data->is_encrypted) { + EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(), + decrypt_buffer.begin())); + } + + decryptor_.CloseSession(gp_session_id_1); + decryptor_.CloseSession(gp_session_id_2); +} + +INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingNoKeyTest, + ::testing::Values(&clear_sub_sample, + &clear_sub_sample_no_key, + &single_encrypted_sub_sample)); + TEST(VersionNumberTest, VersionNumberChangeCanary) { char release_number[PROPERTY_VALUE_MAX]; ASSERT_GT(property_get("ro.build.version.release", release_number, "Unknown"), @@ -3599,7 +3673,7 @@ TEST_F(WvCdmRequestLicenseTest, AddHlsStreamingKeyTest) { kLicenseTypeStreaming, NULL); //TODO(rfrias): Remove once we switch to git-on-borg std::string license_server = "https://proxy.uat.widevine.com/proxy"; - VerifyKeyRequestResponse(license_server, g_client_auth, false); + VerifyKeyRequestResponse(license_server, g_client_auth); decryptor_.CloseSession(session_id_); } @@ -3643,7 +3717,7 @@ TEST_P(WvHlsDecryptionTest, HlsDecryptionTest) { kLicenseTypeStreaming, NULL); //TODO(rfrias): Remove once we switch to git-on-borg std::string license_server = "https://proxy.uat.widevine.com/proxy"; - VerifyKeyRequestResponse(license_server, g_client_auth, false); + VerifyKeyRequestResponse(license_server, g_client_auth); CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap(); EXPECT_EQ(1u, key_status_map.size()); KeyId key_id = key_status_map.begin()->first; @@ -3697,7 +3771,7 @@ TEST_P(WvHlsFourCCBackwardCompatibilityTest, HlsDecryptionTest) { kLicenseTypeStreaming, NULL); //TODO(rfrias): Remove once we switch to git-on-borg std::string license_server = "https://proxy.uat.widevine.com/proxy"; - VerifyKeyRequestResponse(license_server, g_client_auth, false); + VerifyKeyRequestResponse(license_server, g_client_auth); CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap(); EXPECT_EQ(1u, key_status_map.size()); KeyId key_id = key_status_map.begin()->first; diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index e5e8bd56..41958dba 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -476,7 +476,7 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, if (name == "vendor") { value = "Google"; } else if (name == "version") { - value = "1.0"; + return queryProperty(QUERY_KEY_WVCDM_VERSION, value); } else if (name == "description") { value = "Widevine CDM"; } else if (name == "algorithms") { @@ -519,6 +519,10 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, value = mPropertySet.app_id().c_str(); } else if (name == "origin") { value = mCdmIdentifier.origin.c_str(); + } else if (name == "CurrentSRMVersion") { + return queryProperty(QUERY_KEY_CURRENT_SRM_VERSION, value); + } else if (name == "SRMUpdateSupport") { + return queryProperty(QUERY_KEY_SRM_UPDATE_SUPPORT, value); } else { ALOGE("App requested unknown string property %s", name.string()); return android::ERROR_DRM_CANNOT_HANDLE; @@ -1005,6 +1009,11 @@ status_t WVDrmPlugin::mapOEMCryptoResult(OEMCryptoResult res) { bool WVDrmPlugin::initDataResemblesPSSH(const Vector& initData) { const uint8_t* const initDataArray = initData.array(); + if (sizeof(uint32_t) + kPsshTag.size() > initData.size()) { + // The init data is so small that it couldn't contain a size and PSSH tag. + return false; + } + // Extract the size field const uint8_t* const sizeField = &initDataArray[0]; uint32_t nboSize; diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp index 1d12d40f..23fd4a08 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp @@ -93,6 +93,7 @@ using wvcdm::KEY_ID_SIZE; using wvcdm::KEY_IV_SIZE; using wvcdm::KEY_SET_ID_PREFIX; using wvcdm::NEVER_EXPIRES; +using wvcdm::QUERY_KEY_CURRENT_SRM_VERSION; using wvcdm::QUERY_KEY_DEVICE_ID; using wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS; using wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS; @@ -100,7 +101,9 @@ using wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION; using wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID; using wvcdm::QUERY_KEY_PROVISIONING_ID; using wvcdm::QUERY_KEY_SECURITY_LEVEL; +using wvcdm::QUERY_KEY_SRM_UPDATE_SUPPORT; using wvcdm::QUERY_KEY_SYSTEM_ID; +using wvcdm::QUERY_KEY_WVCDM_VERSION; using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1; using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3; using wvcdm::SecurityLevel; @@ -1045,6 +1048,11 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { static const std::string maxSessions = "54"; static const std::string oemCryptoApiVersion = "13"; + static const std::string currentSRMVersion = "1"; + static const std::string cdmVersion = "Infinity Minus 1"; + std::string serializedMetrics( + kSerializedMetrics, kSerializedMetrics + sizeof(kSerializedMetrics)); + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), testing::Return(wvcdm::NO_ERROR))) @@ -1075,6 +1083,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { .WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion), testing::Return(wvcdm::NO_ERROR))); + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SRM_UPDATE_SUPPORT, _)) + .WillOnce(DoAll(SetArgPointee<2>("True"), + testing::Return(wvcdm::NO_ERROR))); + + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_CURRENT_SRM_VERSION, _)) + .WillOnce(DoAll(SetArgPointee<2>(currentSRMVersion), + testing::Return(wvcdm::NO_ERROR))); + + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_WVCDM_VERSION, _)) + .WillOnce(DoAll(SetArgPointee<2>(cdmVersion), + testing::Return(wvcdm::NO_ERROR))); + + EXPECT_CALL(*cdm, GetSerializedMetrics(_)) + .WillOnce(SetArgPointee<0>(serializedMetrics)); + WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); std::string stringResult; std::vector vectorResult; @@ -1088,7 +1111,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { plugin.getPropertyString( hidl_string("version"), [&](Status status, hidl_string stringResult) { ASSERT_EQ(Status::OK, status); - EXPECT_STREQ("1.0", stringResult.c_str()); + EXPECT_STREQ(cdmVersion.c_str(), stringResult.c_str()); }); plugin.getPropertyString( @@ -1159,7 +1182,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { hidl_string("oemCryptoApiVersion"), [&](Status status, hidl_string stringResult) { ASSERT_EQ(Status::OK, status); - EXPECT_EQ(oemCryptoApiVersion, stringResult.c_str()); + EXPECT_STREQ(oemCryptoApiVersion.c_str(), stringResult.c_str()); + }); + + plugin.getPropertyString( + hidl_string("SRMUpdateSupport"), + [&](Status status, hidl_string stringResult) { + ASSERT_EQ(Status::OK, status); + EXPECT_STREQ("True", stringResult.c_str()); + }); + + plugin.getPropertyString( + hidl_string("CurrentSRMVersion"), + [&](Status status, hidl_string stringResult) { + ASSERT_EQ(Status::OK, status); + EXPECT_STREQ(currentSRMVersion.c_str(), stringResult.c_str()); }); } diff --git a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp index 8be056f0..47510501 100644 --- a/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp +++ b/libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp @@ -838,6 +838,11 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { static const string maxSessions = "18"; static const string oemCryptoApiVersion = "10"; + static const string currentSRMVersion = "1"; + static const string cdmVersion = "Infinity Minus 1"; + string serializedMetrics(kSerializedMetrics, + kSerializedMetrics + sizeof(kSerializedMetrics)); + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), Return(wvcdm::NO_ERROR))) @@ -868,6 +873,21 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { .WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion), Return(wvcdm::NO_ERROR))); + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SRM_UPDATE_SUPPORT, _)) + .WillOnce(DoAll(SetArgPointee<2>("True"), + testing::Return(wvcdm::NO_ERROR))); + + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_CURRENT_SRM_VERSION, _)) + .WillOnce(DoAll(SetArgPointee<2>(currentSRMVersion), + testing::Return(wvcdm::NO_ERROR))); + + EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_WVCDM_VERSION, _)) + .WillOnce(DoAll(SetArgPointee<2>(cdmVersion), + Return(wvcdm::NO_ERROR))); + + EXPECT_CALL(*cdm, GetSerializedMetrics(_)) + .WillOnce(SetArgPointee<0>(serializedMetrics)); + String8 stringResult; Vector vectorResult; @@ -877,7 +897,7 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { res = plugin.getPropertyString(String8("version"), stringResult); ASSERT_EQ(OK, res); - EXPECT_STREQ("1.0", stringResult.string()); + EXPECT_STREQ(cdmVersion.c_str(), stringResult.string()); res = plugin.getPropertyString(String8("description"), stringResult); ASSERT_EQ(OK, res); @@ -918,7 +938,22 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { res = plugin.getPropertyString(String8("oemCryptoApiVersion"), stringResult); ASSERT_EQ(OK, res); - EXPECT_EQ(oemCryptoApiVersion, stringResult.string()); + + EXPECT_STREQ(oemCryptoApiVersion.c_str(), stringResult.string()); + + res = plugin.getPropertyString(String8("SRMUpdateSupport"), stringResult); + ASSERT_EQ(OK, res); + EXPECT_STREQ("True", stringResult.string()); + + res = plugin.getPropertyString(String8("CurrentSRMVersion"), stringResult); + ASSERT_EQ(OK, res); + EXPECT_STREQ(currentSRMVersion.c_str(), stringResult.string()); + + vectorResult.clear(); + res = plugin.getPropertyByteArray(String8("metrics"), vectorResult); + ASSERT_EQ(OK, res); + EXPECT_THAT(vectorResult, ElementsAreArray(serializedMetrics.data(), + serializedMetrics.size())); } TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) {