Add basic handling for entitlement keys in a license.

Merge from Widevine repo of http://go/wvgerrit/41834

Key rotation is not yet supported.

The key statuses are updated from a license. The
mechanism expects content keys tro come in a license.
For entitlement licenses, the content keys come in the
init_data.

This code does not yet support the key rotation event.
(A new pssh with wrapped keys is a passed to the cdm)
The policy engine/key status mechanism needs to be
updated to handle updated from the init_data.

For now, the cdm builds a license with a key container
with the content keys and used that to call
PolicyEngine::SetLicense to setup the policy engine
and key statuses.

Bug: 64003606
Bug: 70334840

Test: In child CL
Change-Id: Ibf46a18f5321cab4ff6f1778ba30527942c8021f
This commit is contained in:
Fred Gylys-Colwell
2018-01-25 15:31:49 -08:00
committed by Rahul Frias
parent 8251aab9f6
commit 9ae7489938
22 changed files with 749 additions and 376 deletions

View File

@@ -35,6 +35,7 @@ LOCAL_SRC_FILES := \
$(CORE_SRC_DIR)/content_key_session.cpp \ $(CORE_SRC_DIR)/content_key_session.cpp \
$(CORE_SRC_DIR)/crypto_session.cpp \ $(CORE_SRC_DIR)/crypto_session.cpp \
$(CORE_SRC_DIR)/device_files.cpp \ $(CORE_SRC_DIR)/device_files.cpp \
$(CORE_SRC_DIR)/entitlement_key_session.cpp \
$(CORE_SRC_DIR)/initialization_data.cpp \ $(CORE_SRC_DIR)/initialization_data.cpp \
$(CORE_SRC_DIR)/license.cpp \ $(CORE_SRC_DIR)/license.cpp \
$(CORE_SRC_DIR)/license_key_status.cpp \ $(CORE_SRC_DIR)/license_key_status.cpp \

View File

@@ -6,23 +6,23 @@
namespace wvcdm { namespace wvcdm {
class DefaultKeySession : public KeySession { class ContentKeySession : public KeySession {
public: public:
DefaultKeySession(CryptoSessionId oec_session_id, ContentKeySession(CryptoSessionId oec_session_id,
metrics::CryptoMetrics* metrics) metrics::CryptoMetrics* metrics)
: KeySession(metrics), oec_session_id_(oec_session_id) {} : KeySession(metrics), oec_session_id_(oec_session_id) {}
virtual ~DefaultKeySession() {} virtual ~ContentKeySession() {}
KeySessionType Type() { return kDefault; } KeySessionType Type() { return kDefault; }
// Generate Derived Keys for DefaultKeySession // Generate Derived Keys for ContentKeySession
bool GenerateDerivedKeys(const std::string& message); bool GenerateDerivedKeys(const std::string& message);
// Generate Derived Keys (from session key) for DefaultKeySession // Generate Derived Keys (from session key) for ContentKeySession
bool GenerateDerivedKeys(const std::string& message, bool GenerateDerivedKeys(const std::string& message,
const std::string& session_key); const std::string& session_key);
// Load Keys for DefaultKeySession // Load Keys for ContentKeySession
OEMCryptoResult LoadKeys(const std::string& message, OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key_iv,
@@ -32,17 +32,29 @@ class DefaultKeySession : public KeySession {
CdmCipherMode* cipher_mode, CdmCipherMode* cipher_mode,
const std::string& srm_requirement); const std::string& srm_requirement);
// Select Key for DefaultKeySession OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& keys) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Select Key for ContentKeySession
OEMCryptoResult SelectKey(const std::string& key_id, OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode); CdmCipherMode cipher_mode);
// Decrypt for DefaultKeySession // Decrypt for ContentKeySession
OEMCryptoResult Decrypt(const CdmDecryptionParameters& params, OEMCryptoResult Decrypt(const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor, OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor); OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor);
private: protected:
OEMCryptoResult LoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
const std::string& srm_requirement, OEMCrypto_LicenseType license_type);
CryptoSessionId oec_session_id_; CryptoSessionId oec_session_id_;
private:
KeyId cached_key_id_; KeyId cached_key_id_;
}; };

View File

