From 9ae7489938e99e4926e06799f32c4d1150d6f03e Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Thu, 25 Jan 2018 15:31:49 -0800 Subject: [PATCH] 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 --- libwvdrmengine/cdm/Android.mk | 1 + .../cdm/core/include/content_key_session.h | 30 +- libwvdrmengine/cdm/core/include/crypto_key.h | 5 + .../cdm/core/include/crypto_session.h | 55 ++- .../core/include/entitlement_key_session.h | 34 ++ .../cdm/core/include/initialization_data.h | 6 +- libwvdrmengine/cdm/core/include/key_session.h | 4 +- libwvdrmengine/cdm/core/include/license.h | 40 +- .../cdm/core/include/sublicense_key_session.h | 8 +- .../cdm/core/include/wv_cdm_types.h | 5 + libwvdrmengine/cdm/core/src/cdm_session.cpp | 4 +- .../cdm/core/src/content_key_session.cpp | 109 +++-- .../cdm/core/src/crypto_session.cpp | 23 +- .../cdm/core/src/entitlement_key_session.cpp | 54 +++ .../cdm/core/src/initialization_data.cpp | 33 +- libwvdrmengine/cdm/core/src/license.cpp | 184 ++++++- .../cdm/core/src/license_protocol.proto | 57 ++- .../cdm/core/src/sublicense_key_session.cpp | 8 +- .../cdm/core/test/crypto_session_unittest.cpp | 450 +++++++++--------- .../test/initialization_data_unittest.cpp | 10 +- .../cdm/metrics/include/metrics_collections.h | 1 + .../cdm/metrics/src/metrics_collections.cpp | 4 + 22 files changed, 749 insertions(+), 376 deletions(-) create mode 100644 libwvdrmengine/cdm/core/include/entitlement_key_session.h create mode 100644 libwvdrmengine/cdm/core/src/entitlement_key_session.cpp diff --git a/libwvdrmengine/cdm/Android.mk b/libwvdrmengine/cdm/Android.mk index d9eaed57..9ebd5972 100644 --- a/libwvdrmengine/cdm/Android.mk +++ b/libwvdrmengine/cdm/Android.mk @@ -35,6 +35,7 @@ LOCAL_SRC_FILES := \ $(CORE_SRC_DIR)/content_key_session.cpp \ $(CORE_SRC_DIR)/crypto_session.cpp \ $(CORE_SRC_DIR)/device_files.cpp \ + $(CORE_SRC_DIR)/entitlement_key_session.cpp \ $(CORE_SRC_DIR)/initialization_data.cpp \ $(CORE_SRC_DIR)/license.cpp \ $(CORE_SRC_DIR)/license_key_status.cpp \ diff --git a/libwvdrmengine/cdm/core/include/content_key_session.h b/libwvdrmengine/cdm/core/include/content_key_session.h index c9368b9a..9d51f2c4 100644 --- a/libwvdrmengine/cdm/core/include/content_key_session.h +++ b/libwvdrmengine/cdm/core/include/content_key_session.h @@ -6,23 +6,23 @@ namespace wvcdm { -class DefaultKeySession : public KeySession { +class ContentKeySession : public KeySession { public: - DefaultKeySession(CryptoSessionId oec_session_id, + ContentKeySession(CryptoSessionId oec_session_id, metrics::CryptoMetrics* metrics) : KeySession(metrics), oec_session_id_(oec_session_id) {} - virtual ~DefaultKeySession() {} + virtual ~ContentKeySession() {} KeySessionType Type() { return kDefault; } - // Generate Derived Keys for DefaultKeySession + // Generate Derived Keys for ContentKeySession 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, const std::string& session_key); - // Load Keys for DefaultKeySession + // Load Keys for ContentKeySession OEMCryptoResult LoadKeys(const std::string& message, const std::string& signature, const std::string& mac_key_iv, @@ -32,17 +32,29 @@ class DefaultKeySession : public KeySession { CdmCipherMode* cipher_mode, const std::string& srm_requirement); - // Select Key for DefaultKeySession + OEMCryptoResult LoadEntitledContentKeys(const std::vector& keys) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + // Select Key for ContentKeySession OEMCryptoResult SelectKey(const std::string& key_id, CdmCipherMode cipher_mode); - // Decrypt for DefaultKeySession + // Decrypt for ContentKeySession OEMCryptoResult Decrypt(const CdmDecryptionParameters& params, OEMCrypto_DestBufferDesc& buffer_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& keys, + const std::string& provider_session_token, CdmCipherMode* cipher_mode, + const std::string& srm_requirement, OEMCrypto_LicenseType license_type); CryptoSessionId oec_session_id_; + + private: KeyId cached_key_id_; }; diff --git a/libwvdrmengine/cdm/core/include/crypto_key.h b/libwvdrmengine/cdm/core/include/crypto_key.h index 0da57d56..8f08e751 100644 --- a/libwvdrmengine/cdm/core/include/crypto_key.h +++ b/libwvdrmengine/cdm/core/include/crypto_key.h @@ -19,6 +19,7 @@ class CryptoKey { 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() 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_; } CdmCipherMode cipher_mode() const { return cipher_mode_; } 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) { 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; } @@ -52,6 +56,7 @@ class CryptoKey { std::string sub_session_key_id_; std::string track_label_; std::string sub_session_key_; + std::string entitlement_key_id_; CdmCipherMode cipher_mode_; }; diff --git a/libwvdrmengine/cdm/core/include/crypto_session.h b/libwvdrmengine/cdm/core/include/crypto_session.h index cabd78b5..c5f45848 100644 --- a/libwvdrmengine/cdm/core/include/crypto_session.h +++ b/libwvdrmengine/cdm/core/include/crypto_session.h @@ -12,7 +12,6 @@ #include "lock.h" #include "metrics_collections.h" #include "oemcrypto_adapter.h" -#include "OEMCryptoCENC.h" #include "scoped_ptr.h" #include "timer_metric.h" #include "wv_cdm_types.h" @@ -77,13 +76,15 @@ class CryptoSession { bool is_provisioning, std::string* signature); virtual bool PrepareRenewalRequest(const std::string& message, std::string* signature); - virtual CdmResponseType LoadKeys(const std::string& message, - const std::string& signature, - const std::string& mac_key_iv, - const std::string& mac_key, - const std::vector& key_array, - const std::string& provider_session_token, - const std::string& srm_requirement); + virtual CdmResponseType LoadKeys( + const std::string& message, const std::string& signature, + const std::string& mac_key_iv, const std::string& mac_key, + const std::vector& key_array, + const std::string& provider_session_token, + const std::string& srm_requirement, + CdmLicenseKeyType key_type); + virtual CdmResponseType LoadEntitledContentKeys( + const std::vector& key_array); virtual bool LoadCertificatePrivateKey(std::string& wrapped_key); virtual bool RefreshKeys(const std::string& message, const std::string& signature, int num_keys, @@ -169,19 +170,17 @@ class CryptoSession { virtual CdmResponseType LoadUsageEntry(uint32_t entry_number, const CdmUsageEntry& usage_entry); virtual CdmResponseType UpdateUsageEntry( - CdmUsageTableHeader* usage_table_header, - CdmUsageEntry* usage_entry); + CdmUsageTableHeader* usage_table_header, CdmUsageEntry* usage_entry); virtual CdmResponseType ShrinkUsageTableHeader( uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header); virtual CdmResponseType MoveUsageEntry(uint32_t new_entry_number); - virtual bool CreateOldUsageEntry( - uint64_t time_since_license_received, - uint64_t time_since_first_decrypt, - uint64_t time_since_last_decrypt, - UsageDurationStatus status, - const std::string& server_mac_key, - const std::string& client_mac_key, - const std::string& provider_session_token); + virtual bool CreateOldUsageEntry(uint64_t time_since_license_received, + uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, + UsageDurationStatus status, + const std::string& server_mac_key, + const std::string& client_mac_key, + const std::string& provider_session_token); virtual CdmResponseType CopyOldUsageEntry( const std::string& provider_session_token); virtual metrics::CryptoMetrics* GetCryptoMetrics() { return metrics_; } @@ -209,15 +208,19 @@ class CryptoSession { bool SetDestinationBufferType(); - bool RewrapDeviceRSAKey( - const std::string& message, const std::string& signature, - const std::string& nonce, const std::string& enc_rsa_key, - const std::string& rsa_key_iv, std::string* wrapped_rsa_key); + bool RewrapDeviceRSAKey(const std::string& message, + const std::string& signature, + const std::string& nonce, + const std::string& enc_rsa_key, + const std::string& rsa_key_iv, + std::string* wrapped_rsa_key); - bool RewrapDeviceRSAKey30( - const std::string& message, const std::string& nonce, - const std::string& private_key, const std::string& iv, - const std::string& wrapping_key, std::string* wrapped_private_key); + bool RewrapDeviceRSAKey30(const std::string& message, + const std::string& nonce, + const std::string& private_key, + const std::string& iv, + const std::string& wrapping_key, + std::string* wrapped_private_key); CdmResponseType SelectKey(const std::string& key_id, CdmCipherMode cipher_mode); diff --git a/libwvdrmengine/cdm/core/include/entitlement_key_session.h b/libwvdrmengine/cdm/core/include/entitlement_key_session.h new file mode 100644 index 00000000..7cdad259 --- /dev/null +++ b/libwvdrmengine/cdm/core/include/entitlement_key_session.h @@ -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& keys, + const std::string& provider_session_token, + CdmCipherMode* cipher_mode, + const std::string& srm_requirement); + OEMCryptoResult LoadEntitledContentKeys(const std::vector& keys); + + private: + std::vector keys_; +}; + +} // namespace wvcdm + +#endif // WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_ \ No newline at end of file diff --git a/libwvdrmengine/cdm/core/include/initialization_data.h b/libwvdrmengine/cdm/core/include/initialization_data.h index 53e8402f..ce26ea14 100644 --- a/libwvdrmengine/cdm/core/include/initialization_data.h +++ b/libwvdrmengine/cdm/core/include/initialization_data.h @@ -28,8 +28,10 @@ class InitializationData { const CdmInitData& data() const { return data_; } std::vector hls_iv() const { return hls_iv_; } CdmHlsMethod hls_method() const { return hls_method_; } - std::vector ExtractEmbeddedKeys() const; - const std::string ExtractGroupMasterKeyId() const; + // TODO(jfore): Perhaps this should be a generic structure with the ids for + // any type of licensing? + std::vector ExtractSublicenseKeys() const; + std::vector ExtractWrappedKeys() const; private: // Parse a blob of multiple concatenated PSSH atoms to extract the first diff --git a/libwvdrmengine/cdm/core/include/key_session.h b/libwvdrmengine/cdm/core/include/key_session.h index 9de19537..d8c3c737 100644 --- a/libwvdrmengine/cdm/core/include/key_session.h +++ b/libwvdrmengine/cdm/core/include/key_session.h @@ -12,7 +12,7 @@ class KeySession { KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {} public: - typedef enum { kDefault, kSubLicense } KeySessionType; + typedef enum { kDefault, kSubLicense, kEntitlement } KeySessionType; virtual ~KeySession() {} virtual KeySessionType Type() = 0; virtual bool GenerateDerivedKeys(const std::string& message) = 0; @@ -26,6 +26,8 @@ class KeySession { const std::string& provider_session_token, CdmCipherMode* cipher_mode, const std::string& srm_requirement) = 0; + virtual OEMCryptoResult LoadEntitledContentKeys( + const std::vector& keys) = 0; virtual OEMCryptoResult SelectKey(const std::string& key_id, CdmCipherMode cipher_mode) = 0; virtual OEMCryptoResult Decrypt( diff --git a/libwvdrmengine/cdm/core/include/license.h b/libwvdrmengine/cdm/core/include/license.h index dc02859d..ad86c0f7 100644 --- a/libwvdrmengine/cdm/core/include/license.h +++ b/libwvdrmengine/cdm/core/include/license.h @@ -29,11 +29,11 @@ class CdmLicense { CdmLicense(const CdmSessionId& session_id); virtual ~CdmLicense(); - virtual bool Init( - const std::string& client_token, CdmClientTokenType client_token_type, - const std::string& device_id, bool use_privacy_mode, - const std::string& signed_service_certificate, CryptoSession* session, - PolicyEngine* policy_engine); + virtual bool Init(const std::string& client_token, + CdmClientTokenType client_token_type, + const std::string& device_id, bool use_privacy_mode, + const std::string& signed_service_certificate, + CryptoSession* session, PolicyEngine* policy_engine); virtual CdmResponseType PrepareKeyRequest( const InitializationData& init_data, CdmLicenseType license_type, @@ -64,16 +64,13 @@ class CdmLicense { return provider_session_token_; } - virtual bool is_offline() { - return is_offline_; - } + virtual bool is_offline() { return is_offline_; } static bool ExtractProviderSessionToken( const CdmKeyResponse& license_response, std::string* provider_session_token); private: - CdmResponseType HandleKeyErrorResponse( const video_widevine::SignedMessage& signed_message); @@ -86,9 +83,24 @@ class CdmLicense { const std::string& request_id, 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& 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& key_array, + const video_widevine::License& license); + template - bool SetTypeAndId(CdmLicenseType license_type, - const std::string& request_id, T* content_id); + bool SetTypeAndId(CdmLicenseType license_type, const std::string& request_id, + T* content_id); CryptoSession* crypto_session_; PolicyEngine* policy_engine_; @@ -121,6 +133,12 @@ class CdmLicense { // sub session keys we may have received in a license response. These keys // may be used to support key rotation. std::vector 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 wrapped_keys_; #if defined(UNIT_TEST) friend class CdmLicenseTest; #endif diff --git a/libwvdrmengine/cdm/core/include/sublicense_key_session.h b/libwvdrmengine/cdm/core/include/sublicense_key_session.h index ea6bb380..1367882f 100644 --- a/libwvdrmengine/cdm/core/include/sublicense_key_session.h +++ b/libwvdrmengine/cdm/core/include/sublicense_key_session.h @@ -18,7 +18,7 @@ class SubLicenseKeySession : public KeySession { metrics::CryptoMetrics* metrics, const std::string& wrapped_private_device_key, SecurityLevel requested_security_level, - const std::string& group_master_key_id); + const std::string& group_id); virtual ~SubLicenseKeySession(); @@ -43,6 +43,10 @@ class SubLicenseKeySession : public KeySession { CdmCipherMode* cipher_mode, const std::string& srm_requirement); + OEMCryptoResult LoadEntitledContentKeys(const std::vector& keys) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // Each oemcrypto session contains a single key. Find the right sub session // and save it's id as the selected oemcrypto session. OEMCryptoResult SelectKey(const std::string& key_id, @@ -83,7 +87,7 @@ class SubLicenseKeySession : public KeySession { std::vector keys_; SubLicenseSessionMap& sub_license_oec_sessions_; SecurityLevel requested_security_level_; - KeyId group_master_key_id_; + KeyId group_id_; }; } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index a313b279..1ebce62c 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -345,6 +345,11 @@ enum CdmLicenseType { kLicenseTypeSubSession }; +enum CdmLicenseKeyType { + kLicenseKeyTypeContent, + kLicenseKeyTypeEntitlement +}; + enum SecurityLevel { kLevelDefault, kLevel3 diff --git a/libwvdrmengine/cdm/core/src/cdm_session.cpp b/libwvdrmengine/cdm/core/src/cdm_session.cpp index 15b25bee..7a8813e1 100644 --- a/libwvdrmengine/cdm/core/src/cdm_session.cpp +++ b/libwvdrmengine/cdm/core/src/cdm_session.cpp @@ -382,11 +382,11 @@ CdmResponseType CdmSession::GenerateKeyRequest( } std::vector embedded_key_data = - init_data.ExtractEmbeddedKeys(); + init_data.ExtractSublicenseKeys(); for (size_t i = 0; i < embedded_key_data.size(); ++i) { CdmResponseType sts = crypto_session_->AddSubSession( embedded_key_data[i].sub_session_key_id(), - init_data.ExtractGroupMasterKeyId()); + embedded_key_data[i].group_id()); if (NO_ERROR != sts) { LOGE("CdmSession::GenerateKeyRequest: Unable to generate sub session"); return sts; diff --git a/libwvdrmengine/cdm/core/src/content_key_session.cpp b/libwvdrmengine/cdm/core/src/content_key_session.cpp index 42591d1e..5075fd9c 100644 --- a/libwvdrmengine/cdm/core/src/content_key_session.cpp +++ b/libwvdrmengine/cdm/core/src/content_key_session.cpp @@ -6,8 +6,8 @@ namespace wvcdm { -// Generate Derived Keys for DefaultKeySession -bool DefaultKeySession::GenerateDerivedKeys(const std::string& message) { +// Generate Derived Keys for ContentKeySession +bool ContentKeySession::GenerateDerivedKeys(const std::string& message) { std::string mac_deriv_message; std::string enc_deriv_message; GenerateMacContext(message, &mac_deriv_message); @@ -30,8 +30,8 @@ bool DefaultKeySession::GenerateDerivedKeys(const std::string& message) { return true; } -// Generate Derived Keys (from session key) for DefaultKeySession -bool DefaultKeySession::GenerateDerivedKeys(const std::string& message, +// Generate Derived Keys (from session key) for ContentKeySession +bool ContentKeySession::GenerateDerivedKeys(const std::string& message, const std::string& session_key) { std::string mac_deriv_message; std::string enc_deriv_message; @@ -58,13 +58,65 @@ bool DefaultKeySession::GenerateDerivedKeys(const std::string& message, return true; } -// Load Keys for DefaultKeySession -OEMCryptoResult DefaultKeySession::LoadKeys( +// Load Keys for ContentKeySession +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& keys, const std::string& provider_session_token, CdmCipherMode* cipher_mode, 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(cached_key_id_.data()); + + OEMCryptoResult sts; + M_TIME(sts = OEMCrypto_SelectKey( + oec_session_id_, key_id_string, cached_key_id_.size(), + static_cast(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& 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(message.data()); const uint8_t* enc_mac_key = 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_iv = msg + GetOffset(message, mac_key_iv); } else { - LOGV("DefaultKeySession::LoadKeys: enc_mac_key not set"); + LOGV("ContentKeySession::LoadKeys: enc_mac_key not set"); } std::vector load_keys(keys.size()); for (size_t i = 0; i < keys.size(); ++i) { @@ -114,50 +166,9 @@ OEMCryptoResult DefaultKeySession::LoadKeys( oec_session_id_, msg, message.size(), reinterpret_cast(signature.data()), signature.size(), 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); 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(cached_key_id_.data()); - - OEMCryptoResult sts; - M_TIME(sts = OEMCrypto_SelectKey( - oec_session_id_, key_id_string, cached_key_id_.size(), - static_cast(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 \ No newline at end of file diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 41044407..f8ec079c 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -13,6 +13,7 @@ #include "content_key_session.h" #include "crypto_key.h" +#include "entitlement_key_session.h" #include "log.h" #include "openssl/asn1.h" #include "openssl/sha.h" @@ -119,6 +120,12 @@ void GenerateEncryptContext(const std::string& input_context, 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) : metrics_(metrics), system_id_(-1), @@ -692,7 +699,7 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) { } // 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; } @@ -779,10 +786,15 @@ CdmResponseType CryptoSession::LoadKeys( const std::string& mac_key_iv, const std::string& mac_key, const std::vector& keys, const std::string& provider_session_token, - const std::string& srm_requirement) { + const std::string& srm_requirement, CdmLicenseKeyType key_type) { LOGV("CryptoSession::LoadKeys: 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_); OEMCryptoResult sts = key_session_->LoadKeys( message, signature, mac_key_iv, mac_key, keys, provider_session_token, @@ -815,6 +827,13 @@ CdmResponseType CryptoSession::LoadKeys( return result; } +CdmResponseType CryptoSession::LoadEntitledContentKeys( + const std::vector& 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) { LOGV("CryptoSession::LoadCertificatePrivateKey: Lock"); AutoLock auto_lock(crypto_lock_); diff --git a/libwvdrmengine/cdm/core/src/entitlement_key_session.cpp b/libwvdrmengine/cdm/core/src/entitlement_key_session.cpp new file mode 100644 index 00000000..1db42ef0 --- /dev/null +++ b/libwvdrmengine/cdm/core/src/entitlement_key_session.cpp @@ -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& 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& keys) { + // The array |keys| contains new content keys, plus entitlement key ids for + // those content keys. + std::vector entitlements; + entitlements.resize(keys.size()); + + for (size_t i = 0; i < keys.size(); ++i) { + entitlements[i].entitlement_key_id = + reinterpret_cast(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(keys[i].key_id().data()); + entitlements[i].content_key_id_length = keys[i].key_id().size(); + + entitlements[i].content_key_data_iv = + reinterpret_cast(keys[i].key_data_iv().data()); + + entitlements[i].content_key_data = + reinterpret_cast(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 \ No newline at end of file diff --git a/libwvdrmengine/cdm/core/src/initialization_data.cpp b/libwvdrmengine/cdm/core/src/initialization_data.cpp index a4748a59..cfa94722 100644 --- a/libwvdrmengine/cdm/core/src/initialization_data.cpp +++ b/libwvdrmengine/cdm/core/src/initialization_data.cpp @@ -67,7 +67,7 @@ InitializationData::InitializationData(const std::string& type, // Parse the pssh data and return the embedded key data if it exists. std::vector -InitializationData::ExtractEmbeddedKeys() const { +InitializationData::ExtractSublicenseKeys() const { std::vector keys; WidevinePsshData cenc_header; if (!is_cenc_ || !cenc_header.ParseFromString(data_) || @@ -81,6 +81,20 @@ InitializationData::ExtractEmbeddedKeys() const { return keys; } +std::vector InitializationData::ExtractWrappedKeys() + const { + std::vector 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 // Widevine PSSH. bool InitializationData::ExtractWidevinePssh(const CdmInitData& init_data, @@ -483,7 +497,7 @@ bool InitializationData::ConstructWidevineInitData( // have not yet been pushed to production. Set until then. cenc_header.set_algorithm(WidevinePsshData_Algorithm_AESCTR); 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_content_id(content_id); @@ -589,19 +603,4 @@ std::vector InitializationData::ExtractKeyFormatVersions( return versions; } -// Extract the key id of the group master key used to generate sublicense data. -// Returns an empty string if not defined. -const std::string InitializationData::ExtractGroupMasterKeyId() const { - if (!is_cenc_) { - return ""; - } - - WidevinePsshData cenc_header; - if (!cenc_header.ParseFromString(data_)) { - return ""; - } - - return cenc_header.group_master_key_id(); -} - } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/src/license.cpp b/libwvdrmengine/cdm/core/src/license.cpp index 11037939..ea8623b4 100644 --- a/libwvdrmengine/cdm/core/src/license.cpp +++ b/libwvdrmengine/cdm/core/src/license.cpp @@ -72,6 +72,54 @@ static std::vector ExtractSubSessionKeys(const License& license) { return key_array; } +static std::vector ExtractEntitlementKeys(const License& license) { + std::vector 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 ExtractContentKeys(const License& license) { std::vector key_array; @@ -239,6 +287,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest( return PrepareKeyRequest(restored_init_data, license_type, app_parameters, signed_request, server_url); } + wrapped_keys_ = init_data.ExtractWrappedKeys(); if (!init_data.is_supported()) { LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)", init_data.type().c_str()); @@ -306,7 +355,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest( // Prepare the request for any embedded keys that may exist in the // initialization data. std::vector embedded_key_data = - init_data.ExtractEmbeddedKeys(); + init_data.ExtractSublicenseKeys(); for (size_t i = 0; i < embedded_key_data.size(); ++i) { bool exists = false; if (!crypto_session_->GenerateSubSessionNonce( @@ -575,8 +624,15 @@ CdmResponseType CdmLicense::HandleKeyResponse( } } - std::vector key_array = ExtractContentKeys(license); - if (!key_array.size()) { + CdmLicenseKeyType key_type = kLicenseKeyTypeEntitlement; + std::vector 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."); return NO_CONTENT_KEY; } @@ -601,17 +657,15 @@ CdmResponseType CdmLicense::HandleKeyResponse( renew_with_client_id_ = license.policy().always_include_client_id(); } - CdmResponseType resp = crypto_session_->LoadKeys( - signed_response.msg(), signed_response.signature(), mac_key_iv, mac_key, - key_array, provider_session_token_, license.srm_requirement()); - - if (KEY_ADDED == resp) { - loaded_keys_.clear(); - for (std::vector::iterator it = key_array.begin(); - it != key_array.end(); ++it) { - loaded_keys_.insert(it->key_id()); - } - policy_engine_->SetLicense(license); + CdmResponseType resp = NO_CONTENT_KEY; + if (kLicenseKeyTypeEntitlement == key_type) { + resp = HandleEntitlementKeyResponse(signed_response.msg(), + signed_response.signature(), mac_key_iv, + mac_key, key_array, license); + } else if (kLicenseKeyTypeContent == key_type) { + resp = HandleContentKeyResponse(signed_response.msg(), + signed_response.signature(), mac_key_iv, + mac_key, key_array, license); } return resp; } @@ -699,7 +753,7 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse( CdmResponseType CdmLicense::HandleSubLicense( const InitializationData& init_data) { std::vector subkeys = - init_data.ExtractEmbeddedKeys(); + init_data.ExtractSublicenseKeys(); std::set loaded_keys; // Build a license with the rotated keys. License license; @@ -732,7 +786,7 @@ CdmResponseType CdmLicense::HandleSubLicense( //TODO: passing empty cipher_mode and srm_req params - OK? CdmResponseType result = crypto_session_->LoadKeys( sm.msg(), sm.signature(), std::string(), std::string(), keys, - std::string(), std::string()); + std::string(), std::string(), kLicenseKeyTypeContent); if (result != KEY_ADDED) { LOGE("CdmLicense::HandleSubLicense: LoadKeys() call failed, result=%d", result); @@ -1049,6 +1103,104 @@ CdmResponseType CdmLicense::PrepareContentId( 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& 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::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& 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 entitled_key_array; + entitled_key_array.reserve(key_array.size()); + + for (std::vector::iterator wk = + wrapped_keys_.begin(); + wk != wrapped_keys_.end(); wk++) { + for (std::vector::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::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 bool CdmLicense::SetTypeAndId(CdmLicenseType license_type, const std::string& request_id, T* content_id) { diff --git a/libwvdrmengine/cdm/core/src/license_protocol.proto b/libwvdrmengine/cdm/core/src/license_protocol.proto index a0893720..ed5f8a69 100644 --- a/libwvdrmengine/cdm/core/src/license_protocol.proto +++ b/libwvdrmengine/cdm/core/src/license_protocol.proto @@ -102,6 +102,7 @@ message License { KEY_CONTROL = 3; OPERATOR_SESSION = 4; SUB_SESSION = 5; + ENTITLEMENT = 6; } // 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 // holding a single content key. 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 { +// Superceded by protection_scheme. enum Algorithm { UNENCRYPTED = 0; AESCTR = 1; }; - // Replaced with protection_scheme. - optional Algorithm algorithm = 1; - repeated bytes key_id = 2; + + optional Algorithm algorithm = 1 [deprecated = true]; + + // 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. - optional string provider = 3; + optional string provider = 3 [deprecated = true]; // 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; // Track type. Acceptable values are SD, HD and AUDIO. Used to differentiate // content keys used by an asset. // 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. - 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. optional string policy = 6 [deprecated=true]; @@ -750,16 +777,16 @@ message WidevinePsshData { // Optional protected context for group content. The grouped_license is a // serialized SignedMessage. - optional bytes grouped_license = 8; + optional bytes grouped_license = 8 [deprecated = true]; // Protection scheme identifying the encryption algorithm. The protection // 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 - // values. + // values. To be soon deprecated in favor of signaling from content. // 'cenc' (AES-CTR) protection_scheme = 0x63656E63, // 'cbc1' (AES-CBC) protection_scheme = 0x63626331, - // 'cens' (AES-CTR subsample) protection_scheme = 0x63656E73, - // 'cbcs' (AES-CBC subsample) protection_scheme = 0x63626373. + // 'cens' (AES-CTR pattern encryption) protection_scheme = 0x63656E73, + // 'cbcs' (AES-CBC pattern encryption) protection_scheme = 0x63626373. optional uint32 protection_scheme = 9; // 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. repeated SubLicense sub_licenses = 11; - // Key ID used to identify the group master key License Server is supposed - // to use to generate group license. - optional string group_master_key_id = 12; + // IDs of the groups to which the content belongs. A group is a set of + // content IDs. A particular piece of content may belong to multiple groups. + 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. diff --git a/libwvdrmengine/cdm/core/src/sublicense_key_session.cpp b/libwvdrmengine/cdm/core/src/sublicense_key_session.cpp index 29a57534..f67c6eab 100644 --- a/libwvdrmengine/cdm/core/src/sublicense_key_session.cpp +++ b/libwvdrmengine/cdm/core/src/sublicense_key_session.cpp @@ -11,13 +11,13 @@ SubLicenseKeySession::SubLicenseKeySession( metrics::CryptoMetrics* metrics, const std::string& wrapped_private_device_key, SecurityLevel requested_security_level, - const std::string& group_master_key_id) + const std::string& group_id) : KeySession(metrics), state_(kInitializing), wrapped_private_device_key_(wrapped_private_device_key), sub_license_oec_sessions_(sub_license_oec_sessions), requested_security_level_(requested_security_level), - group_master_key_id_(group_master_key_id) {} + group_id_(group_id) {} SubLicenseKeySession::~SubLicenseKeySession() { for (SubLicenseSessionMap::iterator oec_session = @@ -267,9 +267,9 @@ OEMCryptoResult SubLicenseKeySession::DoSubLicenseLoadKeys( std::string mac_deriv_message; std::string enc_deriv_message; - GenerateMacContext(group_master_key_id_ + key.track_label(), + GenerateMacContext(group_id_ + message.c_str(), &mac_deriv_message); - GenerateEncryptContext(group_master_key_id_ + key.track_label(), + GenerateEncryptContext(group_id_ + message.c_str(), &enc_deriv_message); const uint8_t* msg = reinterpret_cast(message.data()); diff --git a/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp b/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp index 59c9a124..662af053 100644 --- a/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/crypto_session_unittest.cpp @@ -5,229 +5,231 @@ #include #include "crypto_session.h" +#include "google/protobuf/text_format.h" +#include "key_session.h" +#include "license_protocol.pb.h" #include "log.h" -#include "metrics_collections.h" #include "metrics.pb.h" +#include "metrics_collections.h" #include "scoped_ptr.h" #include "wv_cdm_types.h" namespace { const uint8_t kOemCert[] = { - 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, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, - 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09, - 0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02, - 0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9, - 0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06, - 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, - 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, - 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, - 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, - 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, - 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, - 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, - 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e, - 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, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e, - 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, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10, - 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d, - 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, - 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, - 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, - 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, - 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 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, - 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe, - 0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49, - 0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c, - 0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c, - 0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e, - 0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a, - 0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87, - 0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e, - 0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4, - 0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10, - 0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04, - 0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97, - 0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b, - 0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6, - 0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01, - 0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40, - 0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87, - 0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f, - 0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36, - 0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0, - 0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4, - 0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15, - 0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5, - 0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf, - 0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3, - 0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b, - 0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e, - 0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d, - 0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87, - 0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56, - 0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd, - 0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2, - 0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, - 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, - 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, - 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, - 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60, - 0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba, - 0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3, - 0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54, - 0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20, - 0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2, - 0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6, - 0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a, - 0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38, - 0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14, - 0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f, - 0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98, - 0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19, - 0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15, - 0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11, - 0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b, - 0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67, - 0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e, - 0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51, - 0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61, - 0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7, - 0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30, - 0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, - 0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f, - 0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, - 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, - 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, - 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, - 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, - 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, - 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, - 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, - 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, - 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, - 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, - 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, - 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, - 0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, - 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, - 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, - 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, - 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, - 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, - 0x2e, 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, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, - 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, - 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, - 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, - 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2, - 0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5, - 0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a, - 0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e, - 0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f, - 0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93, - 0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9, - 0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8, - 0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef, - 0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57, - 0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e, - 0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd, - 0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc, - 0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f, - 0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e, - 0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc, - 0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c, - 0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28, - 0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70, - 0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13, - 0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff, - 0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7, - 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01, - 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, - 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, - 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, - 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, - 0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27, - 0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06, - 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14, - 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13, - 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4, - 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, - 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, - 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, - 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, - 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, - 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, - 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, - 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, - 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, - 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09, - 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06, - 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, - 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, - 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, - 0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87, - 0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7, - 0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a, - 0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d, - 0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44, - 0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57, - 0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc, - 0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1, - 0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f, - 0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a, - 0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85, - 0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56, - 0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15, - 0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76, - 0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89, - 0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3, - 0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b, - 0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b, - 0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3, - 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, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85, - 0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3, - 0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58, - 0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99, - 0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4, - 0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98, - 0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29, - 0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40, - 0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77, - 0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8, - 0x8e, 0xc8, 0x2d, 0x18, 0x2f, 0x52, 0x2a, 0xde, 0xac, 0x56, 0x8d, 0x8c, - 0x67, 0x14, 0xf6, 0xb9, 0xf1, 0x65, 0xd3, 0x22, 0x43, 0xa3, 0x98, 0x42, - 0x20, 0x43, 0x4c, 0xdf, 0xf2, 0xeb, 0x31, 0x8c, 0x0e, 0x53, 0x5b, 0x99, - 0x82, 0xc3, 0x48, 0x04, 0x53, 0xad, 0x96, 0xb6, 0x9f, 0x52, 0xcc, 0x01, - 0xc8, 0xb3, 0x87, 0x6b, 0x9e, 0xea, 0xa9, 0xeb, 0xda, 0xac, 0xf9, 0x6f, - 0xde, 0xa1, 0x44, 0x32, 0x52, 0x49, 0x47, 0xff, 0x65, 0x79, 0x1e, 0xc5, - 0x73, 0x17, 0xb3, 0x36, 0xfc, 0x45, 0xca, 0x90, 0x37, 0x59, 0x1e, 0x16, - 0xab, 0x09, 0x69, 0xcf, 0xda, 0x56, 0x51, 0xfd, 0xeb, 0xcf, 0xcb, 0x8f, - 0xb1, 0xc3, 0x45, 0x2b, 0x7c, 0x0a, 0xa5, 0x9c, 0x0d, 0x2c, 0xad, 0x1c, - 0xd3, 0x33, 0xdd, 0xfe, 0x93, 0x69, 0xa2, 0x4b, 0x4b, 0xcf, 0x1d, 0x20, - 0x98, 0x4a, 0x4f, 0x5b, 0xe9, 0x24, 0xca, 0xfa, 0x18, 0x11, 0x81, 0x8b, - 0x7a, 0xb4, 0x5a, 0xc8, 0xdf, 0x6f, 0x5f, 0x21, 0x07, 0x31, 0x00 -}; + 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, 0x01, 0x31, 0x00, 0x30, 0x0f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x02, 0x04, 0x00, 0xa0, 0x82, 0x09, + 0xc8, 0x30, 0x82, 0x04, 0x1a, 0x30, 0x82, 0x03, 0x02, 0xa0, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x11, 0x00, 0xf2, 0xa1, 0x08, 0xdf, 0x12, 0x84, 0xb9, + 0x73, 0x6c, 0x23, 0x73, 0xe1, 0x1f, 0xf3, 0xac, 0x7a, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, + 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, + 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, + 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, 0x2e, + 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, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, 0x1e, + 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, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x6d, 0x31, 0x12, 0x30, 0x10, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x33, 0x34, 0x36, 0x2d, + 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, + 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, + 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, + 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, 0x82, 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, + 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xf5, 0x09, 0x64, 0x4a, 0x26, 0xfe, + 0xc0, 0x98, 0x55, 0x6a, 0x1d, 0x5d, 0x1c, 0xc7, 0x38, 0xaf, 0xfd, 0x49, + 0x9e, 0x85, 0x3f, 0xd6, 0x45, 0x0e, 0x99, 0x09, 0x85, 0x69, 0x84, 0x3c, + 0xfe, 0x72, 0xa5, 0x56, 0xfa, 0x11, 0x4f, 0x6b, 0x7d, 0x32, 0x2b, 0x0c, + 0xbf, 0x8f, 0xac, 0x47, 0x96, 0x22, 0x82, 0x3d, 0xf5, 0x64, 0x74, 0x7e, + 0x62, 0x68, 0x74, 0xcd, 0x0a, 0xec, 0x84, 0xc5, 0x15, 0x06, 0x0e, 0x5a, + 0x2f, 0x20, 0xe3, 0xc9, 0x67, 0xcd, 0xdd, 0x01, 0xb8, 0xb3, 0x18, 0x87, + 0x8c, 0xa9, 0x58, 0x86, 0x0f, 0xb6, 0xc3, 0x42, 0x7e, 0x87, 0x48, 0x5e, + 0x10, 0x49, 0xc7, 0xd7, 0xb7, 0xb8, 0xa6, 0x34, 0x08, 0x0c, 0x94, 0xf4, + 0xbb, 0x2a, 0x06, 0xa4, 0x4f, 0xec, 0xbc, 0xc4, 0x37, 0xbe, 0x99, 0x10, + 0x23, 0x37, 0x24, 0xb1, 0xdf, 0xcb, 0xe6, 0x3f, 0xc1, 0xf0, 0x0f, 0x04, + 0x03, 0xc8, 0xb0, 0x1e, 0xd6, 0xb8, 0xae, 0x77, 0xe1, 0x4d, 0x6d, 0x97, + 0x69, 0x6d, 0x8a, 0x73, 0x66, 0x32, 0x57, 0x6f, 0xcf, 0xea, 0x1e, 0x7b, + 0x87, 0x03, 0x75, 0xb1, 0xef, 0x83, 0x64, 0x26, 0xf1, 0x3f, 0xbf, 0xe6, + 0x28, 0x03, 0x72, 0x57, 0xbf, 0x47, 0x29, 0x99, 0x8f, 0x74, 0x1d, 0x01, + 0x16, 0xad, 0xb2, 0xdf, 0x80, 0xa4, 0xd3, 0x8b, 0xeb, 0x61, 0xd1, 0x40, + 0x68, 0xb9, 0xa2, 0xa5, 0xef, 0x2b, 0xe5, 0x78, 0xe8, 0x28, 0x88, 0x87, + 0xb7, 0x53, 0x49, 0xbb, 0xe4, 0xea, 0x0d, 0x5e, 0x96, 0xa5, 0xdd, 0x1f, + 0x0b, 0x25, 0x8b, 0xb5, 0x95, 0x46, 0xe7, 0xba, 0xb8, 0xc4, 0x0a, 0x36, + 0xb1, 0x89, 0xeb, 0x27, 0x5d, 0xd9, 0x97, 0x24, 0x59, 0xa3, 0x9b, 0xb0, + 0x23, 0x0b, 0xd2, 0xec, 0x65, 0x91, 0xf9, 0xf0, 0xa0, 0x74, 0x5f, 0xb4, + 0xce, 0x22, 0x27, 0x18, 0x37, 0xe2, 0x4b, 0xfc, 0x91, 0xf9, 0x09, 0x15, + 0xe6, 0xdb, 0x06, 0x9b, 0x4d, 0x82, 0xdc, 0x36, 0x14, 0x48, 0xc6, 0xd5, + 0x87, 0xca, 0xec, 0x5a, 0xa2, 0x29, 0x33, 0xef, 0x22, 0x0c, 0x4b, 0xbf, + 0xe7, 0x2f, 0x95, 0xe1, 0xd3, 0xa5, 0xd8, 0xaa, 0x44, 0x77, 0x29, 0xa3, + 0x20, 0x33, 0xd2, 0x51, 0xa2, 0xf9, 0x4a, 0x6f, 0xf7, 0x3e, 0xf7, 0x0b, + 0x8a, 0xec, 0xc1, 0x99, 0x1d, 0x47, 0xf3, 0x74, 0x02, 0x04, 0xab, 0x8e, + 0x62, 0x4c, 0x9e, 0x00, 0xc2, 0x84, 0xd7, 0xd0, 0xf8, 0xe4, 0x1c, 0x9d, + 0x98, 0x15, 0xa8, 0x8f, 0x08, 0x98, 0x4e, 0x5a, 0xfa, 0xd6, 0x60, 0x87, + 0x12, 0xdc, 0x8e, 0xfd, 0xcb, 0xb3, 0x13, 0x97, 0x7a, 0xa8, 0x8c, 0x56, + 0x2e, 0x49, 0x26, 0x60, 0xe9, 0x4a, 0xdc, 0xec, 0x3f, 0xf0, 0x94, 0xcd, + 0x90, 0x8e, 0x7c, 0x21, 0x3f, 0x80, 0x14, 0x33, 0xdd, 0xb0, 0x00, 0xe2, + 0x09, 0x37, 0x06, 0xdd, 0x17, 0x69, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, + 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, + 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x8e, 0x2d, 0x13, 0x1e, 0x60, + 0xaa, 0xda, 0x52, 0x53, 0x55, 0x64, 0x3a, 0xdc, 0xb6, 0x7a, 0xc0, 0xba, + 0xfa, 0xeb, 0x20, 0xab, 0xb6, 0x63, 0xcf, 0xcd, 0x9b, 0xdb, 0x71, 0xf3, + 0xa0, 0xd6, 0x91, 0xbf, 0x0c, 0xc1, 0xae, 0x8f, 0x02, 0x18, 0x00, 0x54, + 0xfb, 0x49, 0x03, 0x34, 0x8d, 0x92, 0x9d, 0x5d, 0x8d, 0xa8, 0x1c, 0x20, + 0x0f, 0x85, 0x60, 0xf9, 0xf6, 0x8b, 0xbb, 0x2b, 0x82, 0xce, 0xb3, 0xe2, + 0x91, 0xe7, 0xbd, 0x91, 0x61, 0x52, 0x36, 0x40, 0x9f, 0x2f, 0x5e, 0xa6, + 0x5d, 0x2f, 0xb3, 0x81, 0xe7, 0xf1, 0x87, 0xbe, 0xc5, 0x9d, 0x67, 0x5a, + 0xf7, 0x41, 0x1e, 0x73, 0xb0, 0x1e, 0xdc, 0x4f, 0x8d, 0x53, 0x21, 0x38, + 0x1b, 0xfd, 0x92, 0x43, 0x68, 0x83, 0x03, 0xd0, 0x9a, 0xca, 0x92, 0x14, + 0x73, 0x04, 0x94, 0x2a, 0x93, 0x22, 0x60, 0x5e, 0xee, 0xb6, 0xec, 0x0f, + 0xb0, 0xc8, 0x92, 0x97, 0xfb, 0x5d, 0xed, 0x1f, 0xa0, 0x5f, 0xe4, 0x98, + 0x2f, 0xf6, 0x13, 0x78, 0x99, 0xec, 0xb3, 0xf1, 0x0d, 0x27, 0xaa, 0x19, + 0x95, 0x39, 0xdb, 0xb0, 0x7b, 0x96, 0x74, 0x03, 0x5e, 0x51, 0xf5, 0x15, + 0x27, 0xce, 0xca, 0x0b, 0x2a, 0x0d, 0x43, 0xb3, 0x68, 0x17, 0x1e, 0x11, + 0x60, 0xd9, 0x84, 0x9b, 0xc3, 0x53, 0xce, 0xbd, 0xf4, 0x61, 0x51, 0x4b, + 0x41, 0x00, 0x7e, 0xe1, 0x5f, 0x69, 0xb3, 0x4a, 0x89, 0x7e, 0x47, 0x67, + 0xfd, 0x76, 0xf8, 0x94, 0x2f, 0x72, 0xb6, 0x14, 0x08, 0x2c, 0x16, 0x4e, + 0x9d, 0x37, 0x62, 0xbf, 0x11, 0x67, 0xc0, 0x70, 0x71, 0xec, 0x55, 0x51, + 0x4e, 0x46, 0x76, 0xb4, 0xc3, 0xeb, 0x52, 0x06, 0x17, 0x06, 0xce, 0x61, + 0x43, 0xce, 0x26, 0x80, 0x68, 0xb6, 0x2d, 0x57, 0xba, 0x8c, 0x7d, 0xb7, + 0xc5, 0x05, 0x2c, 0xf8, 0xa3, 0x69, 0xf8, 0x96, 0xad, 0xac, 0xd1, 0x30, + 0x82, 0x05, 0xa6, 0x30, 0x82, 0x03, 0x8e, 0xa0, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x10, 0x73, 0xd1, 0xe1, 0x1d, 0xa9, 0x75, 0xfd, 0x0c, 0xda, 0x7f, + 0xfa, 0x43, 0x3c, 0x26, 0xbd, 0x3d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x7e, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, + 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, + 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, + 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, + 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, + 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x30, + 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, 0x5a, 0x17, 0x0d, + 0x32, 0x37, 0x30, 0x33, 0x31, 0x34, 0x30, 0x33, 0x30, 0x32, 0x34, 0x31, + 0x5a, 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, + 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, + 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, + 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x30, 0x30, + 0x2e, 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, 0x76, 0x69, 0x63, 0x65, 0x3b, 0x20, 0x73, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, 0x37, 0x33, 0x34, 0x36, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa5, 0x45, 0x13, 0xf2, + 0xb2, 0xcb, 0x4b, 0x0f, 0xb4, 0x44, 0x25, 0x9c, 0x8a, 0x68, 0x54, 0xd5, + 0x45, 0x1e, 0x15, 0x89, 0x5b, 0xb8, 0xce, 0xda, 0x5a, 0x42, 0xe6, 0x9a, + 0x8c, 0xc1, 0xcb, 0xe8, 0xc5, 0xf5, 0x8f, 0x49, 0x0e, 0x02, 0xef, 0x5e, + 0x97, 0x1a, 0x91, 0xa4, 0x94, 0xc3, 0x50, 0x13, 0xe5, 0x13, 0xb7, 0x7f, + 0x26, 0x53, 0x19, 0xb0, 0x37, 0xa5, 0xef, 0xe6, 0x2a, 0x39, 0xdc, 0x93, + 0x37, 0xe2, 0x3d, 0x7f, 0xcb, 0x4b, 0x93, 0xa2, 0xc3, 0x69, 0x78, 0xc9, + 0x01, 0xfa, 0x68, 0x3b, 0xe0, 0xe2, 0x22, 0x6c, 0xeb, 0xe4, 0x8a, 0xa8, + 0x3e, 0xf5, 0x20, 0x82, 0xa8, 0x62, 0x68, 0x59, 0x78, 0x24, 0xde, 0xef, + 0x47, 0x43, 0xb1, 0x6c, 0x38, 0x29, 0xd3, 0x69, 0x3f, 0xae, 0x35, 0x57, + 0x75, 0x80, 0xc9, 0x21, 0xe7, 0x01, 0xb9, 0x54, 0x8b, 0x6e, 0x4e, 0x2e, + 0x5a, 0x5b, 0x77, 0xa4, 0x22, 0xc2, 0x7b, 0x95, 0xb9, 0x39, 0x2c, 0xbd, + 0xc2, 0x1e, 0x02, 0xa6, 0xb2, 0xbc, 0x0f, 0x7a, 0xcb, 0xdc, 0xbc, 0xbc, + 0x90, 0x66, 0xe3, 0xca, 0x46, 0x53, 0x3e, 0x98, 0xff, 0x2e, 0x78, 0x9f, + 0xd3, 0xa1, 0x12, 0x93, 0x66, 0x7d, 0xcc, 0x94, 0x6b, 0xec, 0x19, 0x0e, + 0x20, 0x45, 0x22, 0x57, 0x6d, 0x9e, 0xd0, 0x89, 0xf2, 0xa9, 0x34, 0xdc, + 0xab, 0xa5, 0x73, 0x47, 0x38, 0xe3, 0x7f, 0x98, 0x3a, 0x61, 0xae, 0x6c, + 0x4d, 0xf2, 0x31, 0x90, 0xcb, 0x83, 0xc1, 0xee, 0xb4, 0xf2, 0x9a, 0x28, + 0x5f, 0xbb, 0x7d, 0x89, 0xdf, 0xa2, 0x31, 0xb6, 0x1d, 0x39, 0x2b, 0x70, + 0xbf, 0x1e, 0xad, 0xe1, 0x74, 0x94, 0x1d, 0xf8, 0xc5, 0x1a, 0x8d, 0x13, + 0x45, 0xf0, 0x6a, 0x80, 0x0c, 0x5d, 0xbb, 0x46, 0x8a, 0x43, 0xd0, 0xff, + 0x21, 0x39, 0x57, 0x53, 0x5b, 0x51, 0xf8, 0xa2, 0x8f, 0x7f, 0x27, 0xc7, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, 0x01, + 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x02, + 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, + 0xe8, 0xe9, 0xac, 0x16, 0x5c, 0x5e, 0xb2, 0xe8, 0xeb, 0xff, 0x57, 0x27, + 0x20, 0x08, 0x72, 0x63, 0x9b, 0xe5, 0xb5, 0x16, 0x30, 0x81, 0xb2, 0x06, + 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, 0x30, 0x81, 0xa7, 0x80, 0x14, + 0x04, 0x94, 0x66, 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, 0x13, + 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, 0x8f, 0xa1, 0x81, 0x83, 0xa4, + 0x81, 0x80, 0x30, 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, + 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, + 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, + 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, + 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, + 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x23, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, 0x65, + 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x65, 0x6d, + 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, 0x09, + 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, 0x9a, 0x9a, 0x30, 0x12, 0x06, + 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, + 0x04, 0x02, 0x02, 0x1c, 0xb2, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, 0x01, + 0x00, 0x25, 0xce, 0xd2, 0x02, 0x48, 0xbb, 0xbe, 0xfc, 0xb6, 0xa4, 0x87, + 0x87, 0xe0, 0x21, 0x7d, 0xfa, 0x23, 0xc3, 0x0d, 0x73, 0x8f, 0x46, 0xe7, + 0x09, 0x59, 0xda, 0x2e, 0x55, 0x59, 0xff, 0x3c, 0x1b, 0xf6, 0xf8, 0x9a, + 0xc4, 0x1c, 0xf7, 0xac, 0xca, 0xe7, 0x63, 0xf2, 0xc7, 0xd6, 0x0c, 0x2d, + 0xa6, 0xad, 0x55, 0xf4, 0x10, 0x0e, 0xa8, 0x82, 0x0f, 0x88, 0xb5, 0x44, + 0xe8, 0x8e, 0x84, 0x08, 0xf7, 0xdd, 0xe7, 0x10, 0xce, 0x71, 0x56, 0x57, + 0x3f, 0xed, 0x48, 0xee, 0xe2, 0x5d, 0x08, 0x0a, 0x58, 0xe4, 0xfe, 0xbc, + 0x8c, 0x27, 0x1a, 0x46, 0x3f, 0xd5, 0x2d, 0xdb, 0x0b, 0x71, 0x73, 0xd1, + 0x49, 0xf3, 0x5c, 0x86, 0x4d, 0x0a, 0xe1, 0xeb, 0x53, 0x21, 0x38, 0x4f, + 0xec, 0x1e, 0xc2, 0x68, 0x1f, 0x7d, 0xa6, 0x33, 0xe9, 0xa5, 0x37, 0x2a, + 0xef, 0xcd, 0x78, 0x56, 0xb3, 0x39, 0x60, 0xf4, 0xa5, 0xf9, 0x2b, 0x85, + 0xcf, 0xe6, 0x1c, 0x7c, 0x8a, 0x5d, 0xe8, 0x26, 0x02, 0xcf, 0x7a, 0x56, + 0x1f, 0xae, 0x0d, 0x71, 0x20, 0xee, 0xec, 0x3b, 0xae, 0x95, 0x25, 0x15, + 0xc8, 0xf6, 0x92, 0x5d, 0xb8, 0x9b, 0xc2, 0xb4, 0x95, 0x33, 0x13, 0x76, + 0x45, 0xbe, 0x21, 0xe2, 0x3a, 0x69, 0x66, 0xd7, 0xff, 0x22, 0x00, 0x89, + 0xc9, 0x44, 0xb6, 0x54, 0x38, 0x1f, 0x33, 0xe4, 0xda, 0x7b, 0x87, 0xf3, + 0x23, 0xed, 0xf5, 0x16, 0x08, 0xbe, 0x4b, 0xea, 0x91, 0x8f, 0x91, 0x8b, + 0x4e, 0xd1, 0x02, 0x06, 0xa2, 0x77, 0x15, 0x03, 0x46, 0x11, 0x7d, 0x5b, + 0xea, 0x7a, 0xf6, 0x86, 0x7d, 0x96, 0xb7, 0x73, 0x9b, 0x5b, 0x32, 0xc3, + 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, 0x21, 0x11, 0x68, 0xb2, 0xd6, 0x8d, 0xc4, 0xf8, 0xe4, 0x70, 0x85, + 0x19, 0xa7, 0x82, 0x27, 0x2c, 0x24, 0x21, 0x7a, 0x3b, 0xad, 0x8a, 0xd3, + 0xae, 0xda, 0x78, 0x3c, 0x6c, 0xab, 0xa2, 0xaa, 0x36, 0xf0, 0x1c, 0x58, + 0xd4, 0x72, 0x5e, 0xe8, 0x8b, 0x41, 0x08, 0xf5, 0x85, 0xdd, 0xee, 0x99, + 0x12, 0xf4, 0xd6, 0x41, 0x83, 0x69, 0xe7, 0x79, 0x19, 0xa3, 0x74, 0xc4, + 0x34, 0x2a, 0x8a, 0x7e, 0x4d, 0xbb, 0x2c, 0x49, 0x19, 0xf7, 0x98, 0x98, + 0xfc, 0x81, 0xf7, 0x9b, 0x7f, 0xff, 0xd9, 0x66, 0xf4, 0x51, 0x14, 0x29, + 0x2a, 0x14, 0x1d, 0x4f, 0xbd, 0x91, 0xba, 0x6f, 0x32, 0x34, 0x3c, 0x40, + 0x28, 0x6c, 0x97, 0xf8, 0x6d, 0x38, 0xcd, 0xa3, 0x7b, 0x18, 0xc8, 0x77, + 0x58, 0x4d, 0x53, 0x30, 0x7f, 0x4d, 0x89, 0xca, 0x95, 0x6e, 0xb5, 0xb8, + 0x8e, 0xc8, 0x2d, 0x18, 0x2f, 0x52, 0x2a, 0xde, 0xac, 0x56, 0x8d, 0x8c, + 0x67, 0x14, 0xf6, 0xb9, 0xf1, 0x65, 0xd3, 0x22, 0x43, 0xa3, 0x98, 0x42, + 0x20, 0x43, 0x4c, 0xdf, 0xf2, 0xeb, 0x31, 0x8c, 0x0e, 0x53, 0x5b, 0x99, + 0x82, 0xc3, 0x48, 0x04, 0x53, 0xad, 0x96, 0xb6, 0x9f, 0x52, 0xcc, 0x01, + 0xc8, 0xb3, 0x87, 0x6b, 0x9e, 0xea, 0xa9, 0xeb, 0xda, 0xac, 0xf9, 0x6f, + 0xde, 0xa1, 0x44, 0x32, 0x52, 0x49, 0x47, 0xff, 0x65, 0x79, 0x1e, 0xc5, + 0x73, 0x17, 0xb3, 0x36, 0xfc, 0x45, 0xca, 0x90, 0x37, 0x59, 0x1e, 0x16, + 0xab, 0x09, 0x69, 0xcf, 0xda, 0x56, 0x51, 0xfd, 0xeb, 0xcf, 0xcb, 0x8f, + 0xb1, 0xc3, 0x45, 0x2b, 0x7c, 0x0a, 0xa5, 0x9c, 0x0d, 0x2c, 0xad, 0x1c, + 0xd3, 0x33, 0xdd, 0xfe, 0x93, 0x69, 0xa2, 0x4b, 0x4b, 0xcf, 0x1d, 0x20, + 0x98, 0x4a, 0x4f, 0x5b, 0xe9, 0x24, 0xca, 0xfa, 0x18, 0x11, 0x81, 0x8b, + 0x7a, 0xb4, 0x5a, 0xc8, 0xdf, 0x6f, 0x5f, 0x21, 0x07, 0x31, 0x00}; const uint32_t kOemCertSystemId = 7346; @@ -235,17 +237,29 @@ const uint32_t kOemCertSystemId = 7346; namespace wvcdm { -class CryptoSessionForTest: public CryptoSession { +class CryptoSessionForTest : public CryptoSession, public testing::Test { public: 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) { std::string oem_cert(reinterpret_cast(kOemCert), sizeof(kOemCert)); uint32_t system_id; - ASSERT_TRUE(CryptoSessionForTest::ExtractSystemIdFromOemCert(oem_cert, - &system_id)); + ASSERT_TRUE( + CryptoSessionForTest::ExtractSystemIdFromOemCert(oem_cert, &system_id)); ASSERT_EQ(kOemCertSystemId, system_id); } diff --git a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp index d718568b..26a4d8e9 100644 --- a/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp +++ b/libwvdrmengine/cdm/core/test/initialization_data_unittest.cpp @@ -441,7 +441,7 @@ TEST_F(InitializationDataTest, ExtractSubLicense) { InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kSubLicensePsshBox); ASSERT_FALSE(init_data.IsEmpty()); std::vector keys = - init_data.ExtractEmbeddedKeys(); + init_data.ExtractSublicenseKeys(); ASSERT_EQ(keys.size(), 2UL); 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"); @@ -453,7 +453,7 @@ TEST_F(InitializationDataTest, ExtractEmptySubLicense) { InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, kWidevinePssh); ASSERT_FALSE(init_data.IsEmpty()); std::vector keys = - init_data.ExtractEmbeddedKeys(); + init_data.ExtractSublicenseKeys(); ASSERT_TRUE(keys.empty()); } @@ -644,8 +644,8 @@ TEST_P(HlsConstructionTest, InitData) { for (size_t i = 0; i < param.key_ids_.size(); ++i) { bool key_id_found = false; if (param.key_ids_[i].size() != 32) continue; - for (int j = 0; j < cenc_header.key_id_size(); ++j) { - if (param.key_ids_[i] == b2a_hex(cenc_header.key_id(j))) { + for (int j = 0; j < cenc_header.key_ids_size(); ++j) { + if (param.key_ids_[i] == b2a_hex(cenc_header.key_ids(j))) { key_id_found = true; break; } @@ -752,7 +752,7 @@ TEST_P(HlsParseTest, Parse) { } else if (param.key_.compare(kJsonContentId) == 0) { EXPECT_EQ(param.value_, cenc_header.content_id()); } 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())); diff --git a/libwvdrmengine/cdm/metrics/include/metrics_collections.h b/libwvdrmengine/cdm/metrics/include/metrics_collections.h index 435edb58..ccde3ed2 100644 --- a/libwvdrmengine/cdm/metrics/include/metrics_collections.h +++ b/libwvdrmengine/cdm/metrics/include/metrics_collections.h @@ -131,6 +131,7 @@ class CryptoMetrics { ValueMetric oemcrypto_is_anti_rollback_hw_present_; ValueMetric oemcrypto_is_keybox_valid_; EventMetric oemcrypto_load_device_rsa_key_; + EventMetric oemcrypto_load_entitled_keys_; EventMetric oemcrypto_load_keys_; ValueMetric oemcrypto_max_hdcp_capability_; ValueMetric oemcrypto_max_number_of_sessions_; diff --git a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp index 303bb6b4..13e76ce8 100644 --- a/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp +++ b/libwvdrmengine/cdm/metrics/src/metrics_collections.cpp @@ -196,6 +196,9 @@ CryptoMetrics::CryptoMetrics() : oemcrypto_load_device_rsa_key_( "/drm/widevine/oemcrypto/load_device_rsa_key/time", "oemcrypto_error"), + oemcrypto_load_entitled_keys_( + "/drm/widevine/oemcrypto/load_entitled_keys/time", + "oemcrypto_error"), oemcrypto_load_keys_( "/drm/widevine/oemcrypto/load_keys/time", "oemcrypto_error"), @@ -277,6 +280,7 @@ void CryptoMetrics::Serialize(MetricsGroup* metrics) { oemcrypto_is_anti_rollback_hw_present_.Serialize(&serializer); oemcrypto_is_keybox_valid_.Serialize(&serializer); oemcrypto_load_device_rsa_key_.Serialize(&serializer); + oemcrypto_load_entitled_keys_.Serialize(&serializer); oemcrypto_load_keys_.Serialize(&serializer); oemcrypto_max_hdcp_capability_.Serialize(&serializer); oemcrypto_max_number_of_sessions_.Serialize(&serializer);