@@ -19,6 +19,7 @@ class CryptoKey {
const std::string& key_control_iv() const { return key_control_iv_; } const std::string& key_control_iv() const { return key_control_iv_; }
const std::string& sub_session_key_id() const {return sub_session_key_id_;} const std::string& sub_session_key_id() const {return sub_session_key_id_;}
const std::string& sub_session_key() const {return sub_session_key_;} const std::string& sub_session_key() const {return sub_session_key_;}
const std::string& entitlement_key_id() const {return entitlement_key_id_;}
const std::string& track_label() const { return track_label_; } const std::string& track_label() const { return track_label_; }
CdmCipherMode cipher_mode() const { return cipher_mode_; } CdmCipherMode cipher_mode() const { return cipher_mode_; }
void set_key_id(const std::string& key_id) { key_id_ = key_id; } void set_key_id(const std::string& key_id) { key_id_ = key_id; }
@@ -40,6 +41,9 @@ class CryptoKey {
void set_track_label(const std::string& track_label) { void set_track_label(const std::string& track_label) {
track_label_ = track_label; track_label_ = track_label;
} }
void set_entitlement_key_id(const std::string& entitlement_key_id) {
entitlement_key_id_ = entitlement_key_id;
}
bool HasKeyControl() const { return key_control_.size() >= 16; } bool HasKeyControl() const { return key_control_.size() >= 16; }
@@ -52,6 +56,7 @@ class CryptoKey {
std::string sub_session_key_id_; std::string sub_session_key_id_;
std::string track_label_; std::string track_label_;
std::string sub_session_key_; std::string sub_session_key_;
std::string entitlement_key_id_;
CdmCipherMode cipher_mode_; CdmCipherMode cipher_mode_;
}; };

View File

@@ -12,7 +12,6 @@
#include "lock.h" #include "lock.h"
#include "metrics_collections.h" #include "metrics_collections.h"
#include "oemcrypto_adapter.h" #include "oemcrypto_adapter.h"
#include "OEMCryptoCENC.h"
#include "scoped_ptr.h" #include "scoped_ptr.h"
#include "timer_metric.h" #include "timer_metric.h"
#include "wv_cdm_types.h" #include "wv_cdm_types.h"
@@ -77,13 +76,15 @@ class CryptoSession {
bool is_provisioning, std::string* signature); bool is_provisioning, std::string* signature);
virtual bool PrepareRenewalRequest(const std::string& message, virtual bool PrepareRenewalRequest(const std::string& message,
std::string* signature); std::string* signature);
virtual CdmResponseType LoadKeys(const std::string& message, virtual CdmResponseType LoadKeys(
const std::string& signature, const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key_iv, const std::string& mac_key,
const std::string& mac_key, const std::vector<CryptoKey>& key_array,
const std::vector<CryptoKey>& key_array, const std::string& provider_session_token,
const std::string& provider_session_token, const std::string& srm_requirement,
const std::string& srm_requirement); CdmLicenseKeyType key_type);
virtual CdmResponseType LoadEntitledContentKeys(
const std::vector<CryptoKey>& key_array);
virtual bool LoadCertificatePrivateKey(std::string& wrapped_key); virtual bool LoadCertificatePrivateKey(std::string& wrapped_key);
virtual bool RefreshKeys(const std::string& message, virtual bool RefreshKeys(const std::string& message,
const std::string& signature, int num_keys, const std::string& signature, int num_keys,
@@ -169,19 +170,17 @@ class CryptoSession {
virtual CdmResponseType LoadUsageEntry(uint32_t entry_number, virtual CdmResponseType LoadUsageEntry(uint32_t entry_number,
const CdmUsageEntry& usage_entry); const CdmUsageEntry& usage_entry);
virtual CdmResponseType UpdateUsageEntry( virtual CdmResponseType UpdateUsageEntry(
CdmUsageTableHeader* usage_table_header, CdmUsageTableHeader* usage_table_header, CdmUsageEntry* usage_entry);
CdmUsageEntry* usage_entry);
virtual CdmResponseType ShrinkUsageTableHeader( virtual CdmResponseType ShrinkUsageTableHeader(
uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header); uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header);
virtual CdmResponseType MoveUsageEntry(uint32_t new_entry_number); virtual CdmResponseType MoveUsageEntry(uint32_t new_entry_number);
virtual bool CreateOldUsageEntry( virtual bool CreateOldUsageEntry(uint64_t time_since_license_received,
uint64_t time_since_license_received, uint64_t time_since_first_decrypt,
uint64_t time_since_first_decrypt, uint64_t time_since_last_decrypt,
uint64_t time_since_last_decrypt, UsageDurationStatus status,
UsageDurationStatus status, const std::string& server_mac_key,
const std::string& server_mac_key, const std::string& client_mac_key,
const std::string& client_mac_key, const std::string& provider_session_token);
const std::string& provider_session_token);
virtual CdmResponseType CopyOldUsageEntry( virtual CdmResponseType CopyOldUsageEntry(
const std::string& provider_session_token); const std::string& provider_session_token);
virtual metrics::CryptoMetrics* GetCryptoMetrics() { return metrics_; } virtual metrics::CryptoMetrics* GetCryptoMetrics() { return metrics_; }
@@ -209,15 +208,19 @@ class CryptoSession {
bool SetDestinationBufferType(); bool SetDestinationBufferType();
bool RewrapDeviceRSAKey( bool RewrapDeviceRSAKey(const std::string& message,
const std::string& message, const std::string& signature, const std::string& signature,
const std::string& nonce, const std::string& enc_rsa_key, const std::string& nonce,
const std::string& rsa_key_iv, std::string* wrapped_rsa_key); const std::string& enc_rsa_key,
const std::string& rsa_key_iv,
std::string* wrapped_rsa_key);
bool RewrapDeviceRSAKey30( bool RewrapDeviceRSAKey30(const std::string& message,
const std::string& message, const std::string& nonce, const std::string& nonce,
const std::string& private_key, const std::string& iv, const std::string& private_key,
const std::string& wrapping_key, std::string* wrapped_private_key); const std::string& iv,
const std::string& wrapping_key,
std::string* wrapped_private_key);
CdmResponseType SelectKey(const std::string& key_id, CdmResponseType SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode); CdmCipherMode cipher_mode);

View File

@@ -0,0 +1,34 @@
#ifndef WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_
#define WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_
#include "content_key_session.h"
#include "key_session.h"
namespace wvcdm {
class EntitlementKeySession : public ContentKeySession {
public:
EntitlementKeySession(CryptoSessionId oec_session_id,
metrics::CryptoMetrics* metrics);
virtual ~EntitlementKeySession() {}
KeySessionType Type() { return kEntitlement; }
// Load Keys for ContentKeySession
OEMCryptoResult LoadKeys(const std::string& message,
const std::string& signature,
const std::string& mac_key_iv,
const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token,
CdmCipherMode* cipher_mode,
const std::string& srm_requirement);
OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& keys);
private:
std::vector<CryptoKey> keys_;
};
} // namespace wvcdm
#endif // WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_

View File

@@ -28,8 +28,10 @@ class InitializationData {
const CdmInitData& data() const { return data_; } const CdmInitData& data() const { return data_; }
std::vector<uint8_t> hls_iv() const { return hls_iv_; } std::vector<uint8_t> hls_iv() const { return hls_iv_; }
CdmHlsMethod hls_method() const { return hls_method_; } CdmHlsMethod hls_method() const { return hls_method_; }
std::vector<video_widevine::SubLicense> ExtractEmbeddedKeys() const; // TODO(jfore): Perhaps this should be a generic structure with the ids for
const std::string ExtractGroupMasterKeyId() const; // any type of licensing?
std::vector<video_widevine::SubLicense> ExtractSublicenseKeys() const;
std::vector<video_widevine::WrappedKey> ExtractWrappedKeys() const;
private: private:
// Parse a blob of multiple concatenated PSSH atoms to extract the first // Parse a blob of multiple concatenated PSSH atoms to extract the first

View File

@@ -12,7 +12,7 @@ class KeySession {
KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {} KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {}
public: public:
typedef enum { kDefault, kSubLicense } KeySessionType; typedef enum { kDefault, kSubLicense, kEntitlement } KeySessionType;
virtual ~KeySession() {} virtual ~KeySession() {}
virtual KeySessionType Type() = 0; virtual KeySessionType Type() = 0;
virtual bool GenerateDerivedKeys(const std::string& message) = 0; virtual bool GenerateDerivedKeys(const std::string& message) = 0;
@@ -26,6 +26,8 @@ class KeySession {
const std::string& provider_session_token, const std::string& provider_session_token,
CdmCipherMode* cipher_mode, CdmCipherMode* cipher_mode,
const std::string& srm_requirement) = 0; const std::string& srm_requirement) = 0;
virtual OEMCryptoResult LoadEntitledContentKeys(
const std::vector<CryptoKey>& keys) = 0;
virtual OEMCryptoResult SelectKey(const std::string& key_id, virtual OEMCryptoResult SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) = 0; CdmCipherMode cipher_mode) = 0;
virtual OEMCryptoResult Decrypt( virtual OEMCryptoResult Decrypt(

View File

@@ -29,11 +29,11 @@ class CdmLicense {
CdmLicense(const CdmSessionId& session_id); CdmLicense(const CdmSessionId& session_id);
virtual ~CdmLicense(); virtual ~CdmLicense();
virtual bool Init( virtual bool Init(const std::string& client_token,
const std::string& client_token, CdmClientTokenType client_token_type, CdmClientTokenType client_token_type,
const std::string& device_id, bool use_privacy_mode, const std::string& device_id, bool use_privacy_mode,
const std::string& signed_service_certificate, CryptoSession* session, const std::string& signed_service_certificate,
PolicyEngine* policy_engine); CryptoSession* session, PolicyEngine* policy_engine);
virtual CdmResponseType PrepareKeyRequest( virtual CdmResponseType PrepareKeyRequest(
const InitializationData& init_data, CdmLicenseType license_type, const InitializationData& init_data, CdmLicenseType license_type,
@@ -64,16 +64,13 @@ class CdmLicense {
return provider_session_token_; return provider_session_token_;
} }
virtual bool is_offline() { virtual bool is_offline() { return is_offline_; }
return is_offline_;
}
static bool ExtractProviderSessionToken( static bool ExtractProviderSessionToken(
const CdmKeyResponse& license_response, const CdmKeyResponse& license_response,
std::string* provider_session_token); std::string* provider_session_token);
private: private:
CdmResponseType HandleKeyErrorResponse( CdmResponseType HandleKeyErrorResponse(
const video_widevine::SignedMessage& signed_message); const video_widevine::SignedMessage& signed_message);
@@ -86,9 +83,24 @@ class CdmLicense {
const std::string& request_id, const std::string& request_id,
video_widevine::LicenseRequest* license_request); video_widevine::LicenseRequest* license_request);
CdmResponseType HandleContentKeyResponse(
const std::string& msg, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& key_array,
const video_widevine::License& license);
// HandleEntitlementKeyResponse loads the entitlement keys in |key_array| into
// the crypto session. In addition, it also extracts content keys from
// |wrapped_keys_| and loads them for use.
CdmResponseType HandleEntitlementKeyResponse(
const std::string& msg, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& key_array,
const video_widevine::License& license);
template <typename T> template <typename T>
bool SetTypeAndId(CdmLicenseType license_type, bool SetTypeAndId(CdmLicenseType license_type, const std::string& request_id,
const std::string& request_id, T* content_id); T* content_id);
CryptoSession* crypto_session_; CryptoSession* crypto_session_;
PolicyEngine* policy_engine_; PolicyEngine* policy_engine_;
@@ -121,6 +133,12 @@ class CdmLicense {
// sub session keys we may have received in a license response. These keys // sub session keys we may have received in a license response. These keys
// may be used to support key rotation. // may be used to support key rotation.
std::vector<CryptoKey> sub_session_key_array_; std::vector<CryptoKey> sub_session_key_array_;
// For entitlement key licensing. This holds the keys from the init_data.
// These keys are extracted from the pssh when we generate a license request.
// It is used to load content keys after we have received a license and
// entitelement keys. It is also used in updating the key status info.
std::vector<video_widevine::WrappedKey> wrapped_keys_;
#if defined(UNIT_TEST) #if defined(UNIT_TEST)
friend class CdmLicenseTest; friend class CdmLicenseTest;
#endif #endif

View File

@@ -18,7 +18,7 @@ class SubLicenseKeySession : public KeySession {
metrics::CryptoMetrics* metrics, metrics::CryptoMetrics* metrics,
const std::string& wrapped_private_device_key, const std::string& wrapped_private_device_key,
SecurityLevel requested_security_level, SecurityLevel requested_security_level,
const std::string& group_master_key_id); const std::string& group_id);
virtual ~SubLicenseKeySession(); virtual ~SubLicenseKeySession();
@@ -43,6 +43,10 @@ class SubLicenseKeySession : public KeySession {
CdmCipherMode* cipher_mode, CdmCipherMode* cipher_mode,
const std::string& srm_requirement); const std::string& srm_requirement);
OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& keys) {
return OEMCrypto_ERROR_INVALID_CONTEXT;
}
// Each oemcrypto session contains a single key. Find the right sub session // Each oemcrypto session contains a single key. Find the right sub session
// and save it's id as the selected oemcrypto session. // and save it's id as the selected oemcrypto session.
OEMCryptoResult SelectKey(const std::string& key_id, OEMCryptoResult SelectKey(const std::string& key_id,
@@ -83,7 +87,7 @@ class SubLicenseKeySession : public KeySession {
std::vector<CryptoKey> keys_; std::vector<CryptoKey> keys_;
SubLicenseSessionMap& sub_license_oec_sessions_; SubLicenseSessionMap& sub_license_oec_sessions_;
SecurityLevel requested_security_level_; SecurityLevel requested_security_level_;
KeyId group_master_key_id_; KeyId group_id_;
}; };
} // namespace wvcdm } // namespace wvcdm

View File

@@ -345,6 +345,11 @@ enum CdmLicenseType {
kLicenseTypeSubSession kLicenseTypeSubSession
}; };
enum CdmLicenseKeyType {
kLicenseKeyTypeContent,
kLicenseKeyTypeEntitlement
};
enum SecurityLevel { enum SecurityLevel {
kLevelDefault, kLevelDefault,
kLevel3 kLevel3

View File

@@ -382,11 +382,11 @@ CdmResponseType CdmSession::GenerateKeyRequest(
} }
std::vector<video_widevine::SubLicense> embedded_key_data = std::vector<video_widevine::SubLicense> embedded_key_data =
init_data.ExtractEmbeddedKeys(); init_data.ExtractSublicenseKeys();
for (size_t i = 0; i < embedded_key_data.size(); ++i) { for (size_t i = 0; i < embedded_key_data.size(); ++i) {
CdmResponseType sts = crypto_session_->AddSubSession( CdmResponseType sts = crypto_session_->AddSubSession(
embedded_key_data[i].sub_session_key_id(), embedded_key_data[i].sub_session_key_id(),
init_data.ExtractGroupMasterKeyId()); embedded_key_data[i].group_id());
if (NO_ERROR != sts) { if (NO_ERROR != sts) {
LOGE("CdmSession::GenerateKeyRequest: Unable to generate sub session"); LOGE("CdmSession::GenerateKeyRequest: Unable to generate sub session");
return sts; return sts;

View File

@@ -6,8 +6,8 @@
namespace wvcdm { namespace wvcdm {
// Generate Derived Keys for DefaultKeySession // Generate Derived Keys for ContentKeySession
bool DefaultKeySession::GenerateDerivedKeys(const std::string& message) { bool ContentKeySession::GenerateDerivedKeys(const std::string& message) {
std::string mac_deriv_message; std::string mac_deriv_message;
std::string enc_deriv_message; std::string enc_deriv_message;
GenerateMacContext(message, &mac_deriv_message); GenerateMacContext(message, &mac_deriv_message);
@@ -30,8 +30,8 @@ bool DefaultKeySession::GenerateDerivedKeys(const std::string& message) {
return true; return true;
} }
// Generate Derived Keys (from session key) for DefaultKeySession // Generate Derived Keys (from session key) for ContentKeySession
bool DefaultKeySession::GenerateDerivedKeys(const std::string& message, bool ContentKeySession::GenerateDerivedKeys(const std::string& message,
const std::string& session_key) { const std::string& session_key) {
std::string mac_deriv_message; std::string mac_deriv_message;
std::string enc_deriv_message; std::string enc_deriv_message;
@@ -58,13 +58,65 @@ bool DefaultKeySession::GenerateDerivedKeys(const std::string& message,
return true; return true;
} }
// Load Keys for DefaultKeySession // Load Keys for ContentKeySession
OEMCryptoResult DefaultKeySession::LoadKeys( OEMCryptoResult ContentKeySession::LoadKeys(
const std::string& message, const std::string& signature, const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key, const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys, const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, CdmCipherMode* cipher_mode, const std::string& provider_session_token, CdmCipherMode* cipher_mode,
const std::string& srm_requirement) { const std::string& srm_requirement) {
return LoadKeys(message, signature, mac_key_iv, mac_key, keys,
provider_session_token, cipher_mode, srm_requirement,
OEMCrypto_ContentLicense);
}
// Select Key for ContentKeySession
OEMCryptoResult ContentKeySession::SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
// Crypto session lock already locked.
if (!cached_key_id_.empty() && cached_key_id_ == key_id) {
// Already using the desired key.
return OEMCrypto_SUCCESS;
}
cached_key_id_ = key_id;
const uint8_t* key_id_string =
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_SelectKey(
oec_session_id_, key_id_string, cached_key_id_.size(),
static_cast<OEMCryptoCipherMode>(cipher_mode)),
metrics_, oemcrypto_select_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
cached_key_id_.clear();
}
return sts;
}
// Decrypt for ContentKeySession
OEMCryptoResult ContentKeySession::Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DecryptCENC(
oec_session_id_, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags),
metrics_, oemcrypto_decrypt_cenc_, sts,
metrics::Pow2Bucket(params.encrypt_length));
return sts;
}
OEMCryptoResult ContentKeySession::LoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
const std::string& srm_requirement, OEMCrypto_LicenseType license_type) {
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data()); const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL; const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL; const uint8_t* enc_mac_key_iv = NULL;
@@ -72,7 +124,7 @@ OEMCryptoResult DefaultKeySession::LoadKeys(
enc_mac_key = msg + GetOffset(message, mac_key); enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else { } else {
LOGV("DefaultKeySession::LoadKeys: enc_mac_key not set"); LOGV("ContentKeySession::LoadKeys: enc_mac_key not set");
} }
std::vector<OEMCrypto_KeyObject> load_keys(keys.size()); std::vector<OEMCrypto_KeyObject> load_keys(keys.size());
for (size_t i = 0; i < keys.size(); ++i) { for (size_t i = 0; i < keys.size(); ++i) {
@@ -114,50 +166,9 @@ OEMCryptoResult DefaultKeySession::LoadKeys(
oec_session_id_, msg, message.size(), oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst, enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst,
provider_session_token.length(), srm_req, OEMCrypto_ContentLicense), provider_session_token.length(), srm_req, license_type),
metrics_, oemcrypto_load_keys_, sts); metrics_, oemcrypto_load_keys_, sts);
return sts; return sts;
} }
// Select Key for DefaultKeySession
OEMCryptoResult DefaultKeySession::SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) {
// Crypto session lock already locked.
if (!cached_key_id_.empty() && cached_key_id_ == key_id) {
// Already using the desired key.
return OEMCrypto_SUCCESS;
}
cached_key_id_ = key_id;
const uint8_t* key_id_string =
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_SelectKey(
oec_session_id_, key_id_string, cached_key_id_.size(),
static_cast<OEMCryptoCipherMode>(cipher_mode)),
metrics_, oemcrypto_select_key_, sts);
if (OEMCrypto_SUCCESS != sts) {
cached_key_id_.clear();
}
return sts;
}
// Decrypt for DefaultKeySession
OEMCryptoResult DefaultKeySession::Decrypt(
const CdmDecryptionParameters& params,
OEMCrypto_DestBufferDesc& buffer_descriptor,
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) {
OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_DecryptCENC(
oec_session_id_, params.encrypt_buffer, params.encrypt_length,
params.is_encrypted, &(*params.iv).front(), params.block_offset,
&buffer_descriptor, &pattern_descriptor, params.subsample_flags),
metrics_, oemcrypto_decrypt_cenc_, sts,
metrics::Pow2Bucket(params.encrypt_length));
return sts;
}
} // namespace wvcdm } // namespace wvcdm

View File

@@ -13,6 +13,7 @@
#include "content_key_session.h" #include "content_key_session.h"
#include "crypto_key.h" #include "crypto_key.h"
#include "entitlement_key_session.h"
#include "log.h" #include "log.h"
#include "openssl/asn1.h" #include "openssl/asn1.h"
#include "openssl/sha.h" #include "openssl/sha.h"
@@ -119,6 +120,12 @@ void GenerateEncryptContext(const std::string& input_context,
deriv_context->append(EncodeUint32(kEncryptionKeySizeBits)); deriv_context->append(EncodeUint32(kEncryptionKeySizeBits));
} }
OEMCrypto_LicenseType OEMCryptoLicenseType(CdmLicenseKeyType cdm_license_type) {
return cdm_license_type == kLicenseKeyTypeContent
? OEMCrypto_ContentLicense
: OEMCrypto_EntitlementLicense;
}
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics) CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
: metrics_(metrics), : metrics_(metrics),
system_id_(-1), system_id_(-1),
@@ -692,7 +699,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
} }
// TODO(gmorgan, jfore): resolve handling of usage records in sublicenses // TODO(gmorgan, jfore): resolve handling of usage records in sublicenses
key_session_.reset(new DefaultKeySession(oec_session_id_, metrics_)); key_session_.reset(new ContentKeySession(oec_session_id_, metrics_));
return NO_ERROR; return NO_ERROR;
} }
@@ -779,10 +786,15 @@ CdmResponseType CryptoSession::LoadKeys(
const std::string& mac_key_iv, const std::string& mac_key, const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys, const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, const std::string& provider_session_token,
const std::string& srm_requirement) { const std::string& srm_requirement, CdmLicenseKeyType key_type) {
LOGV("CryptoSession::LoadKeys: Lock"); LOGV("CryptoSession::LoadKeys: Lock");
AutoLock auto_lock(crypto_lock_); AutoLock auto_lock(crypto_lock_);
if (key_type == kLicenseKeyTypeEntitlement &&
key_session_->Type() != KeySession::kEntitlement) {
key_session_.reset(new EntitlementKeySession(oec_session_id_, metrics_));
}
LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_); LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts = key_session_->LoadKeys( OEMCryptoResult sts = key_session_->LoadKeys(
message, signature, mac_key_iv, mac_key, keys, provider_session_token, message, signature, mac_key_iv, mac_key, keys, provider_session_token,
@@ -815,6 +827,13 @@ CdmResponseType CryptoSession::LoadKeys(
return result; return result;
} }
CdmResponseType CryptoSession::LoadEntitledContentKeys(
const std::vector<CryptoKey>& key_array) {
// TODO(jfore): Handle and return errors.
/*OEMCryptoResult status =*/ key_session_->LoadEntitledContentKeys(key_array);
return KEY_ADDED;
}
bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) { bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) {
LOGV("CryptoSession::LoadCertificatePrivateKey: Lock"); LOGV("CryptoSession::LoadCertificatePrivateKey: Lock");
AutoLock auto_lock(crypto_lock_); AutoLock auto_lock(crypto_lock_);

View File

@@ -0,0 +1,54 @@
#include "entitlement_key_session.h"
#include "crypto_key.h"
namespace wvcdm {
EntitlementKeySession::EntitlementKeySession(CryptoSessionId oec_session_id,
metrics::CryptoMetrics* metrics)
: ContentKeySession(oec_session_id, metrics) {}
OEMCryptoResult EntitlementKeySession::LoadKeys(
const std::string& message, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& keys,
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
const std::string& srm_requirement) {
keys_.resize(keys.size());
return ContentKeySession::LoadKeys(
message, signature, mac_key_iv, mac_key, keys, provider_session_token,
cipher_mode, srm_requirement, OEMCrypto_EntitlementLicense);
}
OEMCryptoResult EntitlementKeySession::LoadEntitledContentKeys(
const std::vector<CryptoKey>& keys) {
// The array |keys| contains new content keys, plus entitlement key ids for
// those content keys.
std::vector<OEMCrypto_EntitledContentKeyObject> entitlements;
entitlements.resize(keys.size());
for (size_t i = 0; i < keys.size(); ++i) {
entitlements[i].entitlement_key_id =
reinterpret_cast<const uint8_t*>(keys[i].entitlement_key_id().data());
entitlements[i].entitlement_key_id_length =
keys[i].entitlement_key_id().size();
entitlements[i].content_key_id =
reinterpret_cast<const uint8_t*>(keys[i].key_id().data());
entitlements[i].content_key_id_length = keys[i].key_id().size();
entitlements[i].content_key_data_iv =
reinterpret_cast<const uint8_t*>(keys[i].key_data_iv().data());
entitlements[i].content_key_data =
reinterpret_cast<const uint8_t*>(keys[i].key_data().data());
entitlements[i].content_key_data_length = keys[i].key_data().size();
}
OEMCryptoResult result = OEMCrypto_SUCCESS;
M_TIME(result = OEMCrypto_LoadEntitledContentKeys(
oec_session_id_, entitlements.size(), &entitlements[0]),
metrics_, oemcrypto_load_entitled_keys_, result);
return result;
}
} // namespace wvcdm

View File

@@ -67,7 +67,7 @@ InitializationData::InitializationData(const std::string& type,
// Parse the pssh data and return the embedded key data if it exists. // Parse the pssh data and return the embedded key data if it exists.
std::vector<video_widevine::SubLicense> std::vector<video_widevine::SubLicense>
InitializationData::ExtractEmbeddedKeys() const { InitializationData::ExtractSublicenseKeys() const {
std::vector<video_widevine::SubLicense> keys; std::vector<video_widevine::SubLicense> keys;
WidevinePsshData cenc_header; WidevinePsshData cenc_header;
if (!is_cenc_ || !cenc_header.ParseFromString(data_) || if (!is_cenc_ || !cenc_header.ParseFromString(data_) ||
@@ -81,6 +81,20 @@ InitializationData::ExtractEmbeddedKeys() const {
return keys; return keys;
} }
std::vector<video_widevine::WrappedKey> InitializationData::ExtractWrappedKeys()
const {
std::vector<video_widevine::WrappedKey> keys;
WidevinePsshData cenc_header;
if (!is_cenc_ || !cenc_header.ParseFromString(data_) ||
cenc_header.entitled_keys().size() == 0)
return keys;
keys.reserve(cenc_header.entitled_keys().size());
for (int i = 0; i < cenc_header.entitled_keys().size(); ++i) {
keys.push_back(cenc_header.entitled_keys(i));
}
return keys;
}
// Parse a blob of multiple concatenated PSSH atoms to extract the first // Parse a blob of multiple concatenated PSSH atoms to extract the first
// Widevine PSSH. // Widevine PSSH.
bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data, bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data,
@@ -483,7 +497,7 @@ bool InitializationData::ConstructWidevineInitData(
// have not yet been pushed to production. Set until then. // have not yet been pushed to production. Set until then.
cenc_header.set_algorithm(WidevinePsshData_Algorithm_AESCTR); cenc_header.set_algorithm(WidevinePsshData_Algorithm_AESCTR);
for (size_t i = 0; i < key_ids.size(); ++i) { for (size_t i = 0; i < key_ids.size(); ++i) {
cenc_header.add_key_id(key_ids[i]); cenc_header.add_key_ids(key_ids[i]);
} }
cenc_header.set_provider(provider); cenc_header.set_provider(provider);
cenc_header.set_content_id(content_id); cenc_header.set_content_id(content_id);
@@ -589,19 +603,4 @@ std::vector<std::string> InitializationData::ExtractKeyFormatVersions(
return versions; return versions;
} }
// Extract the key id of the group master key used to generate sublicense data.
// Returns an empty string if not defined.
const std::string InitializationData::ExtractGroupMasterKeyId() const {
if (!is_cenc_) {
return "";
}
WidevinePsshData cenc_header;
if (!cenc_header.ParseFromString(data_)) {
return "";
}
return cenc_header.group_master_key_id();
}
} // namespace wvcdm } // namespace wvcdm

View File

@@ -72,6 +72,54 @@ static std::vector<CryptoKey> ExtractSubSessionKeys(const License& license) {
return key_array; return key_array;
} }
static std::vector<CryptoKey> ExtractEntitlementKeys(const License& license) {
std::vector<CryptoKey> key_array;
// Extract sub session key(s)
for (int i = 0; i < license.key_size(); ++i) {
CryptoKey key;
switch (license.key(i).type()) {
case License_KeyContainer::ENTITLEMENT: {
key.set_key_data(license.key(i).key());
key.set_key_data_iv(license.key(i).iv());
key.set_key_id(license.key(i).id());
key.set_track_label(license.key(i).track_label());
if (license.key(i).has_key_control()) {
key.set_key_control(license.key(i).key_control().key_control_block());
key.set_key_control_iv(license.key(i).key_control().iv());
}
uint32_t four_cc = kFourCcCenc;
if (license.has_protection_scheme()) {
four_cc = license.protection_scheme();
}
key.set_track_label(license.key(i).track_label());
switch (four_cc) {
// b/30713238: Android N assumed that the "protection scheme" Four
// CC code, after being extracted from the protobuf, was host byte
// order dependent. Later versions do not assume this, and thus,
// for backwards compatibility, must support both byte orders.
case kFourCcCbc1:
case kFourCcCbcs:
case kFourCcLittleEndianCbc1:
case kFourCcLittleEndianCbcs:
key.set_cipher_mode(kCipherModeCbc);
break;
default:
key.set_cipher_mode(kCipherModeCtr);
break;
}
key_array.push_back(key);
} break;
default:
// Ignore all but ENTITLEMENT key types.
break;
}
}
return key_array;
}
static std::vector<CryptoKey> ExtractContentKeys(const License& license) { static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
std::vector<CryptoKey> key_array; std::vector<CryptoKey> key_array;
@@ -239,6 +287,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
return PrepareKeyRequest(restored_init_data, license_type, app_parameters, return PrepareKeyRequest(restored_init_data, license_type, app_parameters,
signed_request, server_url); signed_request, server_url);
} }
wrapped_keys_ = init_data.ExtractWrappedKeys();
if (!init_data.is_supported()) { if (!init_data.is_supported()) {
LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)", LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)",
init_data.type().c_str()); init_data.type().c_str());
@@ -306,7 +355,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
// Prepare the request for any embedded keys that may exist in the // Prepare the request for any embedded keys that may exist in the
// initialization data. // initialization data.
std::vector<video_widevine::SubLicense> embedded_key_data = std::vector<video_widevine::SubLicense> embedded_key_data =
init_data.ExtractEmbeddedKeys(); init_data.ExtractSublicenseKeys();
for (size_t i = 0; i < embedded_key_data.size(); ++i) { for (size_t i = 0; i < embedded_key_data.size(); ++i) {
bool exists = false; bool exists = false;
if (!crypto_session_->GenerateSubSessionNonce( if (!crypto_session_->GenerateSubSessionNonce(
@@ -575,8 +624,15 @@ CdmResponseType CdmLicense::HandleKeyResponse(
} }
} }
std::vector<CryptoKey> key_array = ExtractContentKeys(license); CdmLicenseKeyType key_type = kLicenseKeyTypeEntitlement;
if (!key_array.size()) { std::vector<CryptoKey> key_array = ExtractEntitlementKeys(license);
if (key_array.empty()) {
key_array = ExtractContentKeys(license);
key_type = kLicenseKeyTypeContent;
} else if (wrapped_keys_.empty()) {
key_array.clear();
}
if (key_array.empty()) {
LOGE("CdmLicense::HandleKeyResponse : No content keys."); LOGE("CdmLicense::HandleKeyResponse : No content keys.");
return NO_CONTENT_KEY; return NO_CONTENT_KEY;
} }
@@ -601,17 +657,15 @@ CdmResponseType CdmLicense::HandleKeyResponse(
renew_with_client_id_ = license.policy().always_include_client_id(); renew_with_client_id_ = license.policy().always_include_client_id();
} }
CdmResponseType resp = crypto_session_->LoadKeys( CdmResponseType resp = NO_CONTENT_KEY;
signed_response.msg(), signed_response.signature(), mac_key_iv, mac_key, if (kLicenseKeyTypeEntitlement == key_type) {
key_array, provider_session_token_, license.srm_requirement()); resp = HandleEntitlementKeyResponse(signed_response.msg(),
signed_response.signature(), mac_key_iv,
if (KEY_ADDED == resp) { mac_key, key_array, license);
loaded_keys_.clear(); } else if (kLicenseKeyTypeContent == key_type) {
for (std::vector<CryptoKey>::iterator it = key_array.begin(); resp = HandleContentKeyResponse(signed_response.msg(),
it != key_array.end(); ++it) { signed_response.signature(), mac_key_iv,
loaded_keys_.insert(it->key_id()); mac_key, key_array, license);
}
policy_engine_->SetLicense(license);
} }
return resp; return resp;
} }
@@ -699,7 +753,7 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
CdmResponseType CdmLicense::HandleSubLicense( CdmResponseType CdmLicense::HandleSubLicense(
const InitializationData& init_data) { const InitializationData& init_data) {
std::vector<video_widevine::SubLicense> subkeys = std::vector<video_widevine::SubLicense> subkeys =
init_data.ExtractEmbeddedKeys(); init_data.ExtractSublicenseKeys();
std::set<KeyId> loaded_keys; std::set<KeyId> loaded_keys;
// Build a license with the rotated keys. // Build a license with the rotated keys.
License license; License license;
@@ -732,7 +786,7 @@ CdmResponseType CdmLicense::HandleSubLicense(
//TODO: passing empty cipher_mode and srm_req params - OK? //TODO: passing empty cipher_mode and srm_req params - OK?
CdmResponseType result = crypto_session_->LoadKeys( CdmResponseType result = crypto_session_->LoadKeys(
sm.msg(), sm.signature(), std::string(), std::string(), keys, sm.msg(), sm.signature(), std::string(), std::string(), keys,
std::string(), std::string()); std::string(), std::string(), kLicenseKeyTypeContent);
if (result != KEY_ADDED) { if (result != KEY_ADDED) {
LOGE("CdmLicense::HandleSubLicense: LoadKeys() call failed, result=%d", LOGE("CdmLicense::HandleSubLicense: LoadKeys() call failed, result=%d",
result); result);
@@ -1049,6 +1103,104 @@ CdmResponseType CdmLicense::PrepareContentId(
return NO_ERROR; return NO_ERROR;
} }
CdmResponseType CdmLicense::HandleContentKeyResponse(
const std::string& msg, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& key_array,
const video_widevine::License& license) {
if (key_array.empty()) {
LOGE("CdmLicense::HandleKeyResponse : No content keys.");
return NO_CONTENT_KEY;
}
CdmResponseType resp = crypto_session_->LoadKeys(
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
license.srm_requirement(), kLicenseKeyTypeContent);
if (KEY_ADDED == resp) {
loaded_keys_.clear();
for (std::vector<CryptoKey>::const_iterator it = key_array.begin();
it != key_array.end(); ++it) {
loaded_keys_.insert(it->key_id());
}
policy_engine_->SetLicense(license);
}
return resp;
}
CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
const std::string& msg, const std::string& signature,
const std::string& mac_key_iv, const std::string& mac_key,
const std::vector<CryptoKey>& key_array,
const video_widevine::License& license) {
if (key_array.empty() || wrapped_keys_.empty()) {
LOGE("CdmLicense::HandleKeyResponse : No content keys.");
return NO_CONTENT_KEY;
}
CdmResponseType resp = crypto_session_->LoadKeys(
msg, signature, mac_key_iv, mac_key, key_array, provider_session_token_,
license.srm_requirement(), kLicenseKeyTypeEntitlement);
if (KEY_ADDED != resp) {
return resp;
}
std::vector<CryptoKey> entitled_key_array;
entitled_key_array.reserve(key_array.size());
for (std::vector<video_widevine::WrappedKey>::iterator wk =
wrapped_keys_.begin();
wk != wrapped_keys_.end(); wk++) {
for (std::vector<CryptoKey>::const_iterator key = key_array.begin();
key != key_array.end(); key++) {
if (wk->wrapping_key_id() == key->key_id()) {
entitled_key_array.resize(entitled_key_array.size() + 1);
CryptoKey& this_entry = entitled_key_array.back();
this_entry.set_key_id(wk->key_id());
this_entry.set_key_data(wk->wrapped_key());
this_entry.set_key_data_iv(wk->wrapping_iv());
this_entry.set_entitlement_key_id(wk->wrapping_key_id());
}
}
}
resp = crypto_session_->LoadEntitledContentKeys(entitled_key_array);
if (KEY_ADDED == resp) {
loaded_keys_.clear();
for (std::vector<video_widevine::WrappedKey>::const_iterator it =
wrapped_keys_.begin();
it != wrapped_keys_.end(); ++it) {
loaded_keys_.insert(it->key_id());
}
// TODO(jfore): Move the information to build this "license" to the
// entitlement key session. It is used to update the policy engine and
// key status when using entitlement licenses. It may become unnecessary
// if policy manager ius changed to allow setting keys from the wrapped
// keys from init_data.
video_widevine::License entitled_license;
entitled_license.mutable_policy()->CopyFrom(license.policy());
entitled_license.mutable_id()->CopyFrom(license.id());
entitled_license.mutable_key()->CopyFrom(license.key());
entitled_license.set_license_start_time(license.license_start_time());
for (size_t i = 0; i < wrapped_keys_.size(); ++i) {
for (int x = 0; x < entitled_license.key().size(); ++x) {
LOGE("Test for %s", wrapped_keys_[i].wrapping_key_id().c_str());
if (entitled_license.key(x).id() ==
wrapped_keys_[i].wrapping_key_id()) {
video_widevine::License::KeyContainer* kc =
entitled_license.mutable_key(x);
kc->set_type(video_widevine::License::KeyContainer::CONTENT);
kc->set_key(wrapped_keys_[i].wrapped_key());
kc->set_id(wrapped_keys_[i].key_id());
LOGE("Add %s", wrapped_keys_[i].wrapping_key_id().c_str());
}
}
}
LOGE("%d license keys", entitled_license.key_size());
policy_engine_->SetLicense(entitled_license);
}
return resp;
}
template <typename T> template <typename T>
bool CdmLicense::SetTypeAndId(CdmLicenseType license_type, bool CdmLicense::SetTypeAndId(CdmLicenseType license_type,
const std::string& request_id, T* content_id) { const std::string& request_id, T* content_id) {

View File

@@ -102,6 +102,7 @@ message License {
KEY_CONTROL = 3; KEY_CONTROL = 3;
OPERATOR_SESSION = 4; OPERATOR_SESSION = 4;
SUB_SESSION = 5; SUB_SESSION = 5;
ENTITLEMENT = 6;
} }
// The SecurityLevel enumeration allows the server to communicate the level // The SecurityLevel enumeration allows the server to communicate the level
@@ -719,28 +720,54 @@ message SubLicense {
// proto. Internally the message field will contain a serialized KeyContainer // proto. Internally the message field will contain a serialized KeyContainer
// holding a single content key. // holding a single content key.
optional bytes key_msg = 2; optional bytes key_msg = 2;
// TODO(jfore): There is some uncertainty about including the current group in
// a license. This may change.
// Byte string that identifies the group to which this this content
// belongs.
optional bytes group_id = 13;
}
// Container for keys which are wrapped using an entitlement key from a master
// license.
message WrappedKey {
// ID of the wrapped key. Required.
optional bytes key_id = 1;
// ID of wrapping key. Required.
optional bytes wrapping_key_id = 2;
// IV used to wrap the key. Required.
optional bytes wrapping_iv = 3;
// Encrypted entitled key. Wrapped with the entitlement key and IV, using
// AES-256-CBC with PKCS#7 padding. Required.
optional bytes wrapped_key = 4;
} }
message WidevinePsshData { message WidevinePsshData {
// Superceded by protection_scheme.
enum Algorithm { enum Algorithm {
UNENCRYPTED = 0; UNENCRYPTED = 0;
AESCTR = 1; AESCTR = 1;
}; };
// Replaced with protection_scheme.
optional Algorithm algorithm = 1; optional Algorithm algorithm = 1 [deprecated = true];
repeated bytes key_id = 2;
// Key IDentifier(s). This field is mutually exclusive with content_id, below.
// Only One or the other, but at least one must be present.
repeated bytes key_ids = 2;
// Content provider name. // Content provider name.
optional string provider = 3; optional string provider = 3 [deprecated = true];
// A content identifier, specified by content provider. // A content identifier, specified by content provider.
// This field is mutually exclusive with key_ids, above. Only
// one or the other, but at least one must be present.
optional bytes content_id = 4; optional bytes content_id = 4;
// Track type. Acceptable values are SD, HD and AUDIO. Used to differentiate // Track type. Acceptable values are SD, HD and AUDIO. Used to differentiate
// content keys used by an asset. // content keys used by an asset.
// No longer adding track_type to the PSSH since the Widevine license server // No longer adding track_type to the PSSH since the Widevine license server
// will return keys for all allowed track types in a single license. // will return keys for all allowed track types in a single license.
optional string track_type_deprecated = 5; optional string track_type = 5 [deprecated = true];
// The name of a registered policy to be used for this asset. // The name of a registered policy to be used for this asset.
optional string policy = 6 [deprecated=true]; optional string policy = 6 [deprecated=true];
@@ -750,16 +777,16 @@ message WidevinePsshData {
// Optional protected context for group content. The grouped_license is a // Optional protected context for group content. The grouped_license is a
// serialized SignedMessage. // serialized SignedMessage.
optional bytes grouped_license = 8; optional bytes grouped_license = 8 [deprecated = true];
// Protection scheme identifying the encryption algorithm. The protection // Protection scheme identifying the encryption algorithm. The protection
// scheme is represented as a uint32 value. The uint32 contains 4 bytes each // scheme is represented as a uint32 value. The uint32 contains 4 bytes each
// representing a single ascii character in one of the 4CC protection scheme // representing a single ascii character in one of the 4CC protection scheme
// values. // values. To be soon deprecated in favor of signaling from content.
// 'cenc' (AES-CTR) protection_scheme = 0x63656E63, // 'cenc' (AES-CTR) protection_scheme = 0x63656E63,
// 'cbc1' (AES-CBC) protection_scheme = 0x63626331, // 'cbc1' (AES-CBC) protection_scheme = 0x63626331,
// 'cens' (AES-CTR subsample) protection_scheme = 0x63656E73, // 'cens' (AES-CTR pattern encryption) protection_scheme = 0x63656E73,
// 'cbcs' (AES-CBC subsample) protection_scheme = 0x63626373. // 'cbcs' (AES-CBC pattern encryption) protection_scheme = 0x63626373.
optional uint32 protection_scheme = 9; optional uint32 protection_scheme = 9;
// Optional. For media using key rotation, this represents the duration // Optional. For media using key rotation, this represents the duration
@@ -769,9 +796,15 @@ message WidevinePsshData {
// Required when using content keys that are embedded in content. // Required when using content keys that are embedded in content.
repeated SubLicense sub_licenses = 11; repeated SubLicense sub_licenses = 11;
// Key ID used to identify the group master key License Server is supposed // IDs of the groups to which the content belongs. A group is a set of
// to use to generate group license. // content IDs. A particular piece of content may belong to multiple groups.
optional string group_master_key_id = 12; repeated bytes group_ids = 12;
// Copy/copies of the content key used to decrypt the media stream in which
// the PSSH box is embedded, each wrapped with a different entitlement key.
// May be repeated if using group entitlement keys. Optional, used for content
// key rotation.
repeated WrappedKey entitled_keys = 13;
} }
// Signed device certificate definition. // Signed device certificate definition.

View File

@@ -11,13 +11,13 @@ SubLicenseKeySession::SubLicenseKeySession(
metrics::CryptoMetrics* metrics, metrics::CryptoMetrics* metrics,
const std::string& wrapped_private_device_key, const std::string& wrapped_private_device_key,
SecurityLevel requested_security_level, SecurityLevel requested_security_level,
const std::string& group_master_key_id) const std::string& group_id)
: KeySession(metrics), : KeySession(metrics),
state_(kInitializing), state_(kInitializing),
wrapped_private_device_key_(wrapped_private_device_key), wrapped_private_device_key_(wrapped_private_device_key),
sub_license_oec_sessions_(sub_license_oec_sessions), sub_license_oec_sessions_(sub_license_oec_sessions),
requested_security_level_(requested_security_level), requested_security_level_(requested_security_level),
group_master_key_id_(group_master_key_id) {} group_id_(group_id) {}
SubLicenseKeySession::~SubLicenseKeySession() { SubLicenseKeySession::~SubLicenseKeySession() {
for (SubLicenseSessionMap::iterator oec_session = for (SubLicenseSessionMap::iterator oec_session =
@@ -267,9 +267,9 @@ OEMCryptoResult SubLicenseKeySession::DoSubLicenseLoadKeys(
std::string mac_deriv_message; std::string mac_deriv_message;
std::string enc_deriv_message; std::string enc_deriv_message;
GenerateMacContext(group_master_key_id_ + key.track_label(), GenerateMacContext(group_id_ + message.c_str(),
&mac_deriv_message); &mac_deriv_message);
GenerateEncryptContext(group_master_key_id_ + key.track_label(), GenerateEncryptContext(group_id_ + message.c_str(),
&enc_deriv_message); &enc_deriv_message);
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data()); const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());

View File

@@ -5,229 +5,231 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "crypto_session.h" #include "crypto_session.h"
#include "google/protobuf/text_format.h"
#include "key_session.h"
#include "license_protocol.pb.h"
#include "log.h" #include "log.h"
#include "metrics_collections.h"
#include "metrics.pb.h" #include "metrics.pb.h"
#include "metrics_collections.h"
#include "scoped_ptr.h" #include "scoped_ptr.h"
#include "wv_cdm_types.h" #include "wv_cdm_types.h"
namespace { namespace {
const uint8_t kOemCert[] = { const uint8_t kOemCert[] = {
0x30, 0x82, 0x09, 0xf7, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x30, 0x82, 0x09, 0xf7, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0xe8, 0x30, 0x82, 0x09, 0xe4, 0x02, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0xe8, 0x30, 0x82, 0x09, 0xe4, 0x02,
0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0x01, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09,
0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02, 0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02,
0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9, 0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9,
0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06, 0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f,
0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08,
0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d,
0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08,
0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44, 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x44,
0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65,
0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e,
0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x33, 0x31, 0x33, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x30, 0x38, 0x30, 0x30, 0x30, 0x5a, 0x17, 0x0d, 0x31, 0x39, 0x31, 0x32, 0x30, 0x38, 0x30,
0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d,
0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 0x01,
0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0xa2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8f, 0x00, 0x30, 0x82, 0x01,
0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe,
0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49, 0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49,
0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c, 0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c,
0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c, 0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c,
0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e, 0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e,
0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a, 0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a,
0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87, 0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87,
0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e, 0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e,
0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4, 0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4,
0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10, 0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10,
0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04, 0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04,
0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97, 0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97,
0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b, 0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b,
0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6, 0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6,
0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01, 0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01,
0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40, 0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40,
0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87, 0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87,
0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f, 0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f,
0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36, 0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36,
0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0, 0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0,
0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4, 0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4,
0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15, 0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15,
0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5, 0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5,
0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf, 0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf,
0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3, 0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3,
0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b, 0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b,
0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e, 0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e,
0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d, 0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d,
0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87, 0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87,
0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56, 0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56,
0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd, 0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd,
0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2, 0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2,
0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3,
0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01,
0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30,
0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b,
0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60,
0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba, 0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba,
0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3, 0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3,
0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54, 0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54,
0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20, 0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20,
0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2, 0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2,
0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6, 0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6,
0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a, 0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a,
0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38, 0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38,
0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14, 0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14,
0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f, 0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f,
0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98, 0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98,
0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19, 0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19,
0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15, 0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15,
0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11, 0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11,
0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b, 0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b,
0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67, 0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67,
0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e, 0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e,
0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51, 0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51,
0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61, 0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61,
0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7, 0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7,
0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30, 0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30,
0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02,
0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f, 0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f,
0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31,
0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53,
0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57,
0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b,
0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04,
0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30,
0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65,
0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04,
0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74,
0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30,
0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d,
0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31,
0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30,
0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x27, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x20, 0x4f, 0x45, 0x4d, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20,
0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30,
0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30,
0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2,
0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5, 0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5,
0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a, 0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a,
0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e, 0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e,
0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f, 0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f,
0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93, 0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93,
0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9, 0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9,
0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8, 0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8,
0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef, 0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef,
0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57, 0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57,
0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e, 0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e,
0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd, 0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd,
0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc, 0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc,
0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f, 0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f,
0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e, 0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e,
0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc, 0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc,
0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c, 0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c,
0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28, 0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28,
0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70, 0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70,
0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13, 0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13,
0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff, 0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff,
0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7, 0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7,
0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01,
0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04,
0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06,
0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02,
0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14,
0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27, 0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27,
0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06, 0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06,
0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14,
0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13, 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13,
0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4,
0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55,
0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74,
0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30,
0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c,
0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30,
0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65,
0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d,
0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09,
0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06,
0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04,
0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01,
0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87, 0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87,
0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7, 0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7,
0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a, 0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a,
0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d, 0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d,
0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44, 0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44,
0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57, 0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57,
0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc, 0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc,
0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1, 0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1,
0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f, 0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f,
0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a, 0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a,
0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85, 0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85,
0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56, 0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56,
0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15, 0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15,
0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76, 0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76,
0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89, 0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89,
0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3, 0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3,
0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b, 0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b,
0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b, 0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b,
0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3, 0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3,
0xf8, 0x92, 0x36, 0xe3, 0xe3, 0x2f, 0xe8, 0xf1, 0x72, 0xec, 0x0d, 0x50, 0xf8, 0x92, 0x36, 0xe3, 0xe3, 0x2f, 0xe8, 0xf1, 0x72, 0xec, 0x0d, 0x50,
0xd4, 0x86, 0xc5, 0x62, 0x83, 0xf1, 0x2a, 0x4c, 0xd1, 0xbf, 0x76, 0x62, 0xd4, 0x86, 0xc5, 0x62, 0x83, 0xf1, 0x2a, 0x4c, 0xd1, 0xbf, 0x76, 0x62,
0xd4, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85, 0xd4, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85,
0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3, 0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3,
0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58, 0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58,
0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99, 0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99,
0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4, 0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4,
0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98, 0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98,
0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29, 0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29,
0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40, 0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40,
0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77, 0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77,
0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8, 0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8,
0x8e, 0xc8, 0x2d, 0x18, 0x2f, 0x52, 0x2a, 0xde, 0xac, 0x56, 0x8d, 0x8c, 0x8e, 0xc8, 0x2d, 0x18, 0x2f, 0x52, 0x2a, 0xde, 0xac, 0x56, 0x8d, 0x8c,
0x67, 0x14, 0xf6, 0xb9, 0xf1, 0x65, 0xd3, 0x22, 0x43, 0xa3, 0x98, 0x42, 0x67, 0x14, 0xf6, 0xb9, 0xf1, 0x65, 0xd3, 0x22, 0x43, 0xa3, 0x98, 0x42,
0x20, 0x43, 0x4c, 0xdf, 0xf2, 0xeb, 0x31, 0x8c, 0x0e, 0x53, 0x5b, 0x99, 0x20, 0x43, 0x4c, 0xdf, 0xf2, 0xeb, 0x31, 0x8c, 0x0e, 0x53, 0x5b, 0x99,
0x82, 0xc3, 0x48, 0x04, 0x53, 0xad, 0x96, 0xb6, 0x9f, 0x52, 0xcc, 0x01, 0x82, 0xc3, 0x48, 0x04, 0x53, 0xad, 0x96, 0xb6, 0x9f, 0x52, 0xcc, 0x01,
0xc8, 0xb3, 0x87, 0x6b, 0x9e, 0xea, 0xa9, 0xeb, 0xda, 0xac, 0xf9, 0x6f, 0xc8, 0xb3, 0x87, 0x6b, 0x9e, 0xea, 0xa9, 0xeb, 0xda, 0xac, 0xf9, 0x6f,
0xde, 0xa1, 0x44, 0x32, 0x52, 0x49, 0x47, 0xff, 0x65, 0x79, 0x1e, 0xc5, 0xde, 0xa1, 0x44, 0x32, 0x52, 0x49, 0x47, 0xff, 0x65, 0x79, 0x1e, 0xc5,
0x73, 0x17, 0xb3, 0x36, 0xfc, 0x45, 0xca, 0x90, 0x37, 0x59, 0x1e, 0x16, 0x73, 0x17, 0xb3, 0x36, 0xfc, 0x45, 0xca, 0x90, 0x37, 0x59, 0x1e, 0x16,
0xab, 0x09, 0x69, 0xcf, 0xda, 0x56, 0x51, 0xfd, 0xeb, 0xcf, 0xcb, 0x8f, 0xab, 0x09, 0x69, 0xcf, 0xda, 0x56, 0x51, 0xfd, 0xeb, 0xcf, 0xcb, 0x8f,
0xb1, 0xc3, 0x45, 0x2b, 0x7c, 0x0a, 0xa5, 0x9c, 0x0d, 0x2c, 0xad, 0x1c, 0xb1, 0xc3, 0x45, 0x2b, 0x7c, 0x0a, 0xa5, 0x9c, 0x0d, 0x2c, 0xad, 0x1c,
0xd3, 0x33, 0xdd, 0xfe, 0x93, 0x69, 0xa2, 0x4b, 0x4b, 0xcf, 0x1d, 0x20, 0xd3, 0x33, 0xdd, 0xfe, 0x93, 0x69, 0xa2, 0x4b, 0x4b, 0xcf, 0x1d, 0x20,
0x98, 0x4a, 0x4f, 0x5b, 0xe9, 0x24, 0xca, 0xfa, 0x18, 0x11, 0x81, 0x8b, 0x98, 0x4a, 0x4f, 0x5b, 0xe9, 0x24, 0xca, 0xfa, 0x18, 0x11, 0x81, 0x8b,
0x7a, 0xb4, 0x5a, 0xc8, 0xdf, 0x6f, 0x5f, 0x21, 0x07, 0x31, 0x00 0x7a, 0xb4, 0x5a, 0xc8, 0xdf, 0x6f, 0x5f, 0x21, 0x07, 0x31, 0x00};
};
const uint32_t kOemCertSystemId = 7346; const uint32_t kOemCertSystemId = 7346;
@@ -235,17 +237,29 @@ const uint32_t kOemCertSystemId = 7346;
namespace wvcdm { namespace wvcdm {
class CryptoSessionForTest: public CryptoSession { class CryptoSessionForTest : public CryptoSession, public testing::Test {
public: public:
using CryptoSession::ExtractSystemIdFromOemCert; using CryptoSession::ExtractSystemIdFromOemCert;
CryptoSessionForTest() : CryptoSession(metrics_.GetCryptoMetrics()) {}
void SetUp() {
// crypto_metrics_.crypto_session_security_level_.Record(kSecurityLevelL3);
}
KeySession* key_session() { return key_session_.get(); }
private:
static metrics::SessionMetrics metrics_;
}; };
metrics::SessionMetrics CryptoSessionForTest::metrics_;
TEST(CryptoSessionTest, CanExtractSystemIdFromOemCertificate) { TEST(CryptoSessionTest, CanExtractSystemIdFromOemCertificate) {
std::string oem_cert(reinterpret_cast<const char*>(kOemCert), std::string oem_cert(reinterpret_cast<const char*>(kOemCert),
sizeof(kOemCert)); sizeof(kOemCert));
uint32_t system_id; uint32_t system_id;
ASSERT_TRUE(CryptoSessionForTest::ExtractSystemIdFromOemCert(oem_cert, ASSERT_TRUE(
&system_id)); CryptoSessionForTest::ExtractSystemIdFromOemCert(oem_cert, &system_id));
ASSERT_EQ(kOemCertSystemId, system_id); ASSERT_EQ(kOemCertSystemId, system_id);
} }

View File

@@ -441,7 +441,7 @@ TEST_F(InitializationDataTest, ExtractSubLicense) {
InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kSubLicensePsshBox); InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kSubLicensePsshBox);
ASSERT_FALSE(init_data.IsEmpty()); ASSERT_FALSE(init_data.IsEmpty());
std::vector<video_widevine::SubLicense> keys = std::vector<video_widevine::SubLicense> keys =
init_data.ExtractEmbeddedKeys(); init_data.ExtractSublicenseKeys();
ASSERT_EQ(keys.size(), 2UL); ASSERT_EQ(keys.size(), 2UL);
EXPECT_EQ(keys[0].sub_session_key_id(), "sub_session_key_id_0"); EXPECT_EQ(keys[0].sub_session_key_id(), "sub_session_key_id_0");
EXPECT_EQ(keys[1].sub_session_key_id(), "sub_session_key_id_1"); EXPECT_EQ(keys[1].sub_session_key_id(), "sub_session_key_id_1");
@@ -453,7 +453,7 @@ TEST_F(InitializationDataTest, ExtractEmptySubLicense) {
InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kWidevinePssh); InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kWidevinePssh);
ASSERT_FALSE(init_data.IsEmpty()); ASSERT_FALSE(init_data.IsEmpty());
std::vector<video_widevine::SubLicense> keys = std::vector<video_widevine::SubLicense> keys =
init_data.ExtractEmbeddedKeys(); init_data.ExtractSublicenseKeys();
ASSERT_TRUE(keys.empty()); ASSERT_TRUE(keys.empty());
} }
@@ -644,8 +644,8 @@ TEST_P(HlsConstructionTest, InitData) {
for (size_t i = 0; i < param.key_ids_.size(); ++i) { for (size_t i = 0; i < param.key_ids_.size(); ++i) {
bool key_id_found = false; bool key_id_found = false;
if (param.key_ids_[i].size() != 32) continue; if (param.key_ids_[i].size() != 32) continue;
for (int j = 0; j < cenc_header.key_id_size(); ++j) { for (int j = 0; j < cenc_header.key_ids_size(); ++j) {
if (param.key_ids_[i] == b2a_hex(cenc_header.key_id(j))) { if (param.key_ids_[i] == b2a_hex(cenc_header.key_ids(j))) {
key_id_found = true; key_id_found = true;
break; break;
} }
@@ -752,7 +752,7 @@ TEST_P(HlsParseTest, Parse) {
} else if (param.key_.compare(kJsonContentId) == 0) { } else if (param.key_.compare(kJsonContentId) == 0) {
EXPECT_EQ(param.value_, cenc_header.content_id()); EXPECT_EQ(param.value_, cenc_header.content_id());
} else if (param.key_.compare(kJsonKeyIds) == 0) { } else if (param.key_.compare(kJsonKeyIds) == 0) {
EXPECT_EQ(param.value_, b2a_hex(cenc_header.key_id(0))); EXPECT_EQ(param.value_, b2a_hex(cenc_header.key_ids(0)));
} }
EXPECT_EQ(kHlsIvHexValue, b2a_hex(init_data.hls_iv())); EXPECT_EQ(kHlsIvHexValue, b2a_hex(init_data.hls_iv()));

View File

@@ -131,6 +131,7 @@ class CryptoMetrics {
ValueMetric<bool> oemcrypto_is_anti_rollback_hw_present_; ValueMetric<bool> oemcrypto_is_anti_rollback_hw_present_;
ValueMetric<bool> oemcrypto_is_keybox_valid_; ValueMetric<bool> oemcrypto_is_keybox_valid_;
EventMetric<OEMCryptoResult> oemcrypto_load_device_rsa_key_; EventMetric<OEMCryptoResult> oemcrypto_load_device_rsa_key_;
EventMetric<OEMCryptoResult> oemcrypto_load_entitled_keys_;
EventMetric<OEMCryptoResult> oemcrypto_load_keys_; EventMetric<OEMCryptoResult> oemcrypto_load_keys_;
ValueMetric<OEMCrypto_HDCP_Capability> oemcrypto_max_hdcp_capability_; ValueMetric<OEMCrypto_HDCP_Capability> oemcrypto_max_hdcp_capability_;
ValueMetric<size_t> oemcrypto_max_number_of_sessions_; ValueMetric<size_t> oemcrypto_max_number_of_sessions_;

View File

@@ -196,6 +196,9 @@ CryptoMetrics::CryptoMetrics() :
oemcrypto_load_device_rsa_key_( oemcrypto_load_device_rsa_key_(
"/drm/widevine/oemcrypto/load_device_rsa_key/time", "/drm/widevine/oemcrypto/load_device_rsa_key/time",
"oemcrypto_error"), "oemcrypto_error"),
oemcrypto_load_entitled_keys_(
"/drm/widevine/oemcrypto/load_entitled_keys/time",
"oemcrypto_error"),
oemcrypto_load_keys_( oemcrypto_load_keys_(
"/drm/widevine/oemcrypto/load_keys/time", "/drm/widevine/oemcrypto/load_keys/time",
"oemcrypto_error"), "oemcrypto_error"),
@@ -277,6 +280,7 @@ void CryptoMetrics::Serialize(MetricsGroup* metrics) {
oemcrypto_is_anti_rollback_hw_present_.Serialize(&serializer); oemcrypto_is_anti_rollback_hw_present_.Serialize(&serializer);
oemcrypto_is_keybox_valid_.Serialize(&serializer); oemcrypto_is_keybox_valid_.Serialize(&serializer);
oemcrypto_load_device_rsa_key_.Serialize(&serializer); oemcrypto_load_device_rsa_key_.Serialize(&serializer);
oemcrypto_load_entitled_keys_.Serialize(&serializer);
oemcrypto_load_keys_.Serialize(&serializer); oemcrypto_load_keys_.Serialize(&serializer);
oemcrypto_max_hdcp_capability_.Serialize(&serializer); oemcrypto_max_hdcp_capability_.Serialize(&serializer);
oemcrypto_max_number_of_sessions_.Serialize(&serializer); oemcrypto_max_number_of_sessions_.Serialize(&serializer);