Source release v3.3.0
This commit is contained in:
@@ -3,9 +3,11 @@
|
||||
#ifndef WVCDM_CORE_CDM_ENGINE_H_
|
||||
#define WVCDM_CORE_CDM_ENGINE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cdm_session_map.h"
|
||||
#include "certificate_provisioning.h"
|
||||
#include "clock.h"
|
||||
#include "crypto_session.h"
|
||||
@@ -26,11 +28,9 @@ class CryptoEngine;
|
||||
class UsagePropertySet;
|
||||
class WvCdmEventListener;
|
||||
|
||||
typedef std::map<CdmSessionId, CdmSession*> CdmSessionMap;
|
||||
typedef std::map<
|
||||
CdmKeySetId,
|
||||
std::pair<CdmSessionId, int64_t /* expiration time in seconds */> >
|
||||
CdmReleaseKeySetMap;
|
||||
// Keep expiration time for each key set
|
||||
typedef std::map<CdmKeySetId,
|
||||
std::pair<CdmSessionId, int64_t> > CdmReleaseKeySetMap;
|
||||
|
||||
class CdmEngine {
|
||||
public:
|
||||
@@ -44,6 +44,20 @@ class CdmEngine {
|
||||
virtual CdmResponseType SetServiceCertificate(
|
||||
const std::string& certificate);
|
||||
|
||||
// Report whether the service certificate has been set.
|
||||
virtual bool HasServiceCertificate();
|
||||
|
||||
// Generate and return a Service Certificate Request message.
|
||||
// This message can be sent to the License Server to get a service
|
||||
// certificate.
|
||||
virtual bool GetServiceCertificateRequest(CdmKeyMessage* request);
|
||||
|
||||
// Parse the message returned by the License Server in response to a
|
||||
// Service Certificate Request message. Return the service certificate
|
||||
// from the parsed response.
|
||||
virtual CdmResponseType ParseServiceCertificateResponse(
|
||||
const std::string& response, std::string* certificate);
|
||||
|
||||
// Session related methods
|
||||
virtual CdmResponseType OpenSession(
|
||||
const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
|
||||
@@ -158,24 +172,45 @@ class CdmEngine {
|
||||
virtual CdmResponseType Unprovision(CdmSecurityLevel security_level);
|
||||
|
||||
// Delete OEMCrypto usage tables. Used by Unprovision().
|
||||
CdmResponseType DeleteUsageTable(CdmSecurityLevel security_level);
|
||||
virtual CdmResponseType DeleteUsageTable(CdmSecurityLevel security_level);
|
||||
|
||||
// Return the list of key_set_ids stored on the current (origin-specific)
|
||||
// file system.
|
||||
virtual CdmResponseType ListStoredLicenses(
|
||||
CdmSecurityLevel security_level, std::vector<std::string>* key_set_ids);
|
||||
|
||||
// Return the list of key_set_ids stored as usage records on the
|
||||
// current (origin-specific) file system.
|
||||
virtual CdmResponseType ListUsageRecords(
|
||||
const std::string& app_id, CdmSecurityLevel security_level,
|
||||
std::vector<std::string>* ksids);
|
||||
|
||||
// Delete the usage record for the given key_set_id. This removes the
|
||||
// usage record in the file system and the OEMCrypto usage record.
|
||||
virtual CdmResponseType DeleteUsageRecord(const std::string& app_id,
|
||||
CdmSecurityLevel security_level,
|
||||
const std::string& key_set_id);
|
||||
|
||||
// Usage related methods for streaming licenses
|
||||
// Retrieve a random usage info from the list of all usage infos for this app
|
||||
// id.
|
||||
virtual CdmResponseType GetUsageInfo(const std::string& app_id,
|
||||
CdmUsageInfo* usage_info);
|
||||
|
||||
// Retrieve the usage info for the specified pst.
|
||||
// Returns UNKNOWN_ERROR if no usage info was found.
|
||||
virtual CdmResponseType GetUsageInfo(const std::string& app_id,
|
||||
const CdmSecureStopId& ssid,
|
||||
CdmUsageInfo* usage_info);
|
||||
|
||||
// Release all usage records for the current origin.
|
||||
virtual CdmResponseType ReleaseAllUsageInfo(const std::string& app_id,
|
||||
CdmSecurityLevel security_level);
|
||||
|
||||
// Release all usage records for the current origin. Span all
|
||||
// security levels.
|
||||
virtual CdmResponseType ReleaseAllUsageInfo(const std::string& app_id);
|
||||
|
||||
virtual CdmResponseType ReleaseUsageInfo(
|
||||
const CdmUsageInfoReleaseMessage& message);
|
||||
virtual CdmResponseType LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
@@ -215,7 +250,7 @@ class CdmEngine {
|
||||
CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature);
|
||||
|
||||
virtual size_t SessionSize() const { return sessions_.size(); }
|
||||
virtual size_t SessionSize() const { return session_map_.Size(); }
|
||||
|
||||
// Is the key known to any session?
|
||||
virtual bool IsKeyLoaded(const KeyId& key_id);
|
||||
@@ -255,7 +290,7 @@ class CdmEngine {
|
||||
void CloseExpiredReleaseSessions();
|
||||
|
||||
// instance variables
|
||||
CdmSessionMap sessions_;
|
||||
CdmSessionMap session_map_;
|
||||
CdmReleaseKeySetMap release_key_sets_;
|
||||
scoped_ptr<CertificateProvisioning> cert_provisioning_;
|
||||
SecurityLevel cert_provisioning_requested_security_level_;
|
||||
@@ -276,14 +311,7 @@ class CdmEngine {
|
||||
scoped_ptr<UsagePropertySet> usage_property_set_;
|
||||
int64_t last_usage_information_update_time_;
|
||||
|
||||
// Locks the list of sessions, |sessions_|, for the event timer. It will be
|
||||
// locked in OpenSession, CloseSession. It is also locked in OnTimerEvent and
|
||||
// OnKeyReleaseEvent while the list of event listeners is being generated.
|
||||
// The layer above the CDM implementation is expected to handle thread
|
||||
// synchronization to make sure other functions that access sessions do not
|
||||
// occur simultaneously with OpenSession or CloseSession.
|
||||
Lock session_list_lock_;
|
||||
|
||||
// Protect release_key_sets_ from non-thread-safe operations.
|
||||
Lock release_key_sets_lock_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CdmEngine);
|
||||
|
||||
@@ -28,6 +28,9 @@ class CdmSession {
|
||||
CdmSession(FileSystem* file_system);
|
||||
virtual ~CdmSession();
|
||||
|
||||
void Close() { closed_ = true; }
|
||||
bool IsClosed() { return closed_; }
|
||||
|
||||
virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set);
|
||||
virtual CdmResponseType Init(ServiceCertificate* service_certificate,
|
||||
CdmClientPropertySet* cdm_client_property_set,
|
||||
@@ -171,6 +174,7 @@ class CdmSession {
|
||||
|
||||
// instance variables
|
||||
bool initialized_;
|
||||
bool closed_; // Session closed, but final shared_ptr has not been released.
|
||||
CdmSessionId session_id_;
|
||||
scoped_ptr<CdmLicense> license_parser_;
|
||||
scoped_ptr<CryptoSession> crypto_session_;
|
||||
|
||||
52
core/include/cdm_session_map.h
Normal file
52
core/include/cdm_session_map.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef WVCDM_CORE_CDM_SESSION_MAP_H_
|
||||
#define WVCDM_CORE_CDM_SESSION_MAP_H_
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "lock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class CdmSession;
|
||||
|
||||
typedef std::list<std::shared_ptr<CdmSession> > CdmSessionList;
|
||||
|
||||
class CdmSessionMap {
|
||||
public:
|
||||
CdmSessionMap() {}
|
||||
virtual ~CdmSessionMap();
|
||||
|
||||
void Add(const std::string& id, CdmSession* session);
|
||||
|
||||
bool CloseSession(const std::string& id);
|
||||
|
||||
bool Exists(const std::string& id);
|
||||
|
||||
size_t Size() const { return sessions_.size(); }
|
||||
|
||||
bool FindSession(const CdmSessionId& id,
|
||||
std::shared_ptr<CdmSession>& session);
|
||||
|
||||
void GetSessionList(CdmSessionList& sessions);
|
||||
|
||||
private:
|
||||
typedef std::map<CdmSessionId, std::shared_ptr<CdmSession> >
|
||||
CdmIdToSessionMap;
|
||||
|
||||
bool FindSessionNoLock(const CdmSessionId& session_id,
|
||||
std::shared_ptr<CdmSession>& session);
|
||||
|
||||
Lock lock_;
|
||||
CdmIdToSessionMap sessions_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CdmSessionMap);
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_CDM_SESSION_MAP_H_
|
||||
@@ -49,12 +49,6 @@ class CertificateProvisioning {
|
||||
video_widevine::SignedProvisioningMessage::ProtocolVersion
|
||||
GetProtocolVersion();
|
||||
|
||||
void ComposeJsonRequestAsQueryString(const std::string& message,
|
||||
CdmProvisioningRequest* request);
|
||||
bool ParseJsonResponse(const CdmProvisioningResponse& json_str,
|
||||
const std::string& start_substr,
|
||||
const std::string& end_substr, std::string* result);
|
||||
|
||||
CryptoSession crypto_session_;
|
||||
CdmCertificateType cert_type_;
|
||||
ServiceCertificate* service_certificate_;
|
||||
|
||||
@@ -68,12 +68,15 @@ class CryptoSession {
|
||||
virtual bool GenerateDerivedKeys(const std::string& message);
|
||||
virtual bool GenerateDerivedKeys(const std::string& message,
|
||||
const std::string& session_key);
|
||||
virtual 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);
|
||||
|
||||
|
||||
virtual bool RewrapCertificate(const std::string& signed_message,
|
||||
const std::string& signature,
|
||||
const std::string& nonce,
|
||||
const std::string& private_key,
|
||||
const std::string& iv,
|
||||
const std::string& wrapping_key,
|
||||
std::string* wrapped_private_key);
|
||||
|
||||
// Media data path
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||
@@ -127,7 +130,7 @@ class CryptoSession {
|
||||
const std::string& signature);
|
||||
|
||||
private:
|
||||
bool GetProvisioningMethod(CdmClientTokenType* token_type);
|
||||
bool GetProvisioningMethod(CdmClientTokenType& token_type);
|
||||
void Init();
|
||||
void Terminate();
|
||||
bool GetTokenFromKeybox(std::string* token);
|
||||
@@ -140,6 +143,17 @@ class CryptoSession {
|
||||
bool GenerateRsaSignature(const std::string& message, std::string* signature);
|
||||
size_t GetOffset(std::string message, std::string field);
|
||||
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 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 SelectKey(const std::string& key_id);
|
||||
|
||||
static const OEMCrypto_Algorithm kInvalidAlgorithm =
|
||||
@@ -170,6 +184,7 @@ class CryptoSession {
|
||||
|
||||
bool open_;
|
||||
CdmClientTokenType pre_provision_token_type_;
|
||||
std::string oem_token_; // Cached OEMCrypto Public Key
|
||||
bool update_usage_table_after_close_session_;
|
||||
CryptoSessionId oec_session_id_;
|
||||
|
||||
|
||||
@@ -73,29 +73,45 @@ class DeviceFiles {
|
||||
virtual bool ReserveLicenseId(const std::string& key_set_id);
|
||||
virtual bool UnreserveLicenseId(const std::string& key_set_id);
|
||||
|
||||
// Store a usage record to the set of usage information on the file system.
|
||||
virtual bool StoreUsageInfo(const std::string& provider_session_token,
|
||||
const CdmKeyMessage& key_request,
|
||||
const CdmKeyResponse& key_response,
|
||||
const std::string& app_id,
|
||||
const std::string& key_set_id);
|
||||
|
||||
// Extract KSIDs from usage information on the file system.
|
||||
virtual bool ListUsageRecords(const std::string& app_id,
|
||||
std::vector<std::string>* ksids);
|
||||
|
||||
// Get the provider token for the given key_set_id.
|
||||
virtual bool GetProviderToken(const std::string& app_id,
|
||||
const std::string& key_set_id,
|
||||
std::string* provider_session_token);
|
||||
|
||||
// Delete the usage record for the given PST.
|
||||
virtual bool DeleteUsageInfo(const std::string& app_id,
|
||||
const std::string& provider_session_token);
|
||||
|
||||
// Delete usage information from the file system. Puts a list of all the
|
||||
// psts that were deleted from the file into |provider_session_tokens|.
|
||||
virtual bool DeleteAllUsageInfoForApp(
|
||||
const std::string& app_id,
|
||||
std::vector<std::string>* provider_session_tokens);
|
||||
|
||||
// Retrieve one usage info from the file. Subsequent calls will retrieve
|
||||
// subsequent entries in the table for this app_id.
|
||||
virtual bool RetrieveUsageInfo(
|
||||
const std::string& app_id,
|
||||
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info);
|
||||
|
||||
// Retrieve the usage info entry specified by |provider_session_token|.
|
||||
// Returns false if the entry could not be found.
|
||||
virtual bool RetrieveUsageInfo(const std::string& app_id,
|
||||
const std::string& provider_session_token,
|
||||
CdmKeyMessage* license_request,
|
||||
CdmKeyResponse* license_response);
|
||||
|
||||
// Retrieve the usage info entry specified by |key_set_id|.
|
||||
// Returns false if the entry could not be found.
|
||||
virtual bool RetrieveUsageInfoByKeySetId(const std::string& app_id,
|
||||
@@ -110,6 +126,7 @@ class DeviceFiles {
|
||||
CdmHlsMethod* method,
|
||||
std::vector<uint8_t>* media_segment_iv);
|
||||
virtual bool DeleteHlsAttributes(const std::string& key_set_id);
|
||||
|
||||
private:
|
||||
// Extract serial number and system ID from DRM Device certificate
|
||||
bool ExtractDeviceInfo(const std::string& device_certificate,
|
||||
@@ -138,7 +155,7 @@ class DeviceFiles {
|
||||
#if defined(UNIT_TEST)
|
||||
FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel);
|
||||
FRIEND_TEST(DeviceCertificateStoreTest, StoreCertificate);
|
||||
FRIEND_TEST(DeviceCertificateTest, ReadCertificate);
|
||||
FRIEND_TEST(DeviceCertificateTest, DISABLED_ReadCertificate);
|
||||
FRIEND_TEST(DeviceCertificateTest, HasCertificate);
|
||||
FRIEND_TEST(DeviceFilesStoreTest, StoreLicense);
|
||||
FRIEND_TEST(DeviceFilesHlsAttributesTest, Delete);
|
||||
|
||||
@@ -29,7 +29,7 @@ class CdmLicense {
|
||||
|
||||
virtual bool Init(
|
||||
ServiceCertificate* service_certificate, const std::string& client_token,
|
||||
CdmClientTokenType client_token_type, const std::string& serial_number,
|
||||
CdmClientTokenType client_token_type, const std::string& device_id,
|
||||
CryptoSession* session, PolicyEngine* policy_engine);
|
||||
|
||||
virtual CdmResponseType PrepareKeyRequest(
|
||||
@@ -52,7 +52,6 @@ class CdmLicense {
|
||||
int64_t grace_period_end_time);
|
||||
virtual bool RestoreLicenseForRelease(const CdmKeyMessage& license_request,
|
||||
const CdmKeyResponse& license_response);
|
||||
virtual bool HasInitData() { return stored_init_data_.get(); }
|
||||
virtual bool IsKeyLoaded(const KeyId& key_id);
|
||||
|
||||
virtual std::string provider_session_token() {
|
||||
@@ -89,9 +88,8 @@ class CdmLicense {
|
||||
std::string server_url_;
|
||||
std::string client_token_;
|
||||
CdmClientTokenType client_token_type_;
|
||||
std::string serial_number_;
|
||||
std::string device_id_;
|
||||
const CdmSessionId session_id_;
|
||||
scoped_ptr<InitializationData> stored_init_data_;
|
||||
bool initialized_;
|
||||
std::set<KeyId> loaded_keys_;
|
||||
std::string provider_session_token_;
|
||||
|
||||
@@ -37,7 +37,11 @@ class LicenseKeys {
|
||||
virtual bool ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_keys);
|
||||
|
||||
// Populates the CdmKeyStatusMap with the current content keys.
|
||||
// Returns current CdmKeyStatus for the given key.
|
||||
// Returns kKeyStatusKeyUnknown if key_id not found.
|
||||
virtual CdmKeyStatus GetKeyStatus(const KeyId& key_id);
|
||||
|
||||
// Populates a CdmKeyStatusMap with the current content keys.
|
||||
virtual void ExtractKeyStatuses(CdmKeyStatusMap* content_keys);
|
||||
|
||||
// Determines whether the specified key can be used under the current
|
||||
|
||||
@@ -34,6 +34,11 @@ class PolicyEngine {
|
||||
// status is not calculated to avoid overhead in the decryption path.
|
||||
virtual bool CanDecryptContent(const KeyId& key_id);
|
||||
|
||||
// Returns the current CdmKeyStatus for the given key, or
|
||||
// kKeyStatusKeyUnknown if the key is not found. This is useful for finding
|
||||
// out why a key is not usable.
|
||||
virtual CdmKeyStatus GetKeyStatus(const KeyId& key_id);
|
||||
|
||||
// OnTimerEvent is called when a timer fires. It notifies the Policy Engine
|
||||
// that the timer has fired and dispatches the relevant events through
|
||||
// |event_listener_|.
|
||||
@@ -104,11 +109,9 @@ class PolicyEngine {
|
||||
friend class PolicyEngineConstraintsTest;
|
||||
|
||||
void InitDevice(CryptoSession* crypto_session);
|
||||
void CheckDevice(int64_t current_time);
|
||||
|
||||
void SetDeviceResolution(uint32_t width, uint32_t height) {
|
||||
current_resolution_ = width * height;
|
||||
}
|
||||
void SetDeviceResolution(uint32_t width, uint32_t height);
|
||||
void CheckDeviceHdcpStatusOnTimer(int64_t current_time);
|
||||
void CheckDeviceHdcpStatus();
|
||||
|
||||
typedef enum {
|
||||
kLicenseStateInitial,
|
||||
|
||||
@@ -40,6 +40,9 @@ class Properties {
|
||||
static inline bool use_certificates_as_identification() {
|
||||
return use_certificates_as_identification_;
|
||||
}
|
||||
static inline bool provisioning_messages_are_binary() {
|
||||
return provisioning_messages_are_binary_;
|
||||
}
|
||||
static inline bool security_level_path_backward_compatibility_support() {
|
||||
return security_level_path_backward_compatibility_support_;
|
||||
}
|
||||
@@ -90,6 +93,9 @@ class Properties {
|
||||
static void set_use_certificates_as_identification(bool flag) {
|
||||
use_certificates_as_identification_ = flag;
|
||||
}
|
||||
static void set_provisioning_messages_are_binary(bool flag) {
|
||||
provisioning_messages_are_binary_ = flag;
|
||||
}
|
||||
static void set_security_level_path_backward_compatibility_support(
|
||||
bool flag) {
|
||||
security_level_path_backward_compatibility_support_ = flag;
|
||||
@@ -111,6 +117,7 @@ class Properties {
|
||||
static bool oem_crypto_use_userspace_buffers_;
|
||||
static bool use_certificates_as_identification_;
|
||||
static bool security_level_path_backward_compatibility_support_;
|
||||
static bool provisioning_messages_are_binary_;
|
||||
static scoped_ptr<CdmClientPropertySetMap> session_property_set_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(Properties);
|
||||
|
||||
@@ -11,13 +11,11 @@
|
||||
// Certificate Request to the target server to get one. Once the Service
|
||||
// Certificate is established for the session, it should not change.
|
||||
|
||||
#include "license_protocol.pb.h"
|
||||
#include "wv_cdm_types.h"
|
||||
#include <memory>
|
||||
|
||||
namespace video_widevine {
|
||||
class SignedMessage;
|
||||
class LicenseRequest;
|
||||
} // namespace video_widevine
|
||||
#include "license_protocol.pb.h"
|
||||
#include "privacy_crypto.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
@@ -25,23 +23,20 @@ class CryptoSession;
|
||||
|
||||
class ServiceCertificate {
|
||||
public:
|
||||
ServiceCertificate() {}
|
||||
ServiceCertificate() : has_certificate_(false) {}
|
||||
virtual ~ServiceCertificate() {}
|
||||
|
||||
// Set up a new service certificate.
|
||||
// Accept a serialized video_widevine::SignedDrmDeviceCertificate message.
|
||||
virtual CdmResponseType Init(const std::string& signed_certificate);
|
||||
|
||||
// Initialize the service certificate.
|
||||
// Set the certificate with no certificate and provider ID.
|
||||
virtual void Clear();
|
||||
bool has_certificate() const { return has_certificate_; }
|
||||
const std::string certificate() const { return certificate_; }
|
||||
const std::string& provider_id() const { return provider_id_; }
|
||||
|
||||
// Current state of certificate.
|
||||
// If !HasCertificate() and privacy mode is enabled, then should call
|
||||
// PrepareRequest() and pass the request to the license server.
|
||||
virtual bool HasCertificate() { return !certificate_.empty(); }
|
||||
virtual bool HasProviderId() { return !provider_id_.empty(); }
|
||||
virtual const std::string& provider_id() { return provider_id_; }
|
||||
// Verify the signature for a message.
|
||||
virtual CdmResponseType VerifySignedMessage(const std::string& message,
|
||||
const std::string& signature);
|
||||
|
||||
// Encrypt the ClientIdentification message for a provisioning or
|
||||
// licensing request. Encryption is performed using the current
|
||||
@@ -54,29 +49,23 @@ class ServiceCertificate {
|
||||
const video_widevine::ClientIdentification* clear_client_id,
|
||||
video_widevine::EncryptedClientIdentification* encrypted_client_id);
|
||||
|
||||
// Construct service certificate request.
|
||||
virtual bool PrepareRequest(CdmKeyMessage* signed_request);
|
||||
|
||||
// Parse service certificate response and make it usable.
|
||||
virtual CdmResponseType HandleResponse(
|
||||
const std::string& signed_respnse);
|
||||
|
||||
private:
|
||||
// Verify the signature on the signed service certificate.
|
||||
// Extract and save the certificate and provider_id.
|
||||
// Expected format: serialized video_widevine::SignedDrmDeviceCertificate.
|
||||
virtual CdmResponseType VerifyAndExtract(
|
||||
const std::string& raw_certificate);
|
||||
|
||||
// True while waiting for response to service certificate request.
|
||||
bool fetch_in_progress_;
|
||||
// Track whether object holds valid certificate
|
||||
bool has_certificate_;
|
||||
|
||||
// Certificate, verified and extracted from signed message.
|
||||
std::string certificate_;
|
||||
|
||||
// Certificate serial number.
|
||||
std::string serial_number_;
|
||||
|
||||
// Provider ID, extracted from certificate message.
|
||||
std::string provider_id_;
|
||||
|
||||
// Public key.
|
||||
std::unique_ptr<RsaPublicKey> public_key_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(ServiceCertificate);
|
||||
};
|
||||
|
||||
|
||||
@@ -99,6 +99,10 @@ static const std::string HLS_URI_ATTRIBUTE = "URI";
|
||||
|
||||
static const char EMPTY_ORIGIN[] = "";
|
||||
static const char EMPTY_SPOID[] = "";
|
||||
|
||||
//Policy engine HDCP enforcement
|
||||
static const uint32_t HDCP_UNSPECIFIED_VIDEO_RESOLUTION = 0;
|
||||
static const int64_t HDCP_DEVICE_CHECK_INTERVAL = 10;
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_WV_CDM_CONSTANTS_H_
|
||||
|
||||
@@ -177,9 +177,10 @@ enum CdmResponseType {
|
||||
UNPROVISION_ERROR_4,
|
||||
UNSUPPORTED_INIT_DATA,
|
||||
USAGE_INFO_NOT_FOUND,
|
||||
LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR, /* 140 */
|
||||
UNUSED_8, /* 140 */
|
||||
/* UNUSED_8 previously LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR */
|
||||
PARSE_SERVICE_CERTIFICATE_ERROR,
|
||||
SERVICE_CERTIFICATE_TYPE_ERROR,
|
||||
UNUSED_10, /* previously SERVICE_CERTIFICATE_TYPE_ERROR */
|
||||
CLIENT_ID_GENERATE_RANDOM_ERROR,
|
||||
CLIENT_ID_AES_INIT_ERROR,
|
||||
CLIENT_ID_AES_ENCRYPT_ERROR, /* 145 */
|
||||
@@ -194,7 +195,8 @@ enum CdmResponseType {
|
||||
UNUSED_2, /* previously INVALID_PARAMETERS_LIC_5 */
|
||||
INVALID_PARAMETERS_LIC_6,
|
||||
INVALID_PARAMETERS_LIC_7, /* 155 */
|
||||
LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR,
|
||||
UNUSED_9,
|
||||
/* UNUSED_9 previously LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR */
|
||||
CENC_INIT_DATA_UNAVAILABLE,
|
||||
PREPARE_CENC_CONTENT_ID_FAILED,
|
||||
WEBM_INIT_DATA_UNAVAILABLE,
|
||||
@@ -250,10 +252,29 @@ enum CdmResponseType {
|
||||
CERT_PROVISIONING_CLIENT_TOKEN_ERROR_2, /* 210 */
|
||||
LICENSING_CLIENT_TOKEN_ERROR_1,
|
||||
INVALID_PARAMETERS_ENG_17,
|
||||
STORE_LICENSE_ERROR_3,
|
||||
INVALID_PARAMETERS_ENG_18,
|
||||
LIST_LICENSE_ERROR_1,
|
||||
LIST_LICENSE_ERROR_2, /* 215 */
|
||||
LIST_USAGE_ERROR_1,
|
||||
LIST_USAGE_ERROR_2,
|
||||
DELETE_USAGE_ERROR_1,
|
||||
DELETE_USAGE_ERROR_2,
|
||||
DELETE_USAGE_ERROR_3, /* 220 */
|
||||
RELEASE_ALL_USAGE_INFO_ERROR_3,
|
||||
RELEASE_ALL_USAGE_INFO_ERROR_4,
|
||||
PRIVACY_MODE_ERROR_1,
|
||||
PRIVACY_MODE_ERROR_2,
|
||||
PRIVACY_MODE_ERROR_3, /* 225 */
|
||||
EMPTY_RESPONSE_ERROR_1,
|
||||
INVALID_PARAMETERS_ENG_19,
|
||||
PARSE_RESPONSE_ERROR_1,
|
||||
PARSE_RESPONSE_ERROR_2,
|
||||
PARSE_RESPONSE_ERROR_3, /* 230 */
|
||||
PARSE_RESPONSE_ERROR_4,
|
||||
};
|
||||
|
||||
enum CdmKeyStatus {
|
||||
kKeyStatusKeyUnknown,
|
||||
kKeyStatusUsable,
|
||||
kKeyStatusExpired,
|
||||
kKeyStatusOutputNotAllowed,
|
||||
@@ -270,9 +291,6 @@ enum CdmLicenseType {
|
||||
kLicenseTypeOffline,
|
||||
kLicenseTypeStreaming,
|
||||
kLicenseTypeRelease,
|
||||
// If the original request was saved to make a service certificate request,
|
||||
// use Deferred for the license type in the subsequent request.
|
||||
kLicenseTypeDeferred,
|
||||
// Like Streaming, but stricter. Does not permit storage of any kind.
|
||||
// Named after the 'temporary' session type in EME, which has this behavior.
|
||||
kLicenseTypeTemporary,
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
#include "cdm_engine.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <list>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "cdm_session.h"
|
||||
#include "cdm_session_map.h"
|
||||
#include "clock.h"
|
||||
#include "device_files.h"
|
||||
#include "file_store.h"
|
||||
@@ -27,6 +29,9 @@ const size_t kUsageReportsPerRequest = 1;
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
using video_widevine::SignedMessage;
|
||||
using video_widevine::LicenseError;
|
||||
|
||||
class UsagePropertySet : public CdmClientPropertySet {
|
||||
public:
|
||||
UsagePropertySet() {}
|
||||
@@ -70,20 +75,77 @@ CdmEngine::CdmEngine(FileSystem* file_system, const std::string& spoid)
|
||||
}
|
||||
}
|
||||
|
||||
CdmEngine::~CdmEngine() {
|
||||
AutoLock lock(session_list_lock_);
|
||||
CdmSessionMap::iterator i(sessions_.begin());
|
||||
for (; i != sessions_.end(); ++i) {
|
||||
delete i->second;
|
||||
}
|
||||
sessions_.clear();
|
||||
}
|
||||
CdmEngine::~CdmEngine() {}
|
||||
|
||||
CdmResponseType CdmEngine::SetServiceCertificate(
|
||||
const std::string& certificate) {
|
||||
return service_certificate_.Init(certificate);
|
||||
}
|
||||
|
||||
bool CdmEngine::HasServiceCertificate() {
|
||||
return service_certificate_.has_certificate();
|
||||
}
|
||||
|
||||
bool CdmEngine::GetServiceCertificateRequest(CdmKeyMessage* request) {
|
||||
if (!request) {
|
||||
LOGE("ServiceCertificate::PrepareRequest: no request parameter provided");
|
||||
return false;
|
||||
}
|
||||
SignedMessage message;
|
||||
message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST);
|
||||
message.SerializeToString(request);
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::ParseServiceCertificateResponse(
|
||||
const std::string& response, std::string* certificate) {
|
||||
if (response.empty()) {
|
||||
LOGE("CdmEngine::ParseServiceCertificateResponse: empty response");
|
||||
return EMPTY_RESPONSE_ERROR_1;
|
||||
}
|
||||
if (!certificate) {
|
||||
LOGE("CdmEngine::ParseServiceCertificateResponse: null return parameter");
|
||||
return INVALID_PARAMETERS_ENG_19;
|
||||
}
|
||||
|
||||
SignedMessage signed_response;
|
||||
if (!signed_response.ParseFromString(response)) {
|
||||
LOGE(
|
||||
"CdmEngine::ParseServiceCertificateResponse: cannot parse response");
|
||||
return PARSE_RESPONSE_ERROR_1;
|
||||
}
|
||||
if (signed_response.type() == SignedMessage::SERVICE_CERTIFICATE) {
|
||||
|
||||
CdmResponseType status;
|
||||
status = service_certificate_.Init(signed_response.msg());
|
||||
if (status != NO_ERROR) {
|
||||
LOGE(
|
||||
"CdmEngine::ParseServiceCertificateResponse: certificate handling "
|
||||
"failure, status=%d", status);
|
||||
return PARSE_SERVICE_CERTIFICATE_ERROR;
|
||||
}
|
||||
certificate->assign(signed_response.msg());
|
||||
|
||||
} else if (signed_response.type() == SignedMessage::ERROR_RESPONSE) {
|
||||
|
||||
LicenseError license_error;
|
||||
if (!license_error.ParseFromString(signed_response.msg())) {
|
||||
LOGE("CdmEngine::ParseServiceCertificateResponse: cannot parse "
|
||||
"license error");
|
||||
return PARSE_RESPONSE_ERROR_2;
|
||||
}
|
||||
LOGE("CdmEngine::ParseServiceCertificateResponse: server returned error:"
|
||||
"error code = %d", license_error.error_code());
|
||||
return PARSE_RESPONSE_ERROR_3;
|
||||
} else {
|
||||
LOGE(
|
||||
"CdmEngine::ParseServiceCertificateResponse: response (%d) is "
|
||||
"wrong type", signed_response.type());
|
||||
return PARSE_RESPONSE_ERROR_4;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::OpenSession(
|
||||
const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
|
||||
const CdmSessionId& forced_session_id, WvCdmEventListener* event_listener) {
|
||||
@@ -114,7 +176,7 @@ CdmResponseType CdmEngine::OpenSession(
|
||||
}
|
||||
|
||||
if (forced_session_id) {
|
||||
if (sessions_.find(*forced_session_id) != sessions_.end()) {
|
||||
if (session_map_.Exists(*forced_session_id)) {
|
||||
return DUPLICATE_SESSION_ID_SPECIFIED;
|
||||
}
|
||||
}
|
||||
@@ -138,8 +200,7 @@ CdmResponseType CdmEngine::OpenSession(
|
||||
}
|
||||
CdmSessionId id = new_session->session_id();
|
||||
|
||||
AutoLock lock(session_list_lock_);
|
||||
sessions_[id] = new_session.release();
|
||||
session_map_.Add(id, new_session.release());
|
||||
if (session_id) *session_id = id;
|
||||
return NO_ERROR;
|
||||
}
|
||||
@@ -180,15 +241,10 @@ CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
|
||||
CdmResponseType CdmEngine::CloseSession(const CdmSessionId& session_id) {
|
||||
LOGI("CdmEngine::CloseSession");
|
||||
AutoLock lock(session_list_lock_);
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
if (!session_map_.CloseSession(session_id)) {
|
||||
LOGE("CdmEngine::CloseSession: session not found = %s", session_id.c_str());
|
||||
return SESSION_NOT_FOUND_1;
|
||||
}
|
||||
CdmSession* session = iter->second;
|
||||
sessions_.erase(session_id);
|
||||
delete session;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -218,9 +274,7 @@ CdmResponseType CdmEngine::CloseKeySetSession(const CdmKeySetId& key_set_id) {
|
||||
}
|
||||
|
||||
bool CdmEngine::IsOpenSession(const CdmSessionId& session_id) {
|
||||
AutoLock lock(session_list_lock_);
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
return iter != sessions_.end();
|
||||
return session_map_.Exists(session_id);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
@@ -258,8 +312,8 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
id = iter->second.first;
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(id, session)) {
|
||||
LOGE("CdmEngine::GenerateKeyRequest: session_id not found = %s",
|
||||
id.c_str());
|
||||
return SESSION_NOT_FOUND_2;
|
||||
@@ -273,8 +327,8 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
key_request->message.clear();
|
||||
|
||||
if (license_type == kLicenseTypeRelease &&
|
||||
!iter->second->license_received()) {
|
||||
sts = iter->second->RestoreOfflineSession(key_set_id, kLicenseTypeRelease);
|
||||
!session->license_received()) {
|
||||
sts = session->RestoreOfflineSession(key_set_id, kLicenseTypeRelease);
|
||||
if (sts != KEY_ADDED) {
|
||||
LOGE("CdmEngine::GenerateKeyRequest: key release restoration failed,"
|
||||
"sts = %d", static_cast<int>(sts));
|
||||
@@ -282,13 +336,13 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
}
|
||||
}
|
||||
|
||||
sts = iter->second->GenerateKeyRequest(
|
||||
init_data, license_type, app_parameters, key_request);
|
||||
sts = session->GenerateKeyRequest(init_data, license_type, app_parameters,
|
||||
key_request);
|
||||
|
||||
if (KEY_MESSAGE != sts) {
|
||||
if (sts == NEED_PROVISIONING) {
|
||||
cert_provisioning_requested_security_level_ =
|
||||
iter->second->GetRequestedSecurityLevel();
|
||||
session->GetRequestedSecurityLevel();
|
||||
}
|
||||
LOGE("CdmEngine::GenerateKeyRequest: key request generation failed, "
|
||||
"sts = %d", static_cast<int>(sts));
|
||||
@@ -331,9 +385,8 @@ CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id,
|
||||
id = iter->second.first;
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(id);
|
||||
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(id, session)) {
|
||||
LOGE("CdmEngine::AddKey: session id not found = %s", id.c_str());
|
||||
return SESSION_NOT_FOUND_3;
|
||||
}
|
||||
@@ -343,9 +396,9 @@ CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id,
|
||||
return EMPTY_KEY_DATA_1;
|
||||
}
|
||||
|
||||
CdmResponseType sts = iter->second->AddKey(key_data);
|
||||
CdmResponseType sts = session->AddKey(key_data);
|
||||
if (key_set_id) {
|
||||
*key_set_id = iter->second->key_set_id();
|
||||
*key_set_id = session->key_set_id();
|
||||
}
|
||||
|
||||
switch (sts) {
|
||||
@@ -371,18 +424,18 @@ CdmResponseType CdmEngine::RestoreKey(const CdmSessionId& session_id,
|
||||
return EMPTY_KEYSET_ID_ENG_4;
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::RestoreKey: session_id not found = %s ",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_4;
|
||||
}
|
||||
|
||||
CdmResponseType sts =
|
||||
iter->second->RestoreOfflineSession(key_set_id, kLicenseTypeOffline);
|
||||
session->RestoreOfflineSession(key_set_id, kLicenseTypeOffline);
|
||||
if (sts == NEED_PROVISIONING) {
|
||||
cert_provisioning_requested_security_level_ =
|
||||
iter->second->GetRequestedSecurityLevel();
|
||||
session->GetRequestedSecurityLevel();
|
||||
}
|
||||
if (sts != KEY_ADDED && sts != GET_RELEASED_LICENSE_ERROR) {
|
||||
LOGE("CdmEngine::RestoreKey: restore offline session failed = %d", sts);
|
||||
@@ -393,14 +446,14 @@ CdmResponseType CdmEngine::RestoreKey(const CdmSessionId& session_id,
|
||||
CdmResponseType CdmEngine::RemoveKeys(const CdmSessionId& session_id) {
|
||||
LOGI("CdmEngine::RemoveKeys");
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::RemoveKeys: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_5;
|
||||
}
|
||||
|
||||
iter->second->ReleaseCrypto();
|
||||
session->ReleaseCrypto();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -408,8 +461,8 @@ CdmResponseType CdmEngine::GenerateRenewalRequest(
|
||||
const CdmSessionId& session_id, CdmKeyRequest* key_request) {
|
||||
LOGI("CdmEngine::GenerateRenewalRequest");
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_6;
|
||||
@@ -422,7 +475,7 @@ CdmResponseType CdmEngine::GenerateRenewalRequest(
|
||||
|
||||
key_request->message.clear();
|
||||
|
||||
CdmResponseType sts = iter->second->GenerateRenewalRequest(key_request);
|
||||
CdmResponseType sts = session->GenerateRenewalRequest(key_request);
|
||||
|
||||
if (KEY_MESSAGE != sts) {
|
||||
LOGE("CdmEngine::GenerateRenewalRequest: key request gen. failed, sts=%d",
|
||||
@@ -437,8 +490,8 @@ CdmResponseType CdmEngine::RenewKey(const CdmSessionId& session_id,
|
||||
const CdmKeyResponse& key_data) {
|
||||
LOGI("CdmEngine::RenewKey");
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::RenewKey: session_id not found = %s", session_id.c_str());
|
||||
return SESSION_NOT_FOUND_7;
|
||||
}
|
||||
@@ -448,7 +501,7 @@ CdmResponseType CdmEngine::RenewKey(const CdmSessionId& session_id,
|
||||
return EMPTY_KEY_DATA_2;
|
||||
}
|
||||
|
||||
CdmResponseType sts = iter->second->RenewKey(key_data);
|
||||
CdmResponseType sts = session->RenewKey(key_data);
|
||||
if (KEY_ADDED != sts) {
|
||||
LOGE("CdmEngine::RenewKey: keys not added, sts=%d", static_cast<int>(sts));
|
||||
return sts;
|
||||
@@ -473,8 +526,8 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
}
|
||||
|
||||
if (query_token == QUERY_KEY_SECURITY_LEVEL) {
|
||||
CdmSecurityLevel security_level = crypto_session.GetSecurityLevel();
|
||||
switch (security_level) {
|
||||
CdmSecurityLevel level = crypto_session.GetSecurityLevel();
|
||||
switch (level) {
|
||||
case kSecurityLevelL1:
|
||||
*query_response = QUERY_VALUE_SECURITY_LEVEL_L1;
|
||||
break;
|
||||
@@ -489,8 +542,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
*query_response = QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
LOGW("CdmEngine::QueryStatus: Unknown security level: %d",
|
||||
security_level);
|
||||
LOGW("CdmEngine::QueryStatus: Unknown security level: %d", level);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
} else if (query_token == QUERY_KEY_DEVICE_ID) {
|
||||
@@ -581,47 +633,47 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
CdmResponseType CdmEngine::QuerySessionStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* query_response) {
|
||||
LOGI("CdmEngine::QuerySessionStatus");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::QuerySessionStatus: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_8;
|
||||
}
|
||||
return iter->second->QueryStatus(query_response);
|
||||
return session->QueryStatus(query_response);
|
||||
}
|
||||
|
||||
bool CdmEngine::IsReleaseSession(const CdmSessionId& session_id) {
|
||||
LOGI("CdmEngine::IsReleaseSession");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::IsReleaseSession: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return false;
|
||||
}
|
||||
return iter->second->is_release();
|
||||
return session->is_release();
|
||||
}
|
||||
|
||||
bool CdmEngine::IsOfflineSession(const CdmSessionId& session_id) {
|
||||
LOGI("CdmEngine::IsOfflineSession");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::IsOfflineSession: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return false;
|
||||
}
|
||||
return iter->second->is_offline();
|
||||
return session->is_offline();
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryKeyStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* query_response) {
|
||||
LOGI("CdmEngine::QueryKeyStatus");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::QueryKeyStatus: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_9;
|
||||
}
|
||||
return iter->second->QueryKeyStatus(query_response);
|
||||
return session->QueryKeyStatus(query_response);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryKeyAllowedUsage(const CdmSessionId& session_id,
|
||||
@@ -632,13 +684,13 @@ CdmResponseType CdmEngine::QueryKeyAllowedUsage(const CdmSessionId& session_id,
|
||||
LOGE("CdmEngine::QueryKeyAllowedUsage: no response destination");
|
||||
return INVALID_PARAMETERS_ENG_12;
|
||||
}
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::QueryKeyAllowedUsage: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_12;
|
||||
}
|
||||
return iter->second->QueryKeyAllowedUsage(key_id, key_usage);
|
||||
return session->QueryKeyAllowedUsage(key_id, key_usage);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryKeyAllowedUsage(const std::string& key_id,
|
||||
@@ -652,10 +704,16 @@ CdmResponseType CdmEngine::QueryKeyAllowedUsage(const std::string& key_id,
|
||||
return INVALID_PARAMETERS_ENG_7;
|
||||
}
|
||||
key_usage->Clear();
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
session_sts = iter->second->QueryKeyAllowedUsage(key_id,
|
||||
&found_in_this_session);
|
||||
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
for (CdmSessionList::iterator iter = sessions.begin();
|
||||
iter != sessions.end(); ++iter) {
|
||||
if ((*iter)->IsClosed()) {
|
||||
continue;
|
||||
}
|
||||
session_sts = (*iter)->QueryKeyAllowedUsage(key_id, &found_in_this_session);
|
||||
if (session_sts == NO_ERROR) {
|
||||
if (found) {
|
||||
// Found another key. If usage settings do not match, fail.
|
||||
@@ -680,13 +738,13 @@ CdmResponseType CdmEngine::QueryKeyAllowedUsage(const std::string& key_id,
|
||||
CdmResponseType CdmEngine::QueryOemCryptoSessionId(
|
||||
const CdmSessionId& session_id, CdmQueryMap* query_response) {
|
||||
LOGI("CdmEngine::QueryOemCryptoSessionId");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::QueryOemCryptoSessionId: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_10;
|
||||
}
|
||||
return iter->second->QueryOemCryptoSessionId(query_response);
|
||||
return session->QueryOemCryptoSessionId(query_response);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -835,19 +893,73 @@ CdmResponseType CdmEngine::ListStoredLicenses(
|
||||
CdmSecurityLevel security_level, std::vector<std::string>* key_set_ids) {
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!key_set_ids) {
|
||||
LOGE("CdmEngine::QueryStoredLicenses: no response destination");
|
||||
LOGE("CdmEngine::ListStoredLicenses: no response destination");
|
||||
return INVALID_PARAMETERS_ENG_17;
|
||||
}
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::ListStoredLicenses: unable to initialize device files");
|
||||
return STORE_LICENSE_ERROR_3;
|
||||
return LIST_LICENSE_ERROR_1;
|
||||
}
|
||||
if (!handle.ListLicenses(key_set_ids)) {
|
||||
return UNKNOWN_ERROR;
|
||||
LOGE("CdmEngine::ListStoredLicenses: ListLicenses call failed");
|
||||
return LIST_LICENSE_ERROR_2;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::ListUsageRecords(const std::string& app_id,
|
||||
CdmSecurityLevel security_level,
|
||||
std::vector<std::string>* ksids) {
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!ksids) {
|
||||
LOGE("CdmEngine::ListUsageRecords: no response destination");
|
||||
return INVALID_PARAMETERS_ENG_18;
|
||||
}
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::ListUsageRecords: unable to initialize device files");
|
||||
return LIST_USAGE_ERROR_1;
|
||||
}
|
||||
if (!handle.ListUsageRecords(app_id, ksids)) {
|
||||
LOGE("CdmEngine::ListUsageRecords: ListUsageRecords call failed");
|
||||
return LIST_USAGE_ERROR_2;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::DeleteUsageRecord(const std::string& app_id,
|
||||
CdmSecurityLevel security_level,
|
||||
const std::string& key_set_id) {
|
||||
std::string provider_session_token;
|
||||
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::DeleteUsageRecord: unable to initialize device files");
|
||||
return DELETE_USAGE_ERROR_1;
|
||||
}
|
||||
if (!handle.GetProviderToken(app_id, key_set_id, &provider_session_token)) {
|
||||
LOGE("CdmEngine::DeleteUsageRecord: GetProviderToken failed");
|
||||
return DELETE_USAGE_ERROR_2;
|
||||
}
|
||||
|
||||
// Got provider token. Remove from OEMCrypto.
|
||||
scoped_ptr<CryptoSession> crypto_session(new CryptoSession());
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (status == NO_ERROR) {
|
||||
status = crypto_session->DeleteUsageInformation(provider_session_token);
|
||||
}
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("CdmEngine::DeleteUsageRecord: OEMCrypto failure");
|
||||
}
|
||||
|
||||
// Remove from file system.
|
||||
if (!handle.DeleteUsageInfo(app_id, provider_session_token)) {
|
||||
LOGE("CdmEngine::DeleteUsageRecord: file system failure");
|
||||
return DELETE_USAGE_ERROR_3;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
const CdmSecureStopId& ssid,
|
||||
CdmUsageInfo* usage_info) {
|
||||
@@ -915,6 +1027,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
usage_info->clear();
|
||||
return status;
|
||||
}
|
||||
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
|
||||
@@ -930,7 +1043,9 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
do {
|
||||
status = GetUsageInfo(app_id, security_level, usage_info);
|
||||
|
||||
if (KEY_MESSAGE == status && !usage_info->empty()) return status;
|
||||
if (KEY_MESSAGE == status && !usage_info->empty()) {
|
||||
return status;
|
||||
}
|
||||
} while (KEY_CANCELED == status);
|
||||
|
||||
security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3;
|
||||
@@ -1015,6 +1130,37 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::ReleaseAllUsageInfo(
|
||||
const std::string& app_id, CdmSecurityLevel security_level) {
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::ReleaseAllUsageInfo: unable to initialize device files");
|
||||
return RELEASE_ALL_USAGE_INFO_ERROR_3;
|
||||
}
|
||||
std::vector<std::string> provider_session_tokens;
|
||||
if (!handle.DeleteAllUsageInfoForApp(app_id, &provider_session_tokens)) {
|
||||
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to delete usage records");
|
||||
return RELEASE_ALL_USAGE_INFO_ERROR_4;
|
||||
}
|
||||
|
||||
if (provider_session_tokens.size() == 0UL) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Got at least one provider token. Remove from OEMCrypto.
|
||||
scoped_ptr<CryptoSession> crypto_session(new CryptoSession());
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
security_level == kSecurityLevelL3 ? kLevel3 : kLevelDefault);
|
||||
if (status == NO_ERROR) {
|
||||
status = crypto_session->
|
||||
DeleteMultipleUsageInformation(provider_session_tokens);
|
||||
}
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("CdmEngine::DeleteUsageRecord: CryptoSession failure");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
|
||||
if (NULL == usage_property_set_.get()) {
|
||||
usage_property_set_.reset(new UsagePropertySet());
|
||||
@@ -1081,8 +1227,8 @@ CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
return EMPTY_KEYSET_ID_ENG_5;
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator iter = sessions_.find(key_set_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(key_set_id, session)) {
|
||||
LOGE("CdmEngine::LoadUsageSession: session_id not found = %s ",
|
||||
key_set_id.c_str());
|
||||
return SESSION_NOT_FOUND_11;
|
||||
@@ -1094,13 +1240,13 @@ CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
}
|
||||
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(iter->second->GetSecurityLevel())) {
|
||||
if (!handle.Init(session->GetSecurityLevel())) {
|
||||
LOGE("CdmEngine::LoadUsageSession: unable to initialize device files");
|
||||
return LOAD_USAGE_INFO_FILE_ERROR;
|
||||
}
|
||||
|
||||
std::string app_id;
|
||||
iter->second->GetApplicationId(&app_id);
|
||||
session->GetApplicationId(&app_id);
|
||||
|
||||
CdmKeyMessage key_message;
|
||||
CdmKeyResponse key_response;
|
||||
@@ -1110,22 +1256,22 @@ CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
return LOAD_USAGE_INFO_MISSING;
|
||||
}
|
||||
|
||||
CdmResponseType status =
|
||||
iter->second->RestoreUsageSession(key_message, key_response);
|
||||
CdmResponseType status = session->RestoreUsageSession(key_message,
|
||||
key_response);
|
||||
if (KEY_ADDED != status) {
|
||||
LOGE("CdmEngine::LoadUsageSession: usage session error %ld", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmKeyRequest request;
|
||||
status = iter->second->GenerateReleaseRequest(&request);
|
||||
status = session->GenerateReleaseRequest(&request);
|
||||
*release_message = request.message;
|
||||
|
||||
switch (status) {
|
||||
case KEY_MESSAGE:
|
||||
break;
|
||||
case KEY_CANCELED: // usage information not present in
|
||||
iter->second->DeleteLicense(); // OEMCrypto, delete and try again
|
||||
session->DeleteLicense(); // OEMCrypto, delete and try again
|
||||
break;
|
||||
default:
|
||||
LOGE("CdmEngine::LoadUsageSession: generate release request error: %d",
|
||||
@@ -1161,45 +1307,55 @@ CdmResponseType CdmEngine::Decrypt(const CdmSessionId& session_id,
|
||||
// else we must be level 1 direct and we don't need to return a buffer.
|
||||
}
|
||||
|
||||
CdmSessionMap::iterator session_iter = sessions_.end();
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (session_id.empty()) {
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
// Loop through the sessions to find the session containing the key_id
|
||||
// with the longest remaining license validity.
|
||||
int64_t seconds_remaining = 0;
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
if (iter->second->IsKeyLoaded(*parameters.key_id)) {
|
||||
int64_t duration = iter->second->GetDurationRemaining();
|
||||
for (CdmSessionList::iterator iter = sessions.begin();
|
||||
iter != sessions.end(); ++iter) {
|
||||
if ((*iter)->IsClosed()) {
|
||||
continue;
|
||||
}
|
||||
if ((*iter)->IsKeyLoaded(*parameters.key_id)) {
|
||||
int64_t duration = (*iter)->GetDurationRemaining();
|
||||
if (duration > seconds_remaining) {
|
||||
session_iter = iter;
|
||||
session = *iter;
|
||||
seconds_remaining = duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
session_iter = sessions_.find(session_id);
|
||||
session_map_.FindSession(session_id, session);
|
||||
}
|
||||
if (session_iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::Decrypt: session not found: id=%s, id size=%d",
|
||||
session_id.c_str(), session_id.size());
|
||||
|
||||
if (session.get() == NULL) {
|
||||
if (session_id.empty()) {
|
||||
LOGE("CdmEngine::Decrypt: session not found: Empty session ID");
|
||||
} else {
|
||||
LOGE("CdmEngine::Decrypt: session not found: id=%s, id size=%d",
|
||||
session_id.c_str(), session_id.size());
|
||||
}
|
||||
return SESSION_NOT_FOUND_FOR_DECRYPT;
|
||||
}
|
||||
|
||||
return session_iter->second->Decrypt(parameters);
|
||||
return session->Decrypt(parameters);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GenericEncrypt(
|
||||
const std::string& session_id, const std::string& in_buffer,
|
||||
const std::string& key_id, const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm, std::string* out_buffer) {
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::GenericEncrypt: session_id not found = %s ",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_13;
|
||||
}
|
||||
return iter->second->GenericEncrypt(in_buffer, key_id, iv, algorithm,
|
||||
out_buffer);
|
||||
return session->GenericEncrypt(in_buffer, key_id, iv, algorithm, out_buffer);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GenericDecrypt(
|
||||
@@ -1207,46 +1363,51 @@ CdmResponseType CdmEngine::GenericDecrypt(
|
||||
const std::string& key_id, const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer) {
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::GenericDecrypt: session_id not found = %s ",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_14;
|
||||
}
|
||||
return iter->second->GenericDecrypt(in_buffer, key_id, iv, algorithm,
|
||||
out_buffer);
|
||||
return session->GenericDecrypt(in_buffer, key_id, iv, algorithm, out_buffer);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GenericSign(
|
||||
const std::string& session_id, const std::string& message,
|
||||
const std::string& key_id, CdmSigningAlgorithm algorithm,
|
||||
std::string* signature) {
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::GenericSign: session_id not found = %s ",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_15;
|
||||
}
|
||||
return iter->second->GenericSign(message, key_id, algorithm, signature);
|
||||
return session->GenericSign(message, key_id, algorithm, signature);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GenericVerify(
|
||||
const std::string& session_id, const std::string& message,
|
||||
const std::string& key_id, CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature) {
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!session_map_.FindSession(session_id, session)) {
|
||||
LOGE("CdmEngine::GenericVerify: session_id not found = %s ",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_16;
|
||||
}
|
||||
return iter->second->GenericVerify(message, key_id, algorithm, signature);
|
||||
return session->GenericVerify(message, key_id, algorithm, signature);
|
||||
}
|
||||
|
||||
// TODO(gmorgan) Used? Delete if unused.
|
||||
bool CdmEngine::IsKeyLoaded(const KeyId& key_id) {
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
if (iter->second->IsKeyLoaded(key_id)) {
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
for (CdmSessionList::iterator iter = sessions.begin();
|
||||
iter != sessions.end(); ++iter) {
|
||||
if ((*iter)->IsClosed()) {
|
||||
continue;
|
||||
}
|
||||
if ((*iter)->IsKeyLoaded(key_id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1260,18 +1421,23 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
|
||||
|
||||
CdmSessionMap::iterator session_iter = sessions_.end();
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
CdmSessionList::iterator session_iter = sessions.end();
|
||||
|
||||
int64_t seconds_remaining = 0;
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
CdmSessionId local_session_id = iter->second->session_id();
|
||||
if (Properties::GetSessionSharingId(local_session_id) ==
|
||||
session_sharing_id) {
|
||||
if (iter->second->IsKeyLoaded(key_id)) {
|
||||
int64_t duration = iter->second->GetDurationRemaining();
|
||||
for (CdmSessionList::iterator iter = sessions.begin();
|
||||
iter != sessions.end(); ++iter) {
|
||||
if ((*iter)->IsClosed()) {
|
||||
continue;
|
||||
}
|
||||
CdmSessionId id = (*iter)->session_id();
|
||||
if (Properties::GetSessionSharingId(id) == session_sharing_id) {
|
||||
if ((*iter)->IsKeyLoaded(key_id)) {
|
||||
int64_t duration = (*iter)->GetDurationRemaining();
|
||||
if (duration > seconds_remaining) {
|
||||
session_iter = iter;
|
||||
seconds_remaining = duration;
|
||||
@@ -1280,8 +1446,8 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
|
||||
}
|
||||
}
|
||||
|
||||
if (session_iter != sessions_.end()) {
|
||||
*session_id = session_iter->second->session_id();
|
||||
if (session_iter != sessions.end()) {
|
||||
*session_id = (*session_iter)->session_id();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1289,9 +1455,9 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
|
||||
|
||||
bool CdmEngine::NotifyResolution(const CdmSessionId& session_id, uint32_t width,
|
||||
uint32_t height) {
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter != sessions_.end()) {
|
||||
iter->second->NotifyResolution(width, height);
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (session_map_.FindSession(session_id, session)) {
|
||||
session->NotifyResolution(width, height);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1304,8 +1470,11 @@ bool CdmEngine::ValidateKeySystem(const CdmKeySystem& key_system) {
|
||||
void CdmEngine::OnTimerEvent() {
|
||||
Clock clock;
|
||||
uint64_t current_time = clock.GetCurrentTime();
|
||||
bool usage_update_period_expired = false;
|
||||
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
bool usage_update_period_expired = false;
|
||||
if (current_time - last_usage_information_update_time_ >
|
||||
kUpdateUsageInformationPeriod) {
|
||||
usage_update_period_expired = true;
|
||||
@@ -1315,27 +1484,35 @@ void CdmEngine::OnTimerEvent() {
|
||||
bool is_initial_usage_update = false;
|
||||
bool is_usage_update_needed = false;
|
||||
|
||||
AutoLock lock(session_list_lock_);
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
while (!sessions.empty()) {
|
||||
is_initial_usage_update =
|
||||
is_initial_usage_update || iter->second->is_initial_usage_update();
|
||||
is_initial_usage_update || sessions.front()->is_initial_usage_update();
|
||||
is_usage_update_needed =
|
||||
is_usage_update_needed || iter->second->is_usage_update_needed();
|
||||
is_usage_update_needed || sessions.front()->is_usage_update_needed();
|
||||
|
||||
iter->second->OnTimerEvent(usage_update_period_expired);
|
||||
if (!sessions.front()->IsClosed()) {
|
||||
sessions.front()->OnTimerEvent(usage_update_period_expired);
|
||||
}
|
||||
sessions.pop_front();
|
||||
}
|
||||
|
||||
if (is_usage_update_needed &&
|
||||
(usage_update_period_expired || is_initial_usage_update)) {
|
||||
bool has_usage_been_updated = false;
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
iter->second->reset_usage_flags();
|
||||
|
||||
// Session list may have changed. Rebuild.
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
for (CdmSessionList::iterator iter = sessions.begin();
|
||||
iter != sessions.end(); ++iter) {
|
||||
if ((*iter)->IsClosed()) {
|
||||
continue;
|
||||
}
|
||||
(*iter)->reset_usage_flags();
|
||||
if (!has_usage_been_updated) {
|
||||
// usage is updated for all sessions so this needs to be
|
||||
// called only once per update usage information period
|
||||
CdmResponseType status = iter->second->UpdateUsageInformation();
|
||||
CdmResponseType status = (*iter)->UpdateUsageInformation();
|
||||
if (NO_ERROR != status) {
|
||||
LOGW("Update usage information failed: %d", status);
|
||||
} else {
|
||||
@@ -1344,15 +1521,18 @@ void CdmEngine::OnTimerEvent() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseExpiredReleaseSessions();
|
||||
}
|
||||
|
||||
void CdmEngine::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) {
|
||||
AutoLock lock(session_list_lock_);
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
iter->second->OnKeyReleaseEvent(key_set_id);
|
||||
CdmSessionList sessions;
|
||||
session_map_.GetSessionList(sessions);
|
||||
|
||||
while (!sessions.empty()) {
|
||||
if (!sessions.front()->IsClosed()) {
|
||||
sessions.front()->OnKeyReleaseEvent(key_set_id);
|
||||
}
|
||||
sessions.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1415,12 +1595,12 @@ void CdmEngine::DeleteAllUsageReportsUponFactoryReset() {
|
||||
status = crypto_session->DeleteAllUsageReports();
|
||||
if (NO_ERROR != status) {
|
||||
LOGW(
|
||||
"CdmEngine::GetProvisioningRequest: "
|
||||
"CdmEngine::DeleteAllUsageReportsUponFactoryReset: "
|
||||
"Fails to delete usage reports: %d", status);
|
||||
}
|
||||
} else {
|
||||
LOGW(
|
||||
"CdmEngine::GetProvisioningRequest: "
|
||||
"CdmEngine::DeleteAllUsageReportsUponFactoryReset: "
|
||||
"Fails to open crypto session: error=%d.\n"
|
||||
"Usage reports are not removed after factory reset.", status);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace wvcdm {
|
||||
|
||||
CdmSession::CdmSession(FileSystem* file_system) :
|
||||
initialized_(false),
|
||||
closed_(false),
|
||||
crypto_session_(new CryptoSession),
|
||||
file_handle_(new DeviceFiles(file_system)),
|
||||
license_received_(false),
|
||||
@@ -101,9 +102,8 @@ CdmResponseType CdmSession::Init(
|
||||
// License server client ID token is a stored certificate. Stage it or
|
||||
// indicate that provisioning is needed. Get token from stored certificate
|
||||
std::string wrapped_key;
|
||||
uint32_t system_id;
|
||||
if (!file_handle_->RetrieveCertificate(&client_token, &wrapped_key,
|
||||
&serial_number, &system_id) ||
|
||||
&serial_number, nullptr) ||
|
||||
!crypto_session_->LoadCertificatePrivateKey(wrapped_key)) {
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
@@ -243,26 +243,6 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
case kLicenseTypeRelease:
|
||||
is_release_ = true;
|
||||
break;
|
||||
case kLicenseTypeDeferred:
|
||||
// If you're going to pass Deferred, you must have empty init data in
|
||||
// this call and stored init data from the previous call.
|
||||
if (!init_data.IsEmpty() || !license_parser_->HasInitData()) {
|
||||
return INVALID_LICENSE_TYPE;
|
||||
}
|
||||
// The arguments check out.
|
||||
// The is_release_ and is_offline_ flags were already set last time based
|
||||
// on the original license type. Do not change them, and use them to
|
||||
// re-derive the original license type.
|
||||
if (is_release_) {
|
||||
license_type = kLicenseTypeRelease;
|
||||
} else if (is_offline_) {
|
||||
license_type = kLicenseTypeOffline;
|
||||
} else if (is_temporary_) {
|
||||
license_type = kLicenseTypeTemporary;
|
||||
} else {
|
||||
license_type = kLicenseTypeStreaming;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOGE("CdmSession::GenerateKeyRequest: unrecognized license type: %ld",
|
||||
license_type);
|
||||
@@ -276,16 +256,14 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
} else {
|
||||
key_request->type = kKeyRequestTypeInitial;
|
||||
|
||||
if (!license_parser_->HasInitData()) {
|
||||
if (!init_data.is_supported()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return UNSUPPORTED_INIT_DATA;
|
||||
}
|
||||
if (init_data.IsEmpty()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
return INIT_DATA_NOT_FOUND;
|
||||
}
|
||||
if (!init_data.is_supported()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return UNSUPPORTED_INIT_DATA;
|
||||
}
|
||||
if (init_data.IsEmpty()) {
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
return INIT_DATA_NOT_FOUND;
|
||||
}
|
||||
if (is_offline_ && key_set_id_.empty()) {
|
||||
LOGE("CdmSession::GenerateKeyRequest: Unable to generate key set ID");
|
||||
@@ -297,16 +275,14 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
init_data, license_type,
|
||||
app_parameters, &key_request->message,
|
||||
&key_request->url);
|
||||
|
||||
if (KEY_MESSAGE != status) return status;
|
||||
if (status != KEY_MESSAGE)
|
||||
return status;
|
||||
|
||||
key_request_ = key_request->message;
|
||||
if (is_offline_) {
|
||||
offline_init_data_ = init_data.data();
|
||||
offline_release_server_url_ = key_request->url;
|
||||
|
||||
}
|
||||
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
}
|
||||
@@ -336,6 +312,10 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
|
||||
license_received_ = true;
|
||||
key_response_ = key_response;
|
||||
|
||||
LOGV("AddKey: provider_session_token (size=%d) =%s",
|
||||
license_parser_->provider_session_token().size(),
|
||||
license_parser_->provider_session_token().c_str());
|
||||
|
||||
if (is_offline_ || !license_parser_->provider_session_token().empty()) {
|
||||
sts = StoreLicense();
|
||||
if (sts != NO_ERROR) return sts;
|
||||
@@ -423,6 +403,10 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
// is updated, so we treat this Decrypt call as invalid.
|
||||
if (params.is_encrypted &&
|
||||
!policy_engine_->CanDecryptContent(*params.key_id)) {
|
||||
if (policy_engine_->GetKeyStatus(*params.key_id) ==
|
||||
kKeyStatusOutputNotAllowed) {
|
||||
return INSUFFICIENT_OUTPUT_PROTECTION;
|
||||
}
|
||||
return policy_engine_->IsLicenseForFuture() ? DECRYPT_NOT_READY : NEED_KEY;
|
||||
}
|
||||
|
||||
|
||||
71
core/src/cdm_session_map.cpp
Normal file
71
core/src/cdm_session_map.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "cdm_session_map.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "cdm_session.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
CdmSessionMap::~CdmSessionMap() {
|
||||
AutoLock lock(lock_);
|
||||
for (CdmIdToSessionMap::iterator i = sessions_.begin();
|
||||
i != sessions_.end(); ++i) {
|
||||
i->second->Close();
|
||||
i->second.reset();
|
||||
}
|
||||
sessions_.clear();
|
||||
}
|
||||
|
||||
void CdmSessionMap::Add(const std::string& id, CdmSession* session) {
|
||||
AutoLock lock(lock_);
|
||||
sessions_[id].reset(session);
|
||||
}
|
||||
|
||||
bool CdmSessionMap::CloseSession(const std::string& id) {
|
||||
AutoLock lock(lock_);
|
||||
std::shared_ptr<CdmSession> session;
|
||||
if (!FindSessionNoLock(id, session)) {
|
||||
return false;
|
||||
}
|
||||
session->Close();
|
||||
sessions_.erase(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CdmSessionMap::Exists(const std::string& id) {
|
||||
AutoLock lock(lock_);
|
||||
return sessions_.find(id) != sessions_.end();
|
||||
}
|
||||
|
||||
bool CdmSessionMap::FindSession(const CdmSessionId& id,
|
||||
std::shared_ptr<CdmSession>& session) {
|
||||
AutoLock lock(lock_);
|
||||
return FindSessionNoLock(id, session);
|
||||
}
|
||||
|
||||
bool CdmSessionMap::FindSessionNoLock(const CdmSessionId& session_id,
|
||||
std::shared_ptr<CdmSession>& session) {
|
||||
CdmIdToSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
return false;
|
||||
}
|
||||
session = iter->second;
|
||||
assert(session.get() != NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef std::list<std::shared_ptr<CdmSession> > CdmSessionList;
|
||||
|
||||
void CdmSessionMap::GetSessionList(CdmSessionList& sessions) {
|
||||
sessions.clear();
|
||||
AutoLock lock(lock_);
|
||||
for (CdmIdToSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
sessions.push_back(iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
@@ -19,37 +19,64 @@ const std::string kProvisioningServerUrl =
|
||||
"https://www.googleapis.com/"
|
||||
"certificateprovisioning/v1/devicecertificates/create"
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
|
||||
/*
|
||||
* Provisioning response is a base64-encoded protobuf, optionally within a
|
||||
* JSON wrapper. If the JSON wrapper is present, extract the embedded response
|
||||
* message. Then perform the base64 decode and return the result.
|
||||
*
|
||||
* If an error occurs during the parse or the decode, return an empty string.
|
||||
*/
|
||||
void ExtractAndDecodeSignedMessage(const std::string& provisioning_response,
|
||||
std::string* result) {
|
||||
const std::string json_start_substr("\"signedResponse\": \"");
|
||||
const std::string json_end_substr("\"");
|
||||
std::string message_string;
|
||||
|
||||
size_t start = provisioning_response.find(json_start_substr);
|
||||
|
||||
if (start == provisioning_response.npos) {
|
||||
// Message is not properly wrapped - reject it.
|
||||
LOGE("ExtractAndDecodeSignedMessage: cannot locate start substring");
|
||||
result->clear();
|
||||
return;
|
||||
} else {
|
||||
// Appears to be JSON-wrapped protobuf - find end of protobuf portion.
|
||||
size_t end = provisioning_response.find(json_end_substr,
|
||||
start + json_start_substr.length());
|
||||
if (end == provisioning_response.npos) {
|
||||
LOGE("ExtractAndDecodeSignedMessage: cannot locate end substring");
|
||||
result->clear();
|
||||
return;
|
||||
}
|
||||
size_t b64_string_size = end - start - json_start_substr.length();
|
||||
message_string.assign(provisioning_response,
|
||||
start + json_start_substr.length(), b64_string_size);
|
||||
}
|
||||
|
||||
if (message_string.empty()) {
|
||||
LOGE("ExtractAndDecodeSignedMessage: CdmProvisioningResponse is empty");
|
||||
result->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode the base64-encoded message.
|
||||
const std::vector<uint8_t> decoded_message =
|
||||
wvcdm::Base64SafeDecode(message_string);
|
||||
result->assign(decoded_message.begin(), decoded_message.end());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace wvcdm {
|
||||
// Protobuf generated classes.
|
||||
using video_widevine::ClientIdentification;
|
||||
using video_widevine::EncryptedClientIdentification;
|
||||
using video_widevine::ProvisioningOptions;
|
||||
using video_widevine::ProvisioningRequest;
|
||||
using video_widevine::ProvisioningResponse;
|
||||
using video_widevine::SignedProvisioningMessage;
|
||||
|
||||
/*
|
||||
* This function converts SignedProvisioningRequest into base64 string. It then
|
||||
* wraps it in JSON format expected by the frontend. This server requires a
|
||||
* "web-safe" base 64 encoding, where '+' becomes '-' and '/' becomes '_'.
|
||||
*
|
||||
* Returns the JSON formated string in *request. The JSON string will be
|
||||
* appended as a query parameter, i.e. signedRequest=<base 64 encoded
|
||||
* SignedProvisioningRequest>. All base64 '=' padding chars must be removed.
|
||||
*
|
||||
* The JSON formated request takes the following format:
|
||||
*
|
||||
* base64 encoded message
|
||||
*/
|
||||
void CertificateProvisioning::ComposeJsonRequestAsQueryString(
|
||||
const std::string& message, CdmProvisioningRequest* request) {
|
||||
// Performs base64 encoding for message
|
||||
std::vector<uint8_t> message_vector(message.begin(), message.end());
|
||||
std::string message_b64 = Base64SafeEncodeNoPad(message_vector);
|
||||
request->assign(message_b64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the ClientIdentification message token type for provisioning request.
|
||||
* NOTE: a DRM Cert should never be presented to the provisioning server.
|
||||
@@ -88,7 +115,7 @@ bool CertificateProvisioning::SetSpoidParameter(
|
||||
// Use the SPOID that has been pre-provided
|
||||
request->set_spoid(spoid);
|
||||
} else if (Properties::UseProviderIdInProvisioningRequest()) {
|
||||
if (service_certificate_->HasProviderId()) {
|
||||
if (!service_certificate_->provider_id().empty()) {
|
||||
request->set_provider_id(service_certificate_->provider_id());
|
||||
} else {
|
||||
LOGE("CertificateProvisioning::SetSpoidParameter: Failure getting "
|
||||
@@ -121,9 +148,9 @@ SignedProvisioningMessage::ProtocolVersion
|
||||
}
|
||||
|
||||
/*
|
||||
* Composes a device provisioning request and output the request in JSON format
|
||||
* in *request. It also returns the default url for the provisioning server
|
||||
* in *default_url.
|
||||
* Compose a device provisioning request and output *request in a
|
||||
* JSON-compatible format (web-safe base64).
|
||||
* Also return *default_url of the provisioning server.
|
||||
*
|
||||
* Returns NO_ERROR for success and CERT_PROVISIONING_REQUEST_ERROR_? if fails.
|
||||
*/
|
||||
@@ -162,17 +189,17 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
client_id->set_token(token);
|
||||
client_id->set_type(token_type);
|
||||
|
||||
#if 0 // TODO(gmorgan) in progress - encrypt ClientIdentification.
|
||||
if (service_certificate_->HasCertificate()) {
|
||||
#if 0 // TODO(gmorgan) Encrypt ClientIdentification. Pending Design.
|
||||
if (service_certificate_->has_certificate()) {
|
||||
EncryptedClientIdentification* encrypted_client_id =
|
||||
provisioning_request->mutable_encrypted_client_id();
|
||||
provisioning_request.mutable_encrypted_client_id();
|
||||
CdmResponseType status;
|
||||
status = service_certificate_->EncryptClientId(&crypto_session_, client_id,
|
||||
encrypted_client_id);
|
||||
if (status == NO_ERROR) {
|
||||
provisioning_request->clear_client_id();
|
||||
provisioning_request.clear_client_id();
|
||||
} else {
|
||||
provisioning_request->clear_encrypted_client_id();
|
||||
provisioning_request.clear_encrypted_client_id();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@@ -234,43 +261,17 @@ CdmResponseType CertificateProvisioning::GetProvisioningRequest(
|
||||
std::string serialized_request;
|
||||
signed_provisioning_msg.SerializeToString(&serialized_request);
|
||||
|
||||
// Converts request into JSON string
|
||||
ComposeJsonRequestAsQueryString(serialized_request, request);
|
||||
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
|
||||
// Return request as web-safe base64 string
|
||||
std::vector<uint8_t> request_vector(serialized_request.begin(),
|
||||
serialized_request.end());
|
||||
request->assign(Base64SafeEncodeNoPad(request_vector));
|
||||
} else {
|
||||
request->swap(serialized_request);
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses the input json_str and locates substring using start_substr and
|
||||
* end_stubstr. The found base64 substring is then decoded and returns
|
||||
* in *result.
|
||||
*
|
||||
* Returns true for success and false if fails.
|
||||
*/
|
||||
bool CertificateProvisioning::ParseJsonResponse(
|
||||
const CdmProvisioningResponse& json_str, const std::string& start_substr,
|
||||
const std::string& end_substr, std::string* result) {
|
||||
std::string b64_string;
|
||||
size_t start = json_str.find(start_substr);
|
||||
if (start == json_str.npos) {
|
||||
LOGE("ParseJsonResponse: cannot find start substring");
|
||||
return false;
|
||||
}
|
||||
size_t end = json_str.find(end_substr, start + start_substr.length());
|
||||
if (end == json_str.npos) {
|
||||
LOGE("ParseJsonResponse cannot locate end substring");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t b64_string_size = end - start - start_substr.length();
|
||||
b64_string.assign(json_str, start + start_substr.length(), b64_string_size);
|
||||
|
||||
// Decodes base64 substring and returns it in *result
|
||||
std::vector<uint8_t> result_vector = Base64SafeDecode(b64_string);
|
||||
result->assign(result_vector.begin(), result_vector.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The response message consists of a device certificate and the device RSA key.
|
||||
* The device RSA key is stored in the T.E.E. The device certificate is stored
|
||||
@@ -281,13 +282,19 @@ bool CertificateProvisioning::ParseJsonResponse(
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
FileSystem* file_system, const CdmProvisioningResponse& response,
|
||||
std::string* cert, std::string* wrapped_key) {
|
||||
// Extracts signed response from JSON string, decodes base64 signed response
|
||||
const std::string kMessageStart = "\"signedResponse\": \"";
|
||||
const std::string kMessageEnd = "\"";
|
||||
std::string serialized_signed_response;
|
||||
if (!ParseJsonResponse(response, kMessageStart, kMessageEnd,
|
||||
&serialized_signed_response)) {
|
||||
LOGE("Fails to extract signed serialized response from JSON response");
|
||||
|
||||
std::string raw_string;
|
||||
if (!wvcdm::Properties::provisioning_messages_are_binary()) {
|
||||
// The response is base64 encoded in a JSON wrapper.
|
||||
// Extract it and decode it. If errors, return an empty string.
|
||||
ExtractAndDecodeSignedMessage(response, &raw_string);
|
||||
} else {
|
||||
raw_string.assign(response);
|
||||
}
|
||||
|
||||
if (raw_string.empty()) {
|
||||
LOGE("HandleProvisioningResponse: response message is empty or "
|
||||
"an invalid JSON/base64 string.");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_1;
|
||||
}
|
||||
|
||||
@@ -295,7 +302,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
// the provisioing request's input). Validate provisioning response and
|
||||
// stores private device RSA key and certificate.
|
||||
SignedProvisioningMessage signed_response;
|
||||
if (!signed_response.ParseFromString(serialized_signed_response)) {
|
||||
if (!signed_response.ParseFromString(raw_string)) {
|
||||
LOGE("HandleProvisioningResponse: fails to parse signed response");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_2;
|
||||
}
|
||||
@@ -314,6 +321,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
if (error) return CERT_PROVISIONING_RESPONSE_ERROR_3;
|
||||
|
||||
const std::string& signed_message = signed_response.message();
|
||||
const std::string& signature = signed_response.signature();
|
||||
ProvisioningResponse provisioning_response;
|
||||
|
||||
if (!provisioning_response.ParseFromString(signed_message)) {
|
||||
@@ -326,15 +334,29 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_5;
|
||||
}
|
||||
|
||||
const std::string& enc_rsa_key = provisioning_response.device_rsa_key();
|
||||
// If Provisioning 3.0 (OEM Cert provisioned), verify that the
|
||||
// message is properly signed.
|
||||
if (crypto_session_.GetPreProvisionTokenType() == kClientTokenOemCert) {
|
||||
if (service_certificate_->VerifySignedMessage(signed_message, signature)
|
||||
!= NO_ERROR) {
|
||||
LOGE("HandleProvisioningResponse: message not properly signed");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_6;
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& new_private_key = provisioning_response.device_rsa_key();
|
||||
const std::string& nonce = provisioning_response.nonce();
|
||||
const std::string& rsa_key_iv = provisioning_response.device_rsa_key_iv();
|
||||
const std::string& signature = signed_response.signature();
|
||||
std::string wrapped_rsa_key;
|
||||
if (!crypto_session_.RewrapDeviceRSAKey(signed_message, signature, nonce,
|
||||
enc_rsa_key, rsa_key_iv,
|
||||
&wrapped_rsa_key)) {
|
||||
LOGE("HandleProvisioningResponse: RewrapDeviceRSAKey fails");
|
||||
const std::string& iv = provisioning_response.device_rsa_key_iv();
|
||||
|
||||
const std::string& wrapping_key = (provisioning_response.has_wrapping_key()) ?
|
||||
provisioning_response.wrapping_key() : std::string();
|
||||
|
||||
std::string wrapped_private_key;
|
||||
|
||||
if (!crypto_session_.RewrapCertificate(signed_message, signature, nonce,
|
||||
new_private_key, iv, wrapping_key,
|
||||
&wrapped_private_key)) {
|
||||
LOGE("HandleProvisioningResponse: RewrapCertificate fails");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_6;
|
||||
}
|
||||
|
||||
@@ -342,7 +364,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
|
||||
if (cert_type_ == kCertificateX509) {
|
||||
*cert = provisioning_response.device_certificate();
|
||||
*wrapped_key = wrapped_rsa_key;
|
||||
*wrapped_key = wrapped_private_key;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -357,7 +379,7 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
LOGE("HandleProvisioningResponse: failed to init DeviceFiles");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_7;
|
||||
}
|
||||
if (!handle.StoreCertificate(device_certificate, wrapped_rsa_key)) {
|
||||
if (!handle.StoreCertificate(device_certificate, wrapped_private_key)) {
|
||||
LOGE("HandleProvisioningResponse: failed to save provisioning certificate");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_8;
|
||||
}
|
||||
|
||||
@@ -54,17 +54,17 @@ CryptoSession::~CryptoSession() {
|
||||
Terminate();
|
||||
}
|
||||
|
||||
bool CryptoSession::GetProvisioningMethod(CdmClientTokenType* token_type) {
|
||||
bool CryptoSession::GetProvisioningMethod(CdmClientTokenType& token_type) {
|
||||
OEMCrypto_ProvisioningMethod method;
|
||||
switch (method = OEMCrypto_GetProvisioningMethod(requested_security_level_)) {
|
||||
case OEMCrypto_OEMCertificate:
|
||||
*token_type = kClientTokenOemCert;
|
||||
token_type = kClientTokenOemCert;
|
||||
break;
|
||||
case OEMCrypto_Keybox:
|
||||
*token_type = kClientTokenKeybox;
|
||||
token_type = kClientTokenKeybox;
|
||||
break;
|
||||
case OEMCrypto_DrmCertificate:
|
||||
*token_type = kClientTokenDrmCert;
|
||||
token_type = kClientTokenDrmCert;
|
||||
break;
|
||||
case OEMCrypto_ProvisioningError:
|
||||
default:
|
||||
@@ -86,7 +86,7 @@ void CryptoSession::Init() {
|
||||
}
|
||||
initialized_ = true;
|
||||
}
|
||||
if (!GetProvisioningMethod(&pre_provision_token_type_)) {
|
||||
if (!GetProvisioningMethod(pre_provision_token_type_)) {
|
||||
initialized_ = false;
|
||||
}
|
||||
}
|
||||
@@ -125,6 +125,10 @@ bool CryptoSession::GetTokenFromKeybox(std::string* token) {
|
||||
|
||||
bool CryptoSession::GetTokenFromOemCert(std::string* token) {
|
||||
OEMCryptoResult status;
|
||||
if (!oem_token_.empty()) {
|
||||
token->assign(oem_token_);
|
||||
return true;
|
||||
}
|
||||
std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0');
|
||||
// lock is held by caller
|
||||
bool retrying = false;
|
||||
@@ -133,6 +137,8 @@ bool CryptoSession::GetTokenFromOemCert(std::string* token) {
|
||||
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
|
||||
status = OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size);
|
||||
if (OEMCrypto_SUCCESS == status) {
|
||||
temp_buffer.resize(buf_size);
|
||||
oem_token_.assign(temp_buffer);
|
||||
token->swap(temp_buffer);
|
||||
return true;
|
||||
}
|
||||
@@ -387,7 +393,8 @@ bool CryptoSession::PrepareRequest(const std::string& message,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Properties::use_certificates_as_identification() || is_provisioning) {
|
||||
if (!Properties::use_certificates_as_identification() ||
|
||||
(is_provisioning && (pre_provision_token_type_ == kClientTokenKeybox))) {
|
||||
if (!GenerateDerivedKeys(message)) return false;
|
||||
|
||||
if (!GenerateSignature(message, signature)) return false;
|
||||
@@ -535,8 +542,16 @@ bool CryptoSession::LoadCertificatePrivateKey(std::string& wrapped_key) {
|
||||
LOGV("CryptoSession::LoadCertificatePrivateKey: Lock");
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
|
||||
// Call OEMCrypto_GetOEMPublicCertificate before OEMCrypto_LoadDeviceRSAKey
|
||||
// so it caches the OEMCrypto Public Key and then throw away result
|
||||
std::string temp_buffer(CERTIFICATE_DATA_SIZE, '\0');
|
||||
size_t buf_size = temp_buffer.size();
|
||||
uint8_t* buf = reinterpret_cast<uint8_t*>(&temp_buffer[0]);
|
||||
OEMCryptoResult sts =
|
||||
OEMCrypto_GetOEMPublicCertificate(oec_session_id_, buf, &buf_size);
|
||||
|
||||
LOGV("LoadDeviceRSAKey: id=%ld", (uint32_t)oec_session_id_);
|
||||
OEMCryptoResult sts = OEMCrypto_LoadDeviceRSAKey(
|
||||
sts = OEMCrypto_LoadDeviceRSAKey(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(wrapped_key.data()),
|
||||
wrapped_key.size());
|
||||
|
||||
@@ -1089,6 +1104,34 @@ bool CryptoSession::SetDestinationBufferType() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::RewrapCertificate(const std::string& signed_message,
|
||||
const std::string& signature,
|
||||
const std::string& nonce,
|
||||
const std::string& private_key,
|
||||
const std::string& iv,
|
||||
const std::string& wrapping_key,
|
||||
std::string* wrapped_private_key) {
|
||||
LOGV("CryptoSession::RewrapCertificate, session id=%ld",
|
||||
static_cast<uint32_t>(oec_session_id_));
|
||||
|
||||
if (pre_provision_token_type_ == kClientTokenKeybox) {
|
||||
|
||||
return RewrapDeviceRSAKey(signed_message, signature, nonce, private_key,
|
||||
iv, wrapped_private_key);
|
||||
|
||||
} else if (pre_provision_token_type_ == kClientTokenOemCert) {
|
||||
|
||||
return RewrapDeviceRSAKey30(signed_message, nonce, private_key, iv,
|
||||
wrapping_key, wrapped_private_key);
|
||||
|
||||
} else {
|
||||
LOGE("CryptoSession::RewrapCertificate, Bad pre-provision type=%d: "
|
||||
"session id=%ld", pre_provision_token_type_,
|
||||
static_cast<uint32_t>(oec_session_id_));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& nonce,
|
||||
@@ -1140,6 +1183,57 @@ bool CryptoSession::RewrapDeviceRSAKey(const std::string& message,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::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) {
|
||||
LOGV("CryptoSession::RewrapDeviceRSAKey30, session id=%ld",
|
||||
static_cast<uint32_t>(oec_session_id_));
|
||||
|
||||
const uint8_t* signed_msg = reinterpret_cast<const uint8_t*>(message.data());
|
||||
const uint8_t* msg_private_key = NULL;
|
||||
const uint8_t* msg_iv = NULL;
|
||||
const uint32_t* msg_nonce = NULL;
|
||||
const uint8_t* msg_wrapping_key = NULL;
|
||||
if (private_key.size() >= MAC_KEY_SIZE && iv.size() >= KEY_IV_SIZE) {
|
||||
msg_private_key = signed_msg + GetOffset(message, private_key);
|
||||
msg_iv = signed_msg + GetOffset(message, iv);
|
||||
msg_nonce = reinterpret_cast<const uint32_t*>(signed_msg +
|
||||
GetOffset(message, nonce));
|
||||
msg_wrapping_key = signed_msg + GetOffset(message, wrapping_key);
|
||||
}
|
||||
|
||||
// Gets wrapped_rsa_key_length by passing NULL as uint8_t* wrapped_rsa_key
|
||||
// and 0 as wrapped_rsa_key_length.
|
||||
size_t wrapped_private_key_length = 0;
|
||||
OEMCryptoResult status = OEMCrypto_RewrapDeviceRSAKey30(
|
||||
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
|
||||
msg_private_key, private_key.size(), msg_iv, NULL,
|
||||
&wrapped_private_key_length);
|
||||
|
||||
if (status != OEMCrypto_ERROR_SHORT_BUFFER) {
|
||||
LOGE("OEMCrypto_RewrapDeviceRSAKey30 failed getting wrapped key length");
|
||||
return false;
|
||||
}
|
||||
|
||||
wrapped_private_key->resize(wrapped_private_key_length);
|
||||
status = OEMCrypto_RewrapDeviceRSAKey30(
|
||||
oec_session_id_, msg_nonce, msg_wrapping_key, wrapping_key.size(),
|
||||
msg_private_key, private_key.size(), msg_iv,
|
||||
reinterpret_cast<uint8_t*>(&(*wrapped_private_key)[0]),
|
||||
&wrapped_private_key_length);
|
||||
|
||||
wrapped_private_key->resize(wrapped_private_key_length);
|
||||
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
LOGE("OEMCrypto_RewrapDeviceRSAKey fails with %d", status);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CryptoSession::GetHdcpCapabilities(HdcpCapability* current,
|
||||
HdcpCapability* max) {
|
||||
LOGV("GetHdcpCapabilities: id=%ld", (uint32_t)oec_session_id_);
|
||||
|
||||
@@ -143,52 +143,43 @@ bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
}
|
||||
|
||||
DeviceCertificate device_certificate = file.device_certificate();
|
||||
|
||||
ExtractDeviceInfo(device_certificate.certificate(), serial_number, system_id);
|
||||
|
||||
*certificate = device_certificate.certificate();
|
||||
*wrapped_private_key = device_certificate.wrapped_private_key();
|
||||
return true;
|
||||
return ExtractDeviceInfo(device_certificate.certificate(), serial_number,
|
||||
system_id);
|
||||
}
|
||||
|
||||
bool DeviceFiles::ExtractDeviceInfo(const std::string& device_certificate,
|
||||
std::string* serial_number,
|
||||
uint32_t* system_id) {
|
||||
LOGI("[WEM] ExtractDeviceInfo");
|
||||
LOGI("ExtractDeviceInfo Entry");
|
||||
if (!serial_number && !system_id) {
|
||||
LOGE("Invalid paramters to DeviceFiles::ExtractDeviceInfo");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get serial number and system ID from certificate
|
||||
if ((serial_number != NULL) || (system_id != NULL)) {
|
||||
SignedDrmDeviceCertificate signed_drm_device_certificate;
|
||||
if (!signed_drm_device_certificate.ParseFromString(device_certificate) ||
|
||||
!signed_drm_device_certificate.has_drm_certificate()) {
|
||||
LOGE("DeviceFiles::ExtractDeviceInfo: fails parsing signed drm device "
|
||||
"certificate.");
|
||||
return false;
|
||||
}
|
||||
DrmDeviceCertificate drm_device_certificate;
|
||||
if (!drm_device_certificate.ParseFromString(
|
||||
signed_drm_device_certificate.drm_certificate()) ||
|
||||
(drm_device_certificate.type() !=
|
||||
video_widevine::DrmDeviceCertificate::DRM_USER_DEVICE)) {
|
||||
LOGE("DeviceFiles::ExtractDeviceInfo: fails parsing drm device "
|
||||
"certificate message.");
|
||||
return false;
|
||||
}
|
||||
if (serial_number != NULL) {
|
||||
if (drm_device_certificate.has_serial_number()) {
|
||||
LOGI("DeviceFiles::ExtractDeviceInfo: serial number: [%s]",
|
||||
(b2a_hex(drm_device_certificate.serial_number())).c_str());
|
||||
*serial_number = drm_device_certificate.serial_number();
|
||||
}
|
||||
}
|
||||
if (system_id != NULL) {
|
||||
if (drm_device_certificate.has_system_id()) {
|
||||
LOGI("DeviceFiles::ExtractDeviceInfo: system id: [%d]",
|
||||
drm_device_certificate.system_id());
|
||||
*system_id = drm_device_certificate.system_id();
|
||||
} else {
|
||||
*system_id = 0;
|
||||
}
|
||||
}
|
||||
SignedDrmDeviceCertificate signed_drm_device_certificate;
|
||||
if (!signed_drm_device_certificate.ParseFromString(device_certificate) ||
|
||||
!signed_drm_device_certificate.has_drm_certificate()) {
|
||||
LOGE("DeviceFiles::ExtractDeviceInfo: fails parsing signed drm device "
|
||||
"certificate.");
|
||||
return false;
|
||||
}
|
||||
DrmDeviceCertificate drm_device_certificate;
|
||||
if (!drm_device_certificate.ParseFromString(
|
||||
signed_drm_device_certificate.drm_certificate()) ||
|
||||
(drm_device_certificate.type() !=
|
||||
video_widevine::DrmDeviceCertificate::DRM_USER_DEVICE)) {
|
||||
LOGE("DeviceFiles::ExtractDeviceInfo: fails parsing drm device "
|
||||
"certificate message.");
|
||||
return false;
|
||||
}
|
||||
if (serial_number != NULL) {
|
||||
*serial_number = drm_device_certificate.serial_number();
|
||||
}
|
||||
if (system_id != NULL) {
|
||||
*system_id = drm_device_certificate.system_id();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -341,7 +332,7 @@ bool DeviceFiles::DeleteLicense(const std::string& key_set_id) {
|
||||
|
||||
bool DeviceFiles::ListLicenses(std::vector<std::string>* key_set_ids) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::DeleteAllLicenses: not initialized");
|
||||
LOGW("DeviceFiles::ListLicenses: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -354,7 +345,7 @@ bool DeviceFiles::ListLicenses(std::vector<std::string>* key_set_ids) {
|
||||
// Scan list of returned filenames, remove extension, and return
|
||||
// as a list of key_set_ids.
|
||||
key_set_ids->clear();
|
||||
for (int i = 0; i < filenames.size(); i++) {
|
||||
for (size_t i = 0; i < filenames.size(); i++) {
|
||||
std::string* name = &filenames[i];
|
||||
std::size_t pos = name->find(kLicenseFileNameExt);
|
||||
if (pos == std::string::npos) {
|
||||
@@ -449,6 +440,77 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
|
||||
return StoreFileWithHash(file_name, serialized_file);
|
||||
}
|
||||
|
||||
bool DeviceFiles::ListUsageRecords(const std::string& app_id,
|
||||
std::vector<std::string>* ksids) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::ListUsageRecords: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ksids == NULL) {
|
||||
LOGW("DeviceFiles::ListUsageRecords: return parameter not provided");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Empty or non-existent file == no usage records.
|
||||
std::string file_name = GetUsageInfoFileName(app_id);
|
||||
if (!FileExists(file_name) || GetFileSize(file_name) == 0) {
|
||||
ksids->clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (!RetrieveHashedFile(file_name, &file)) {
|
||||
LOGW("DeviceFiles::ListUsageRecords: Unable to parse file");
|
||||
return false;
|
||||
}
|
||||
|
||||
ksids->clear();
|
||||
|
||||
size_t num_records = file.usage_info().sessions_size();
|
||||
for (size_t i = 0; i < num_records; ++i) {
|
||||
if (!file.usage_info().sessions(i).key_set_id().empty()) {
|
||||
ksids->push_back(file.usage_info().sessions(i).key_set_id());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::GetProviderToken(const std::string& app_id,
|
||||
const std::string& key_set_id,
|
||||
std::string* provider_session_token) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::GetProviderToken: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (provider_session_token == NULL) {
|
||||
LOGW("DeviceFiles::GetProviderToken: NULL return argument pointer");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string file_name = GetUsageInfoFileName(app_id);
|
||||
if (!FileExists(file_name) || GetFileSize(file_name) == 0) {
|
||||
LOGW("DeviceFiles::GetProviderToken: empty file");
|
||||
return false;
|
||||
}
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (!RetrieveHashedFile(file_name, &file)) {
|
||||
LOGW("DeviceFiles::GetProviderToken: unable to parse file");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t num_records = file.usage_info().sessions_size();
|
||||
for (size_t i = 0; i < num_records; ++i) {
|
||||
if (file.usage_info().sessions(i).key_set_id() == key_set_id) {
|
||||
*provider_session_token = file.usage_info().sessions(i).token();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DeviceFiles::DeleteUsageInfo(const std::string& app_id,
|
||||
const std::string& provider_session_token) {
|
||||
if (!initialized_) {
|
||||
|
||||
@@ -19,16 +19,16 @@
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
std::string kCompanyNameKey = "company_name";
|
||||
std::string kModelNameKey = "model_name";
|
||||
std::string kArchitectureNameKey = "architecture_name";
|
||||
std::string kDeviceNameKey = "device_name";
|
||||
std::string kProductNameKey = "product_name";
|
||||
std::string kBuildInfoKey = "build_info";
|
||||
std::string kDeviceIdKey = "device_id";
|
||||
std::string kWVCdmVersionKey = "widevine_cdm_version";
|
||||
std::string kOemCryptoSecurityPatchLevelKey = "oem_crypto_security_patch_level";
|
||||
} // namespace
|
||||
const std::string kCompanyNameKey = "company_name";
|
||||
const std::string kModelNameKey = "model_name";
|
||||
const std::string kArchitectureNameKey = "architecture_name";
|
||||
const std::string kDeviceNameKey = "device_name";
|
||||
const std::string kProductNameKey = "product_name";
|
||||
const std::string kBuildInfoKey = "build_info";
|
||||
const std::string kDeviceIdKey = "device_id";
|
||||
const std::string kWVCdmVersionKey = "widevine_cdm_version";
|
||||
const std::string kOemCryptoSecurityPatchLevelKey =
|
||||
"oem_crypto_security_patch_level";
|
||||
|
||||
const uint32_t kFourCcCbc1 = 0x63626331;
|
||||
const uint32_t kFourCcCbcs = 0x63626373;
|
||||
@@ -37,6 +37,8 @@ const uint32_t kFourCcLittleEndianCbcs = 0x73636263;
|
||||
const uint32_t kFourCcCenc = 0x63656e63;
|
||||
const uint32_t kFourCcCens = 0x63656e73;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// Protobuf generated classes.
|
||||
@@ -144,7 +146,7 @@ CdmLicense::~CdmLicense() {}
|
||||
|
||||
bool CdmLicense::Init(
|
||||
ServiceCertificate* service_certificate, const std::string& client_token,
|
||||
CdmClientTokenType client_token_type, const std::string& serial_number,
|
||||
CdmClientTokenType client_token_type, const std::string& device_id,
|
||||
CryptoSession* session, PolicyEngine* policy_engine) {
|
||||
if (clock_.get() == NULL) {
|
||||
LOGE("CdmLicense::Init: clock parameter not provided");
|
||||
@@ -170,7 +172,7 @@ bool CdmLicense::Init(
|
||||
service_certificate_ = service_certificate;
|
||||
client_token_ = client_token;
|
||||
client_token_type_ = client_token_type;
|
||||
serial_number_ = serial_number;
|
||||
device_id_ = device_id;
|
||||
crypto_session_ = session;
|
||||
policy_engine_ = policy_engine;
|
||||
initialized_ = true;
|
||||
@@ -185,12 +187,6 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
LOGE("CdmLicense::PrepareKeyRequest: not initialized");
|
||||
return LICENSE_PARSER_NOT_INITIALIZED_4;
|
||||
}
|
||||
if (init_data.IsEmpty() && stored_init_data_.get()) {
|
||||
InitializationData restored_init_data = *stored_init_data_;
|
||||
stored_init_data_.reset();
|
||||
return PrepareKeyRequest(restored_init_data, license_type, app_parameters,
|
||||
signed_request, server_url);
|
||||
}
|
||||
if (!init_data.is_supported()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: unsupported init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
@@ -209,16 +205,12 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
return INVALID_PARAMETERS_LIC_7;
|
||||
}
|
||||
|
||||
// If privacy mode and no service certificate, initiate a
|
||||
// service certificate request.
|
||||
// If privacy mode, must have service certificate
|
||||
if (Properties::UsePrivacyMode(session_id_) &&
|
||||
!service_certificate_->HasCertificate()) {
|
||||
stored_init_data_.reset(new InitializationData(init_data));
|
||||
*server_url = server_url_;
|
||||
if (service_certificate_->PrepareRequest(signed_request)) {
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
return LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR;
|
||||
!service_certificate_->has_certificate()) {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: failure with privacy mode - "
|
||||
"no service certificate.");
|
||||
return PRIVACY_MODE_ERROR_1;
|
||||
}
|
||||
|
||||
std::string request_id;
|
||||
@@ -303,12 +295,10 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
|
||||
if (renew_with_client_id_) {
|
||||
if (Properties::UsePrivacyMode(session_id_) &&
|
||||
!service_certificate_->HasCertificate()) {
|
||||
*server_url = server_url_;
|
||||
if (service_certificate_->PrepareRequest(signed_request)) {
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
return LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR;
|
||||
!service_certificate_->has_certificate()) {
|
||||
LOGE("CdmLicense::PrepareKeyUpdateRequest: failure with privacy mode - "
|
||||
"no service certificate.");
|
||||
return PRIVACY_MODE_ERROR_2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,14 +413,6 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
switch (signed_response.type()) {
|
||||
case SignedMessage::LICENSE:
|
||||
break;
|
||||
case SignedMessage::SERVICE_CERTIFICATE: {
|
||||
CdmResponseType status;
|
||||
status = service_certificate_->HandleResponse(signed_response.msg());
|
||||
if (status != NO_ERROR) {
|
||||
return status;
|
||||
}
|
||||
return NEED_KEY;
|
||||
}
|
||||
case SignedMessage::ERROR_RESPONSE:
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
default:
|
||||
@@ -494,8 +476,13 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
license.policy().can_persist())
|
||||
is_offline_ = true;
|
||||
|
||||
if (license.id().has_provider_session_token())
|
||||
LOGV("Get Provider_session_token:");
|
||||
if (license.id().has_provider_session_token()) {
|
||||
provider_session_token_ = license.id().provider_session_token();
|
||||
LOGV("Provider_session_token=%s", provider_session_token_.c_str());
|
||||
} else {
|
||||
LOGV("NO Provider_session_token");
|
||||
}
|
||||
|
||||
if (license.policy().has_renewal_server_url()) {
|
||||
server_url_ = license.policy().renewal_server_url();
|
||||
@@ -540,14 +527,6 @@ CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||
switch (signed_response.type()) {
|
||||
case SignedMessage::LICENSE:
|
||||
break;
|
||||
case SignedMessage::SERVICE_CERTIFICATE: {
|
||||
CdmResponseType status;
|
||||
status = service_certificate_->HandleResponse(signed_response.msg());
|
||||
if (status != NO_ERROR) {
|
||||
return status;
|
||||
}
|
||||
return NEED_KEY;
|
||||
}
|
||||
case SignedMessage::ERROR_RESPONSE:
|
||||
return HandleKeyErrorResponse(signed_response);
|
||||
default:
|
||||
@@ -820,6 +799,7 @@ bool CdmLicense::GetClientTokenType(
|
||||
case kClientTokenOemCert:
|
||||
default:
|
||||
// shouldn't happen
|
||||
LOGE("GetClientTokenType: BAD TOKEN TYPE");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -873,10 +853,10 @@ CdmResponseType CdmLicense::PrepareClientId(
|
||||
client_info->set_name(kBuildInfoKey);
|
||||
client_info->set_value(value);
|
||||
}
|
||||
if (!serial_number_.empty()) {
|
||||
if (!device_id_.empty()) {
|
||||
client_info = client_id->add_client_info();
|
||||
client_info->set_name(kDeviceIdKey);
|
||||
client_info->set_value(b2a_hex(serial_number_));
|
||||
client_info->set_value(b2a_hex(device_id_));
|
||||
} else if (crypto_session_->GetDeviceUniqueId(&value)) {
|
||||
client_info = client_id->add_client_info();
|
||||
client_info->set_name(kDeviceIdKey);
|
||||
@@ -950,9 +930,9 @@ CdmResponseType CdmLicense::PrepareClientId(
|
||||
}
|
||||
|
||||
if (Properties::UsePrivacyMode(session_id_)) {
|
||||
if (!service_certificate_->HasCertificate()) {
|
||||
if (service_certificate_->certificate().empty()) {
|
||||
LOGE("CdmLicense::PrepareClientId: Service Certificate not staged");
|
||||
return LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR;
|
||||
return PRIVACY_MODE_ERROR_3;
|
||||
}
|
||||
EncryptedClientIdentification* encrypted_client_id =
|
||||
license_request->mutable_encrypted_client_id();
|
||||
@@ -983,7 +963,7 @@ CdmResponseType CdmLicense::PrepareContentId(
|
||||
if (!init_data.IsEmpty()) {
|
||||
cenc_content_id->add_pssh(init_data.data());
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: ISO-CENC init data not available");
|
||||
LOGE("CdmLicense::PrepareContentId: ISO-CENC init data not available");
|
||||
return CENC_INIT_DATA_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@@ -997,7 +977,7 @@ CdmResponseType CdmLicense::PrepareContentId(
|
||||
if (!init_data.IsEmpty()) {
|
||||
webm_content_id->set_header(init_data.data());
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: WebM init data not available");
|
||||
LOGE("CdmLicense::PrepareContentId: WebM init data not available");
|
||||
return WEBM_INIT_DATA_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@@ -1005,7 +985,7 @@ CdmResponseType CdmLicense::PrepareContentId(
|
||||
return PREPARE_WEBM_CONTENT_ID_FAILED;
|
||||
}
|
||||
} else {
|
||||
LOGE("CdmLicense::PrepareKeyRequest: no support for init data type (%s)",
|
||||
LOGE("CdmLicense::PrepareContentId: no support for init data type (%s)",
|
||||
init_data.type().c_str());
|
||||
return UNSUPPORTED_INIT_DATA_FORMAT;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "log.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
// License protocol aliases
|
||||
@@ -102,7 +103,15 @@ bool LicenseKeys::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
return keys_changed;
|
||||
}
|
||||
|
||||
CdmKeyStatus LicenseKeys::GetKeyStatus(const KeyId& key_id) {
|
||||
if (keys_.count(key_id) == 0) {
|
||||
return kKeyStatusKeyUnknown;
|
||||
}
|
||||
return keys_[key_id]->GetKeyStatus();
|
||||
}
|
||||
|
||||
void LicenseKeys::ExtractKeyStatuses(CdmKeyStatusMap* content_keys) {
|
||||
content_keys->clear();
|
||||
for (LicenseKeyStatusIterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
if (it->second->IsContentKey()) {
|
||||
const KeyId key_id = it->first;
|
||||
@@ -251,11 +260,11 @@ bool LicenseKeyStatus::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
// requirement, use the key's default HDCP setting to check against the
|
||||
// device's current HDCP level.
|
||||
void LicenseKeyStatus::ApplyConstraints(
|
||||
uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level) {
|
||||
uint32_t video_pixels, CryptoSession::HdcpCapability new_hdcp_level) {
|
||||
|
||||
VideoResolutionConstraint* current_constraint = NULL;
|
||||
if (HasConstraints()) {
|
||||
current_constraint = GetConstraintForRes(new_resolution, constraints_);
|
||||
if (HasConstraints() && video_pixels != HDCP_UNSPECIFIED_VIDEO_RESOLUTION) {
|
||||
current_constraint = GetConstraintForRes(video_pixels, constraints_);
|
||||
if (NULL == current_constraint) {
|
||||
meets_constraints_ = false;
|
||||
return;
|
||||
|
||||
@@ -10,75 +10,73 @@
|
||||
namespace wvcdm {
|
||||
|
||||
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
||||
SecurityLevel level) {
|
||||
SecurityLevel) {
|
||||
return ::OEMCrypto_OpenSession(session);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox,
|
||||
size_t keyBoxLength,
|
||||
SecurityLevel level) {
|
||||
size_t keyBoxLength, SecurityLevel) {
|
||||
return ::OEMCrypto_InstallKeybox(keybox, keyBoxLength);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) {
|
||||
OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel) {
|
||||
return ::OEMCrypto_IsKeyboxValid();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength,
|
||||
SecurityLevel level) {
|
||||
SecurityLevel) {
|
||||
return ::OEMCrypto_GetDeviceID(deviceID, idLength);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength,
|
||||
SecurityLevel level) {
|
||||
SecurityLevel) {
|
||||
return ::OEMCrypto_GetKeyData(keyData, keyDataLength);
|
||||
}
|
||||
|
||||
uint32_t OEMCrypto_APIVersion(SecurityLevel level) {
|
||||
uint32_t OEMCrypto_APIVersion(SecurityLevel) {
|
||||
return ::OEMCrypto_APIVersion();
|
||||
}
|
||||
|
||||
uint8_t OEMCrypto_Security_Patch_Level(SecurityLevel level) {
|
||||
uint8_t OEMCrypto_Security_Patch_Level(SecurityLevel) {
|
||||
return ::OEMCrypto_Security_Patch_Level();
|
||||
}
|
||||
|
||||
const char* OEMCrypto_SecurityLevel(SecurityLevel level) {
|
||||
const char* OEMCrypto_SecurityLevel(SecurityLevel) {
|
||||
return ::OEMCrypto_SecurityLevel();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetHDCPCapability(
|
||||
SecurityLevel level, OEMCrypto_HDCP_Capability* current,
|
||||
SecurityLevel, OEMCrypto_HDCP_Capability* current,
|
||||
OEMCrypto_HDCP_Capability* maximum) {
|
||||
return ::OEMCrypto_GetHDCPCapability(current, maximum);
|
||||
}
|
||||
|
||||
bool OEMCrypto_SupportsUsageTable(SecurityLevel level) {
|
||||
bool OEMCrypto_SupportsUsageTable(SecurityLevel) {
|
||||
return ::OEMCrypto_SupportsUsageTable();
|
||||
}
|
||||
|
||||
bool OEMCrypto_IsAntiRollbackHwPresent(SecurityLevel level) {
|
||||
bool OEMCrypto_IsAntiRollbackHwPresent(SecurityLevel) {
|
||||
return ::OEMCrypto_IsAntiRollbackHwPresent();
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(SecurityLevel level,
|
||||
OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(SecurityLevel,
|
||||
size_t* count) {
|
||||
return ::OEMCrypto_GetNumberOfOpenSessions(count);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(SecurityLevel level,
|
||||
OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(SecurityLevel,
|
||||
size_t* maximum) {
|
||||
return ::OEMCrypto_GetMaxNumberOfSessions(maximum);
|
||||
}
|
||||
|
||||
OEMCryptoResult OEMCrypto_CopyBuffer(
|
||||
SecurityLevel level, const uint8_t* data_addr, size_t data_length,
|
||||
SecurityLevel, const uint8_t* data_addr, size_t data_length,
|
||||
OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) {
|
||||
return ::OEMCrypto_CopyBuffer(data_addr, data_length, out_buffer,
|
||||
subsample_flags);
|
||||
}
|
||||
|
||||
OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(
|
||||
SecurityLevel level) {
|
||||
OEMCrypto_ProvisioningMethod OEMCrypto_GetProvisioningMethod(SecurityLevel) {
|
||||
return ::OEMCrypto_GetProvisioningMethod();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,6 @@
|
||||
|
||||
using video_widevine::License;
|
||||
|
||||
namespace {
|
||||
|
||||
const int64_t kHdcpCheckInterval = 10;
|
||||
const uint32_t kNoResolution = 0;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
||||
@@ -54,25 +47,36 @@ bool PolicyEngine::CanDecryptContent(const KeyId& key_id) {
|
||||
}
|
||||
}
|
||||
|
||||
CdmKeyStatus PolicyEngine::GetKeyStatus(const KeyId& key_id) {
|
||||
return license_keys_->GetKeyStatus(key_id);
|
||||
}
|
||||
|
||||
void PolicyEngine::InitDevice(CryptoSession* crypto_session) {
|
||||
current_resolution_ = kNoResolution;
|
||||
current_resolution_ = HDCP_UNSPECIFIED_VIDEO_RESOLUTION;
|
||||
next_device_check_ = 0;
|
||||
crypto_session_ = crypto_session;
|
||||
}
|
||||
|
||||
void PolicyEngine::CheckDevice(int64_t current_time) {
|
||||
if (current_time < next_device_check_) {
|
||||
return;
|
||||
}
|
||||
void PolicyEngine::SetDeviceResolution(uint32_t width, uint32_t height) {
|
||||
current_resolution_ = width * height;
|
||||
CheckDeviceHdcpStatus();
|
||||
}
|
||||
|
||||
if (!license_keys_->Empty() && current_resolution_ != kNoResolution) {
|
||||
void PolicyEngine::CheckDeviceHdcpStatusOnTimer(int64_t current_time) {
|
||||
if (current_time >= next_device_check_) {
|
||||
CheckDeviceHdcpStatus();
|
||||
next_device_check_ = current_time + HDCP_DEVICE_CHECK_INTERVAL;
|
||||
}
|
||||
}
|
||||
|
||||
void PolicyEngine::CheckDeviceHdcpStatus() {
|
||||
if (!license_keys_->Empty()) {
|
||||
CryptoSession::HdcpCapability current_hdcp_level;
|
||||
CryptoSession::HdcpCapability ignored;
|
||||
if (!crypto_session_->GetHdcpCapabilities(¤t_hdcp_level, &ignored)) {
|
||||
current_hdcp_level = HDCP_NONE;
|
||||
}
|
||||
license_keys_->ApplyConstraints(current_resolution_, current_hdcp_level);
|
||||
next_device_check_ = current_time + kHdcpCheckInterval;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,14 +98,16 @@ void PolicyEngine::OnTimerEvent() {
|
||||
}
|
||||
|
||||
// Check device conditions that affect playability (HDCP, resolution)
|
||||
CheckDevice(current_time);
|
||||
CheckDeviceHdcpStatusOnTimer(current_time);
|
||||
|
||||
bool renewal_needed = false;
|
||||
|
||||
// Test to determine if renewal should be attempted.
|
||||
switch (license_state_) {
|
||||
case kLicenseStateCanPlay: {
|
||||
if (HasRenewalDelayExpired(current_time)) renewal_needed = true;
|
||||
if (HasRenewalDelayExpired(current_time)) {
|
||||
renewal_needed = true;
|
||||
}
|
||||
// HDCP may change, so force a check.
|
||||
NotifyKeysChange(kKeyStatusUsable);
|
||||
break;
|
||||
@@ -113,7 +119,9 @@ void PolicyEngine::OnTimerEvent() {
|
||||
}
|
||||
|
||||
case kLicenseStateWaitingLicenseUpdate: {
|
||||
if (HasRenewalRetryIntervalExpired(current_time)) renewal_needed = true;
|
||||
if (HasRenewalRetryIntervalExpired(current_time)) {
|
||||
renewal_needed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -420,9 +428,16 @@ bool PolicyEngine::HasRenewalRetryIntervalExpired(int64_t current_time) {
|
||||
next_renewal_time_ <= current_time;
|
||||
}
|
||||
|
||||
// Apply a key status to the current keys.
|
||||
// If this represents a new key status, perform a notification callback.
|
||||
// NOTE: if the new status is kKeyStatusUsable, the HDCP check may result in an
|
||||
// override to kKeyStatusOutputNotAllowed.
|
||||
void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) {
|
||||
bool keys_changed;
|
||||
bool has_new_usable_key = false;
|
||||
if (new_status == kKeyStatusUsable) {
|
||||
CheckDeviceHdcpStatus();
|
||||
}
|
||||
keys_changed = license_keys_->ApplyStatusChange(new_status,
|
||||
&has_new_usable_key);
|
||||
if (event_listener_ && keys_changed) {
|
||||
|
||||
@@ -182,7 +182,7 @@ bool RsaPublicKey::Encrypt(const std::string& clear_message,
|
||||
|
||||
// LogOpenSSLError is a callback from OpenSSL which is called with each error
|
||||
// in the thread's error queue.
|
||||
static int LogOpenSSLError(const char *msg, size_t /* len */, void */* ctx */) {
|
||||
static int LogOpenSSLError(const char* msg, size_t /* len */, void* /* ctx */) {
|
||||
LOGE(" %s", msg);
|
||||
return 1;
|
||||
}
|
||||
@@ -199,7 +199,8 @@ static bool VerifyPSSSignature(EVP_PKEY *pkey, const std::string &message,
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_CTX_set_signature_md(pctx, EVP_sha1()) != 1) {
|
||||
if (EVP_PKEY_CTX_set_signature_md(pctx,
|
||||
const_cast<EVP_MD *>(EVP_sha1())) != 1) {
|
||||
LOGE("EVP_PKEY_CTX_set_signature_md failed in VerifyPSSSignature");
|
||||
goto err;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ bool Properties::oem_crypto_use_secure_buffers_;
|
||||
bool Properties::oem_crypto_use_fifo_;
|
||||
bool Properties::oem_crypto_use_userspace_buffers_;
|
||||
bool Properties::use_certificates_as_identification_;
|
||||
bool Properties::provisioning_messages_are_binary_;
|
||||
bool Properties::security_level_path_backward_compatibility_support_;
|
||||
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_;
|
||||
|
||||
|
||||
@@ -11,41 +11,110 @@
|
||||
|
||||
namespace {
|
||||
// Service certificate for Google/Widevine Provisioning and License servers.
|
||||
const unsigned char kServiceCertificateCAPublicKey[] = {
|
||||
0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01, 0x81, 0x00, 0xb4, 0xfe, 0x39,
|
||||
0xc3, 0x65, 0x90, 0x03, 0xdb, 0x3c, 0x11, 0x97, 0x09, 0xe8, 0x68, 0xcd,
|
||||
0xf2, 0xc3, 0x5e, 0x9b, 0xf2, 0xe7, 0x4d, 0x23, 0xb1, 0x10, 0xdb, 0x87,
|
||||
0x65, 0xdf, 0xdc, 0xfb, 0x9f, 0x35, 0xa0, 0x57, 0x03, 0x53, 0x4c, 0xf6,
|
||||
0x6d, 0x35, 0x7d, 0xa6, 0x78, 0xdb, 0xb3, 0x36, 0xd2, 0x3f, 0x9c, 0x40,
|
||||
0xa9, 0x95, 0x26, 0x72, 0x7f, 0xb8, 0xbe, 0x66, 0xdf, 0xc5, 0x21, 0x98,
|
||||
0x78, 0x15, 0x16, 0x68, 0x5d, 0x2f, 0x46, 0x0e, 0x43, 0xcb, 0x8a, 0x84,
|
||||
0x39, 0xab, 0xfb, 0xb0, 0x35, 0x80, 0x22, 0xbe, 0x34, 0x23, 0x8b, 0xab,
|
||||
0x53, 0x5b, 0x72, 0xec, 0x4b, 0xb5, 0x48, 0x69, 0x53, 0x3e, 0x47, 0x5f,
|
||||
0xfd, 0x09, 0xfd, 0xa7, 0x76, 0x13, 0x8f, 0x0f, 0x92, 0xd6, 0x4c, 0xdf,
|
||||
0xae, 0x76, 0xa9, 0xba, 0xd9, 0x22, 0x10, 0xa9, 0x9d, 0x71, 0x45, 0xd6,
|
||||
0xd7, 0xe1, 0x19, 0x25, 0x85, 0x9c, 0x53, 0x9a, 0x97, 0xeb, 0x84, 0xd7,
|
||||
0xcc, 0xa8, 0x88, 0x82, 0x20, 0x70, 0x26, 0x20, 0xfd, 0x7e, 0x40, 0x50,
|
||||
0x27, 0xe2, 0x25, 0x93, 0x6f, 0xbc, 0x3e, 0x72, 0xa0, 0xfa, 0xc1, 0xbd,
|
||||
0x29, 0xb4, 0x4d, 0x82, 0x5c, 0xc1, 0xb4, 0xcb, 0x9c, 0x72, 0x7e, 0xb0,
|
||||
0xe9, 0x8a, 0x17, 0x3e, 0x19, 0x63, 0xfc, 0xfd, 0x82, 0x48, 0x2b, 0xb7,
|
||||
0xb2, 0x33, 0xb9, 0x7d, 0xec, 0x4b, 0xba, 0x89, 0x1f, 0x27, 0xb8, 0x9b,
|
||||
0x88, 0x48, 0x84, 0xaa, 0x18, 0x92, 0x0e, 0x65, 0xf5, 0xc8, 0x6c, 0x11,
|
||||
0xff, 0x6b, 0x36, 0xe4, 0x74, 0x34, 0xca, 0x8c, 0x33, 0xb1, 0xf9, 0xb8,
|
||||
0x8e, 0xb4, 0xe6, 0x12, 0xe0, 0x02, 0x98, 0x79, 0x52, 0x5e, 0x45, 0x33,
|
||||
0xff, 0x11, 0xdc, 0xeb, 0xc3, 0x53, 0xba, 0x7c, 0x60, 0x1a, 0x11, 0x3d,
|
||||
0x00, 0xfb, 0xd2, 0xb7, 0xaa, 0x30, 0xfa, 0x4f, 0x5e, 0x48, 0x77, 0x5b,
|
||||
0x17, 0xdc, 0x75, 0xef, 0x6f, 0xd2, 0x19, 0x6d, 0xdc, 0xbe, 0x7f, 0xb0,
|
||||
0x78, 0x8f, 0xdc, 0x82, 0x60, 0x4c, 0xbf, 0xe4, 0x29, 0x06, 0x5e, 0x69,
|
||||
0x8c, 0x39, 0x13, 0xad, 0x14, 0x25, 0xed, 0x19, 0xb2, 0xf2, 0x9f, 0x01,
|
||||
0x82, 0x0d, 0x56, 0x44, 0x88, 0xc8, 0x35, 0xec, 0x1f, 0x11, 0xb3, 0x24,
|
||||
0xe0, 0x59, 0x0d, 0x37, 0xe4, 0x47, 0x3c, 0xea, 0x4b, 0x7f, 0x97, 0x31,
|
||||
0x1c, 0x81, 0x7c, 0x94, 0x8a, 0x4c, 0x7d, 0x68, 0x15, 0x84, 0xff, 0xa5,
|
||||
0x08, 0xfd, 0x18, 0xe7, 0xe7, 0x2b, 0xe4, 0x47, 0x27, 0x12, 0x11, 0xb8,
|
||||
0x23, 0xec, 0x58, 0x93, 0x3c, 0xac, 0x12, 0xd2, 0x88, 0x6d, 0x41, 0x3d,
|
||||
0xc5, 0xfe, 0x1c, 0xdc, 0xb9, 0xf8, 0xd4, 0x51, 0x3e, 0x07, 0xe5, 0x03,
|
||||
0x6f, 0xa7, 0x12, 0xe8, 0x12, 0xf7, 0xb5, 0xce, 0xa6, 0x96, 0x55, 0x3f,
|
||||
0x78, 0xb4, 0x64, 0x82, 0x50, 0xd2, 0x33, 0x5f, 0x91, 0x02, 0x03, 0x01,
|
||||
0x00, 0x01};
|
||||
static const unsigned char kRootCertForProd[] = {
|
||||
0x0a, 0x9c, 0x03, 0x08, 0x00, 0x12, 0x01, 0x00,
|
||||
0x18, 0xdd, 0x94, 0x88, 0x8b, 0x05, 0x22, 0x8e,
|
||||
0x03, 0x30, 0x82, 0x01, 0x8a, 0x02, 0x82, 0x01,
|
||||
0x81, 0x00, 0xb4, 0xfe, 0x39, 0xc3, 0x65, 0x90,
|
||||
0x03, 0xdb, 0x3c, 0x11, 0x97, 0x09, 0xe8, 0x68,
|
||||
0xcd, 0xf2, 0xc3, 0x5e, 0x9b, 0xf2, 0xe7, 0x4d,
|
||||
0x23, 0xb1, 0x10, 0xdb, 0x87, 0x65, 0xdf, 0xdc,
|
||||
0xfb, 0x9f, 0x35, 0xa0, 0x57, 0x03, 0x53, 0x4c,
|
||||
0xf6, 0x6d, 0x35, 0x7d, 0xa6, 0x78, 0xdb, 0xb3,
|
||||
0x36, 0xd2, 0x3f, 0x9c, 0x40, 0xa9, 0x95, 0x26,
|
||||
0x72, 0x7f, 0xb8, 0xbe, 0x66, 0xdf, 0xc5, 0x21,
|
||||
0x98, 0x78, 0x15, 0x16, 0x68, 0x5d, 0x2f, 0x46,
|
||||
0x0e, 0x43, 0xcb, 0x8a, 0x84, 0x39, 0xab, 0xfb,
|
||||
0xb0, 0x35, 0x80, 0x22, 0xbe, 0x34, 0x23, 0x8b,
|
||||
0xab, 0x53, 0x5b, 0x72, 0xec, 0x4b, 0xb5, 0x48,
|
||||
0x69, 0x53, 0x3e, 0x47, 0x5f, 0xfd, 0x09, 0xfd,
|
||||
0xa7, 0x76, 0x13, 0x8f, 0x0f, 0x92, 0xd6, 0x4c,
|
||||
0xdf, 0xae, 0x76, 0xa9, 0xba, 0xd9, 0x22, 0x10,
|
||||
0xa9, 0x9d, 0x71, 0x45, 0xd6, 0xd7, 0xe1, 0x19,
|
||||
0x25, 0x85, 0x9c, 0x53, 0x9a, 0x97, 0xeb, 0x84,
|
||||
0xd7, 0xcc, 0xa8, 0x88, 0x82, 0x20, 0x70, 0x26,
|
||||
0x20, 0xfd, 0x7e, 0x40, 0x50, 0x27, 0xe2, 0x25,
|
||||
0x93, 0x6f, 0xbc, 0x3e, 0x72, 0xa0, 0xfa, 0xc1,
|
||||
0xbd, 0x29, 0xb4, 0x4d, 0x82, 0x5c, 0xc1, 0xb4,
|
||||
0xcb, 0x9c, 0x72, 0x7e, 0xb0, 0xe9, 0x8a, 0x17,
|
||||
0x3e, 0x19, 0x63, 0xfc, 0xfd, 0x82, 0x48, 0x2b,
|
||||
0xb7, 0xb2, 0x33, 0xb9, 0x7d, 0xec, 0x4b, 0xba,
|
||||
0x89, 0x1f, 0x27, 0xb8, 0x9b, 0x88, 0x48, 0x84,
|
||||
0xaa, 0x18, 0x92, 0x0e, 0x65, 0xf5, 0xc8, 0x6c,
|
||||
0x11, 0xff, 0x6b, 0x36, 0xe4, 0x74, 0x34, 0xca,
|
||||
0x8c, 0x33, 0xb1, 0xf9, 0xb8, 0x8e, 0xb4, 0xe6,
|
||||
0x12, 0xe0, 0x02, 0x98, 0x79, 0x52, 0x5e, 0x45,
|
||||
0x33, 0xff, 0x11, 0xdc, 0xeb, 0xc3, 0x53, 0xba,
|
||||
0x7c, 0x60, 0x1a, 0x11, 0x3d, 0x00, 0xfb, 0xd2,
|
||||
0xb7, 0xaa, 0x30, 0xfa, 0x4f, 0x5e, 0x48, 0x77,
|
||||
0x5b, 0x17, 0xdc, 0x75, 0xef, 0x6f, 0xd2, 0x19,
|
||||
0x6d, 0xdc, 0xbe, 0x7f, 0xb0, 0x78, 0x8f, 0xdc,
|
||||
0x82, 0x60, 0x4c, 0xbf, 0xe4, 0x29, 0x06, 0x5e,
|
||||
0x69, 0x8c, 0x39, 0x13, 0xad, 0x14, 0x25, 0xed,
|
||||
0x19, 0xb2, 0xf2, 0x9f, 0x01, 0x82, 0x0d, 0x56,
|
||||
0x44, 0x88, 0xc8, 0x35, 0xec, 0x1f, 0x11, 0xb3,
|
||||
0x24, 0xe0, 0x59, 0x0d, 0x37, 0xe4, 0x47, 0x3c,
|
||||
0xea, 0x4b, 0x7f, 0x97, 0x31, 0x1c, 0x81, 0x7c,
|
||||
0x94, 0x8a, 0x4c, 0x7d, 0x68, 0x15, 0x84, 0xff,
|
||||
0xa5, 0x08, 0xfd, 0x18, 0xe7, 0xe7, 0x2b, 0xe4,
|
||||
0x47, 0x27, 0x12, 0x11, 0xb8, 0x23, 0xec, 0x58,
|
||||
0x93, 0x3c, 0xac, 0x12, 0xd2, 0x88, 0x6d, 0x41,
|
||||
0x3d, 0xc5, 0xfe, 0x1c, 0xdc, 0xb9, 0xf8, 0xd4,
|
||||
0x51, 0x3e, 0x07, 0xe5, 0x03, 0x6f, 0xa7, 0x12,
|
||||
0xe8, 0x12, 0xf7, 0xb5, 0xce, 0xa6, 0x96, 0x55,
|
||||
0x3f, 0x78, 0xb4, 0x64, 0x82, 0x50, 0xd2, 0x33,
|
||||
0x5f, 0x91, 0x02, 0x03, 0x01, 0x00, 0x01, 0x12,
|
||||
0x80, 0x03, 0x58, 0xf1, 0xd6, 0x4d, 0x04, 0x09,
|
||||
0x7b, 0xdf, 0xd7, 0xef, 0x5d, 0x3b, 0x02, 0x39,
|
||||
0x17, 0xfa, 0x14, 0x36, 0x75, 0x4a, 0x38, 0x67,
|
||||
0x85, 0x57, 0x12, 0xa7, 0x14, 0xee, 0x35, 0x16,
|
||||
0xd5, 0x3d, 0xbf, 0x42, 0x86, 0xf6, 0x69, 0x00,
|
||||
0x76, 0xcd, 0x93, 0xf4, 0x7c, 0xb2, 0xdf, 0x9e,
|
||||
0x44, 0xcd, 0x4c, 0xd4, 0xae, 0x09, 0x18, 0x53,
|
||||
0x44, 0x32, 0xec, 0xe0, 0x61, 0x1b, 0xe5, 0xda,
|
||||
0x13, 0xd3, 0x55, 0xc5, 0xdd, 0x1a, 0xcb, 0x90,
|
||||
0x1e, 0x7e, 0x5b, 0xc6, 0xe9, 0x0f, 0x22, 0x9f,
|
||||
0xbe, 0x85, 0x02, 0xfe, 0x90, 0x31, 0xcc, 0x6b,
|
||||
0x03, 0x84, 0xbd, 0x22, 0xc4, 0x55, 0xfa, 0xf5,
|
||||
0xf2, 0x08, 0xcd, 0x65, 0x41, 0x58, 0xe8, 0x7d,
|
||||
0x29, 0xda, 0x04, 0x58, 0x82, 0xf5, 0x37, 0x69,
|
||||
0xbc, 0xf3, 0x5a, 0x57, 0x84, 0x17, 0x7b, 0x32,
|
||||
0x87, 0x70, 0xb2, 0xb0, 0x76, 0x9c, 0xb2, 0xc3,
|
||||
0x15, 0xd1, 0x11, 0x26, 0x2a, 0x23, 0x75, 0x99,
|
||||
0x3e, 0xb9, 0x77, 0x22, 0x32, 0x0d, 0xbc, 0x1a,
|
||||
0x19, 0xc1, 0xd5, 0x65, 0x90, 0x76, 0x55, 0x74,
|
||||
0x0f, 0x0e, 0x69, 0x4d, 0x5f, 0x4d, 0x8f, 0x19,
|
||||
0xaf, 0xdf, 0xd6, 0x16, 0x31, 0x94, 0xa8, 0x92,
|
||||
0x5f, 0x4f, 0xbc, 0x7a, 0x31, 0xf8, 0xae, 0x8e,
|
||||
0xad, 0x33, 0xb7, 0xe9, 0x30, 0xd0, 0x8c, 0x0a,
|
||||
0x8a, 0x6c, 0x83, 0x35, 0xf8, 0x8a, 0x81, 0xb2,
|
||||
0xfe, 0x1c, 0x88, 0xac, 0x2a, 0x66, 0xc5, 0xff,
|
||||
0xbd, 0xe6, 0x17, 0xd0, 0x62, 0x0b, 0xdc, 0x8a,
|
||||
0x45, 0xf7, 0xb0, 0x3e, 0x5a, 0xc8, 0x1e, 0x4a,
|
||||
0x24, 0x2f, 0x6c, 0xa5, 0xe3, 0x1c, 0x88, 0x14,
|
||||
0x83, 0xd5, 0xc5, 0xef, 0x5e, 0x9f, 0x3d, 0x85,
|
||||
0x45, 0x73, 0xe2, 0x6b, 0x50, 0x52, 0x57, 0x4c,
|
||||
0xfb, 0x92, 0x6c, 0x66, 0x75, 0x8a, 0xd6, 0x0d,
|
||||
0x1b, 0xae, 0xf3, 0xec, 0xaf, 0x51, 0x22, 0x03,
|
||||
0x5d, 0x0a, 0x2e, 0x63, 0x93, 0x9c, 0x0b, 0x01,
|
||||
0x20, 0xa8, 0xa9, 0x84, 0x2e, 0x17, 0xca, 0xae,
|
||||
0x73, 0xec, 0x22, 0x1b, 0x79, 0xae, 0xf6, 0xa0,
|
||||
0x72, 0x2c, 0xdf, 0x07, 0x47, 0xdb, 0x88, 0x86,
|
||||
0x30, 0x14, 0x78, 0x21, 0x11, 0x22, 0x88, 0xac,
|
||||
0xd7, 0x54, 0x74, 0xf9, 0xf3, 0x26, 0xc2, 0xa5,
|
||||
0x56, 0xc8, 0x56, 0x4f, 0x00, 0x29, 0x1d, 0x08,
|
||||
0x7b, 0x7a, 0xfb, 0x95, 0x89, 0xc3, 0xee, 0x98,
|
||||
0x54, 0x9e, 0x3c, 0x6b, 0x94, 0x05, 0x13, 0x12,
|
||||
0xf6, 0x71, 0xb9, 0xab, 0x13, 0xc3, 0x0c, 0x9b,
|
||||
0x46, 0x08, 0x7b, 0x3d, 0x32, 0x6a, 0x68, 0xca,
|
||||
0x1e, 0x9c, 0x90, 0x62, 0xc5, 0xed, 0x10, 0xb9,
|
||||
0x1f, 0x17, 0x25, 0xce, 0x90, 0xb9, 0x6d, 0xcd,
|
||||
0xc4, 0x46, 0xf5, 0xa3, 0x62, 0x13, 0x74, 0x02,
|
||||
0xa7, 0x62, 0xa4, 0xfa, 0x55, 0xd9, 0xde, 0xcf,
|
||||
0xa2, 0xe6, 0x80, 0x74, 0x55, 0x06, 0x49, 0xd5,
|
||||
0x02, 0x0c
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -57,41 +126,90 @@ using video_widevine::EncryptedClientIdentification;
|
||||
using video_widevine::SignedDrmDeviceCertificate;
|
||||
using video_widevine::SignedMessage;
|
||||
|
||||
void ServiceCertificate::Clear() {
|
||||
fetch_in_progress_ = false;
|
||||
certificate_.clear();
|
||||
provider_id_.clear();
|
||||
CdmResponseType ServiceCertificate::Init(const std::string& certificate) {
|
||||
std::string root_cert_str(reinterpret_cast<const char*>(&kRootCertForProd[0]),
|
||||
sizeof(kRootCertForProd));
|
||||
|
||||
// Load root cert public key. Don't bother verifying it.
|
||||
SignedDrmDeviceCertificate signed_root_cert;
|
||||
if (!signed_root_cert.ParseFromString(root_cert_str)) {
|
||||
LOGE("Failed to deserialize signed root certificate.");
|
||||
return DEVICE_CERTIFICATE_ERROR_1;
|
||||
}
|
||||
DrmDeviceCertificate root_cert;
|
||||
if (!root_cert.ParseFromString(signed_root_cert.drm_certificate())) {
|
||||
LOGE("Failed to deserialize signed root certificate.");
|
||||
return DEVICE_CERTIFICATE_ERROR_1;
|
||||
}
|
||||
RsaPublicKey root_key;
|
||||
if (!root_key.Init(root_cert.public_key())) {
|
||||
LOGE("Failed to load root certificate public key.");
|
||||
return DEVICE_CERTIFICATE_ERROR_1;
|
||||
}
|
||||
|
||||
// Load the provided service certificate.
|
||||
// First, parse it and verify its signature.
|
||||
SignedDrmDeviceCertificate signed_service_cert;
|
||||
if (!signed_service_cert.ParseFromString(certificate)) {
|
||||
LOGE("Failed to parse signed service certificate.");
|
||||
return DEVICE_CERTIFICATE_ERROR_2;
|
||||
}
|
||||
if (!root_key.VerifySignature(signed_service_cert.drm_certificate(),
|
||||
signed_service_cert.signature())) {
|
||||
LOGE("Service certificate signature verification failed.");
|
||||
return DEVICE_CERTIFICATE_ERROR_3;
|
||||
}
|
||||
DrmDeviceCertificate service_cert;
|
||||
if (!service_cert.ParseFromString(signed_service_cert.drm_certificate())) {
|
||||
LOGE("Failed to parse service certificate.");
|
||||
return DEVICE_CERTIFICATE_ERROR_2;
|
||||
}
|
||||
if (service_cert.type() !=
|
||||
video_widevine::DrmDeviceCertificate_CertificateType_SERVICE) {
|
||||
LOGE("Not a service certificate.");
|
||||
return DEVICE_CERTIFICATE_ERROR_3;
|
||||
}
|
||||
|
||||
// Service certificate passes all checks - set up its RSA public key.
|
||||
public_key_.reset(new RsaPublicKey);
|
||||
if (!public_key_->Init(service_cert.public_key())) {
|
||||
public_key_.reset();
|
||||
LOGE("Failed to load service certificate public key.");
|
||||
return DEVICE_CERTIFICATE_ERROR_2;
|
||||
}
|
||||
|
||||
// Have service certificate and its public key - keep relevant fields.
|
||||
certificate_ = certificate;
|
||||
serial_number_ = service_cert.serial_number();
|
||||
provider_id_ = service_cert.provider_id();
|
||||
has_certificate_ = true;
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType ServiceCertificate::Init(const std::string& raw_certificate) {
|
||||
return VerifyAndExtract(raw_certificate);
|
||||
CdmResponseType ServiceCertificate::VerifySignedMessage(
|
||||
const std::string& message, const std::string& signature) {
|
||||
if (!public_key_) {
|
||||
LOGE("Service certificate not set.");
|
||||
return DEVICE_CERTIFICATE_ERROR_4;
|
||||
}
|
||||
|
||||
if (!public_key_->VerifySignature(message, signature))
|
||||
return CLIENT_ID_RSA_ENCRYPT_ERROR; // TODO(tinskip): Need new error code.
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType ServiceCertificate::EncryptClientId(
|
||||
CryptoSession* crypto_session, const ClientIdentification* clear_client_id,
|
||||
EncryptedClientIdentification* encrypted_client_id) {
|
||||
DrmDeviceCertificate service_certificate;
|
||||
|
||||
if (certificate_.empty()) {
|
||||
LOGE("ServiceCertificate::EncryptClientId: "
|
||||
"service certificate is not properly initialized");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
if (!service_certificate.ParseFromString(certificate_)) {
|
||||
LOGE("ServiceCertificate::EncryptClientId: unable to parse retrieved "
|
||||
"service certificate");
|
||||
return PARSE_SERVICE_CERTIFICATE_ERROR;
|
||||
if (!public_key_) {
|
||||
LOGE("Service certificate not set.");
|
||||
return DEVICE_CERTIFICATE_ERROR_4;
|
||||
}
|
||||
|
||||
if (service_certificate.type() !=
|
||||
video_widevine::DrmDeviceCertificate_CertificateType_SERVICE) {
|
||||
LOGE("ServiceCertificate::EncryptClientId: retrieved certificate not of "
|
||||
"type service, %d", service_certificate.type());
|
||||
return SERVICE_CERTIFICATE_TYPE_ERROR;
|
||||
}
|
||||
encrypted_client_id->set_provider_id(service_certificate.provider_id());
|
||||
encrypted_client_id->set_service_certificate_serial_number(
|
||||
service_certificate.serial_number());
|
||||
encrypted_client_id->set_provider_id(provider_id_);
|
||||
encrypted_client_id->set_service_certificate_serial_number(serial_number_);
|
||||
|
||||
std::string iv(KEY_IV_SIZE, 0);
|
||||
std::string key(KEY_SIZE, 0);
|
||||
@@ -109,10 +227,8 @@ CdmResponseType ServiceCertificate::EncryptClientId(
|
||||
if (!aes.Init(key)) return CLIENT_ID_AES_INIT_ERROR;
|
||||
if (!aes.Encrypt(id, &enc_id, &iv)) return CLIENT_ID_AES_ENCRYPT_ERROR;
|
||||
|
||||
RsaPublicKey rsa;
|
||||
if (!rsa.Init(service_certificate.public_key()))
|
||||
return CLIENT_ID_RSA_INIT_ERROR;
|
||||
if (!rsa.Encrypt(key, &enc_key)) return CLIENT_ID_RSA_ENCRYPT_ERROR;
|
||||
if (!public_key_->Encrypt(key, &enc_key))
|
||||
return CLIENT_ID_RSA_ENCRYPT_ERROR;
|
||||
|
||||
encrypted_client_id->set_encrypted_client_id_iv(iv);
|
||||
encrypted_client_id->set_encrypted_privacy_key(enc_key);
|
||||
@@ -120,97 +236,4 @@ CdmResponseType ServiceCertificate::EncryptClientId(
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool ServiceCertificate::PrepareRequest(CdmKeyMessage* signed_request) {
|
||||
if (!signed_request) {
|
||||
LOGE("ServiceCertificate::PrepareRequest: no signed request provided");
|
||||
return false;
|
||||
}
|
||||
SignedMessage signed_message;
|
||||
signed_message.set_type(SignedMessage::SERVICE_CERTIFICATE_REQUEST);
|
||||
signed_message.SerializeToString(signed_request);
|
||||
|
||||
fetch_in_progress_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType ServiceCertificate::HandleResponse(
|
||||
const std::string& signed_response) {
|
||||
if (!fetch_in_progress_) {
|
||||
LOGE("ServiceCertificate::HandleResponse: unexpected service "
|
||||
"certificate response.");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
fetch_in_progress_ = false;
|
||||
CdmResponseType status = VerifyAndExtract(signed_response);
|
||||
if (status != NO_ERROR) {
|
||||
return status;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType ServiceCertificate::VerifyAndExtract(
|
||||
const std::string& raw_certificate) {
|
||||
if (raw_certificate.empty()) {
|
||||
Clear();
|
||||
return NO_ERROR;
|
||||
}
|
||||
// Deserialize and parse raw certificate.
|
||||
SignedDrmDeviceCertificate signed_service_certificate;
|
||||
if (!signed_service_certificate.ParseFromString(raw_certificate)) {
|
||||
LOGE(
|
||||
"ServiceCertificate::VerifyAndExtract: unable to parse signed "
|
||||
"service certificate");
|
||||
return DEVICE_CERTIFICATE_ERROR_1;
|
||||
}
|
||||
|
||||
// Set up root key (for verifying signature).
|
||||
RsaPublicKey root_ca_key;
|
||||
std::string ca_public_key(
|
||||
reinterpret_cast<const char*>(&kServiceCertificateCAPublicKey[0]),
|
||||
sizeof(kServiceCertificateCAPublicKey));
|
||||
if (!root_ca_key.Init(ca_public_key)) {
|
||||
LOGE(
|
||||
"ServiceCertificate::VerifyAndExtract: public key initialization "
|
||||
"failed");
|
||||
return DEVICE_CERTIFICATE_ERROR_2;
|
||||
}
|
||||
|
||||
// Verify the signature.
|
||||
if (!root_ca_key.VerifySignature(
|
||||
signed_service_certificate.drm_certificate(),
|
||||
signed_service_certificate.signature())) {
|
||||
LOGE(
|
||||
"ServiceCertificate::VerifyAndExtract: service certificate "
|
||||
"verification failed");
|
||||
return DEVICE_CERTIFICATE_ERROR_3;
|
||||
}
|
||||
|
||||
// Deserialize and parse actual certificate.
|
||||
DrmDeviceCertificate service_certificate;
|
||||
if (!service_certificate.ParseFromString(
|
||||
signed_service_certificate.drm_certificate())) {
|
||||
LOGE(
|
||||
"ServiceCertificate::VerifyAndExtract: unable to parse retrieved "
|
||||
"service certificate");
|
||||
return DEVICE_CERTIFICATE_ERROR_4;
|
||||
}
|
||||
|
||||
// Verify, extract needed fields.
|
||||
if (service_certificate.type() !=
|
||||
video_widevine::DrmDeviceCertificate_CertificateType_SERVICE) {
|
||||
LOGE(
|
||||
"ServiceCertificate::VerifyAndExtract: certificate not of type "
|
||||
"service, %d", service_certificate.type());
|
||||
return INVALID_DEVICE_CERTIFICATE_TYPE;
|
||||
}
|
||||
if (service_certificate.has_provider_id()) {
|
||||
provider_id_.assign(service_certificate.provider_id());
|
||||
} else {
|
||||
provider_id_.clear();
|
||||
}
|
||||
certificate_.assign(signed_service_certificate.drm_certificate());
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -152,16 +152,21 @@ std::vector<uint8_t> Base64Decode(const std::string& b64_input) {
|
||||
}
|
||||
|
||||
// Decode for Filename-friendly base64 encoding (RFC4648), commonly referred
|
||||
// as Base64WebSafeDecode.
|
||||
// as Base64WebSafeDecode. Add padding if needed.
|
||||
std::vector<uint8_t> Base64SafeDecode(const std::string& b64_input) {
|
||||
if (b64_input.empty()) {
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
int in_size = b64_input.size();
|
||||
std::string b64_padded(b64_input);
|
||||
while (b64_padded.size() % 4 != 0) {
|
||||
b64_padded = b64_padded + "=";
|
||||
}
|
||||
|
||||
int in_size = b64_padded.size();
|
||||
std::vector<uint8_t> bin_output(modp_b64w_decode_len(in_size), 0);
|
||||
int out_size = modp_b64w_decode(reinterpret_cast<char*>(&bin_output[0]),
|
||||
b64_input.data(), in_size);
|
||||
b64_padded.data(), in_size);
|
||||
if (out_size == -1) {
|
||||
LOGE("Base64SafeDecode failed");
|
||||
return std::vector<uint8_t>(0);
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
|
||||
#include "cdm_engine.h"
|
||||
#include "config_test_env.h"
|
||||
#include "default_service_certificate.h"
|
||||
#include "initialization_data.h"
|
||||
#include "license_request.h"
|
||||
#include "log.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "properties.h"
|
||||
#include "properties_ce.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "string_conversions.h"
|
||||
#include "test_printers.h"
|
||||
@@ -27,6 +27,7 @@
|
||||
namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
|
||||
// Http OK response code.
|
||||
const int kHttpOk = 200;
|
||||
|
||||
@@ -37,27 +38,313 @@ KeyId g_key_id_pssh;
|
||||
KeyId g_key_id_unwrapped;
|
||||
CdmKeySystem g_key_system;
|
||||
std::string g_license_server;
|
||||
std::string g_provisioning_server;
|
||||
std::string g_provisioning_service_certificate;
|
||||
std::string g_license_service_certificate;
|
||||
KeyId g_wrong_key_id;
|
||||
|
||||
const std::string kCencMimeType = "video/mp4";
|
||||
const std::string kWebmMimeType = "video/webm";
|
||||
|
||||
static void CommonSetup(ServerConfigurationId which,
|
||||
bool bin_prov = false) {
|
||||
|
||||
widevine::PropertiesCE::SetProvisioningMessagesAreBinary(bin_prov);
|
||||
Properties::Init();
|
||||
|
||||
// NOTE: Select configuration
|
||||
ConfigTestEnv config(which);
|
||||
|
||||
g_client_auth.assign(config.client_auth());
|
||||
g_key_system.assign(config.key_system());
|
||||
g_wrong_key_id.assign(config.wrong_key_id());
|
||||
g_license_server.assign(config.license_server());
|
||||
g_key_id_pssh.assign(a2bs_hex(config.key_id()));
|
||||
g_provisioning_service_certificate.assign(
|
||||
config.provisioning_service_certificate());
|
||||
g_license_service_certificate.assign(config.license_service_certificate());
|
||||
g_provisioning_server.assign(config.provisioning_server());
|
||||
|
||||
// Extract the key ID from the PSSH box.
|
||||
InitializationData extractor(CENC_INIT_DATA_FORMAT, g_key_id_pssh);
|
||||
g_key_id_unwrapped = extractor.data();
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate the portion of the server's response message that is between
|
||||
* the strings jason_start_substr and json_end_substr. Returns the string
|
||||
* through *result. If the start substring match fails, assume the entire
|
||||
* string represents a serialized protobuf mesaage and return true with
|
||||
* the entire string. If the end_substring match fails, return false with
|
||||
* an empty *result.
|
||||
*/
|
||||
bool ExtractSignedMessage(const std::string& response,
|
||||
const std::string& json_start_substr,
|
||||
const std::string& json_end_substr,
|
||||
std::string* result) {
|
||||
std::string response_string;
|
||||
size_t start = response.find(json_start_substr);
|
||||
|
||||
if (start == response.npos) {
|
||||
// Assume serialized protobuf message.
|
||||
result->assign(response);
|
||||
} else {
|
||||
// Assume JSON-wrapped protobuf.
|
||||
size_t end = response.find(json_end_substr,
|
||||
start + json_start_substr.length());
|
||||
if (end == response.npos) {
|
||||
LOGE("ExtractSignedMessage cannot locate end substring");
|
||||
result->clear();
|
||||
return false;
|
||||
}
|
||||
size_t result_string_size = end - start - json_start_substr.length();
|
||||
result->assign(response, start + json_start_substr.length(),
|
||||
result_string_size);
|
||||
}
|
||||
|
||||
if (result->empty()) {
|
||||
LOGE("ExtractSignedMessage: Response message is empty");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class WvCdmEngineTest : public testing::Test {
|
||||
class WvCdmEnginePreProvTest : public testing::Test {
|
||||
public:
|
||||
WvCdmEngineTest() : cdm_engine_(&file_system_) {}
|
||||
WvCdmEnginePreProvTest() : cdm_engine_(&file_system_),
|
||||
session_opened_(false) {}
|
||||
|
||||
virtual ~WvCdmEnginePreProvTest() {}
|
||||
|
||||
virtual void SetUp() {
|
||||
CdmResponseType status =
|
||||
cdm_engine_.OpenSession(g_key_system, NULL, NULL, &session_id_);
|
||||
ASSERT_EQ(status, NO_ERROR);
|
||||
session_opened_ = true;
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
if (session_opened_) {
|
||||
cdm_engine_.CloseSession(session_id_);
|
||||
session_opened_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Trade request for response via the license server.
|
||||
virtual bool LicenseServerRequestResponse(const std::string& request,
|
||||
std::string* response) {
|
||||
LOGV("LicenseServerRequestResponse: server url: %s",
|
||||
g_license_server.c_str());
|
||||
UrlRequest url_request(g_license_server + g_client_auth);
|
||||
url_request.PostRequest(request);
|
||||
|
||||
std::string http_response;
|
||||
if (!url_request.GetResponse(&http_response)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LOGV("http_response:\n%s\n", http_response.c_str());
|
||||
|
||||
// Separate message from HTTP headers.
|
||||
LicenseRequest license_request;
|
||||
license_request.GetDrmMessage(http_response, *response);
|
||||
|
||||
LOGV("response: size=%u, string:\n%s\n", response->size(),
|
||||
Base64SafeEncode(std::vector<uint8_t>(response->begin(),
|
||||
response->end())).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void Provision() {
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: url=%s",
|
||||
g_provisioning_server.c_str());
|
||||
CdmProvisioningRequest prov_request;
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority;
|
||||
std::string cert, wrapped_key;
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.SetServiceCertificate(
|
||||
g_provisioning_service_certificate));
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.GetProvisioningRequest(
|
||||
cert_type, cert_authority, &prov_request,
|
||||
&provisioning_server_url));
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: req=%s", prov_request.c_str());
|
||||
|
||||
// Ignore URL provided by CdmEngine. Use ours, as configured
|
||||
// for test vs. production server.
|
||||
provisioning_server_url.assign(g_provisioning_server);
|
||||
UrlRequest url_request(provisioning_server_url);
|
||||
EXPECT_TRUE(url_request.is_connected());
|
||||
url_request.PostCertRequestInQueryString(prov_request);
|
||||
std::string http_message;
|
||||
bool ok = url_request.GetResponse(&http_message);
|
||||
EXPECT_TRUE(ok);
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: http_message: \n%s\n",
|
||||
http_message.c_str());
|
||||
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
cdm_engine_.HandleProvisioningResponse(http_message,
|
||||
&cert, &wrapped_key));
|
||||
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
cdm_engine_.SetServiceCertificate(g_license_service_certificate));
|
||||
}
|
||||
|
||||
FileSystem file_system_;
|
||||
CdmEngine cdm_engine_;
|
||||
bool session_opened_;
|
||||
std::string key_msg_;
|
||||
std::string session_id_;
|
||||
};
|
||||
|
||||
class WvCdmEnginePreProvTestStaging : public WvCdmEnginePreProvTest {
|
||||
public:
|
||||
WvCdmEnginePreProvTestStaging() {}
|
||||
|
||||
virtual ~WvCdmEnginePreProvTestStaging() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
ConfigTestEnv config(kContentProtectionUatServer);
|
||||
g_client_auth.assign(config.client_auth());
|
||||
g_key_system.assign(config.key_system());
|
||||
g_wrong_key_id.assign(config.wrong_key_id());
|
||||
g_license_server.assign(config.license_server());
|
||||
g_key_id_pssh.assign(a2bs_hex(config.key_id()));
|
||||
// NOTE: Select server configuration
|
||||
CommonSetup(kContentProtectionStagingLicense);
|
||||
}
|
||||
};
|
||||
|
||||
// Extract the key ID from the PSSH box.
|
||||
InitializationData extractor(CENC_INIT_DATA_FORMAT, g_key_id_pssh);
|
||||
g_key_id_unwrapped = extractor.data();
|
||||
class WvCdmEnginePreProvTestProd : public WvCdmEnginePreProvTest {
|
||||
public:
|
||||
WvCdmEnginePreProvTestProd() {}
|
||||
|
||||
virtual ~WvCdmEnginePreProvTestProd() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
// NOTE: Select server configuration
|
||||
CommonSetup(kContentProtectionProdLicense);
|
||||
}
|
||||
};
|
||||
|
||||
class WvCdmEnginePreProvTestUat : public WvCdmEnginePreProvTest {
|
||||
public:
|
||||
WvCdmEnginePreProvTestUat() {}
|
||||
|
||||
virtual ~WvCdmEnginePreProvTestUat() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
// NOTE: Select server configuration
|
||||
CommonSetup(kContentProtectionUatLicense);
|
||||
}
|
||||
};
|
||||
|
||||
class WvCdmEnginePreProvTestStagingProv30 : public WvCdmEnginePreProvTest {
|
||||
public:
|
||||
WvCdmEnginePreProvTestStagingProv30() {}
|
||||
|
||||
virtual ~WvCdmEnginePreProvTestStagingProv30() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
// NOTE: Select server configuration
|
||||
CommonSetup(kContentProtectionStagingPlusProv30);
|
||||
}
|
||||
};
|
||||
|
||||
class WvCdmEnginePreProvTestStagingProv30Binary : public WvCdmEnginePreProvTest {
|
||||
public:
|
||||
WvCdmEnginePreProvTestStagingProv30Binary() {}
|
||||
|
||||
virtual ~WvCdmEnginePreProvTestStagingProv30Binary() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
// NOTE: Select server configuration
|
||||
// Override default setting of provisioning_messages_are_binary property
|
||||
CommonSetup(kContentProtectionUatPlusProv30, true);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
virtual void Provision() {
|
||||
LOGV("WvCdmEnginePreProvTestProv30Binary::Provision: url=%s",
|
||||
g_provisioning_server.c_str());
|
||||
CdmProvisioningRequest binary_prov_request;
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority;
|
||||
std::string cert, wrapped_key;
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.SetServiceCertificate(
|
||||
g_provisioning_service_certificate));
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.GetProvisioningRequest(
|
||||
cert_type, cert_authority, &binary_prov_request,
|
||||
&provisioning_server_url));
|
||||
|
||||
// prov_request is binary - base64 encode it
|
||||
std::string prov_request(Base64SafeEncodeNoPad(
|
||||
std::vector<uint8_t>(binary_prov_request.begin(),
|
||||
binary_prov_request.end())));
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: req=%s", prov_request.c_str());
|
||||
|
||||
// Ignore URL provided by CdmEngine. Use ours, as configured
|
||||
// for test vs. production server.
|
||||
provisioning_server_url.assign(g_provisioning_server);
|
||||
UrlRequest url_request(provisioning_server_url);
|
||||
EXPECT_TRUE(url_request.is_connected());
|
||||
url_request.PostCertRequestInQueryString(prov_request);
|
||||
std::string http_message;
|
||||
bool ok = url_request.GetResponse(&http_message);
|
||||
EXPECT_TRUE(ok);
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: http_message: \n%s\n",
|
||||
http_message.c_str());
|
||||
|
||||
// extract provisioning response from received message
|
||||
// Extracts signed response from JSON string, result is serialized protobuf.
|
||||
const std::string kMessageStart = "\"signedResponse\": \"";
|
||||
const std::string kMessageEnd = "\"";
|
||||
std::string protobuf_response;
|
||||
EXPECT_TRUE (ExtractSignedMessage(http_message, kMessageStart, kMessageEnd,
|
||||
&protobuf_response)) <<
|
||||
"Failed to extract signed serialized response from JSON response";
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: extracted response "
|
||||
"message: \n%s\n", protobuf_response.c_str());
|
||||
|
||||
// base64 decode response to yield binary protobuf
|
||||
std::vector<uint8_t> response_vec(Base64SafeDecode(
|
||||
std::string(protobuf_response.begin(), protobuf_response.end())));
|
||||
std::string binary_protobuf_response(response_vec.begin(),
|
||||
response_vec.end());
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
cdm_engine_.HandleProvisioningResponse(binary_protobuf_response,
|
||||
&cert, &wrapped_key));
|
||||
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
cdm_engine_.SetServiceCertificate(g_license_service_certificate));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class WvCdmEnginePreProvTestUatProv30 : public WvCdmEnginePreProvTest {
|
||||
public:
|
||||
WvCdmEnginePreProvTestUatProv30() {}
|
||||
|
||||
virtual ~WvCdmEnginePreProvTestUatProv30() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
// NOTE: Select server configuration
|
||||
CommonSetup(kContentProtectionStagingPlusProv30);
|
||||
}
|
||||
};
|
||||
|
||||
class WvCdmEngineTest : public WvCdmEnginePreProvTest {
|
||||
public:
|
||||
WvCdmEngineTest() {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
// NOTE: Select server configuration
|
||||
CommonSetup(kContentProtectionStagingLicense);
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
@@ -72,29 +359,7 @@ class WvCdmEngineTest : public testing::Test {
|
||||
ASSERT_TRUE(cdm_engine_.IsOpenSession(session_id_));
|
||||
}
|
||||
|
||||
virtual void TearDown() { cdm_engine_.CloseSession(session_id_); }
|
||||
|
||||
protected:
|
||||
void Provision() {
|
||||
CdmProvisioningRequest prov_request;
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority;
|
||||
std::string cert, wrapped_key;
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.SetServiceCertificate(
|
||||
kDefaultServiceCertificate));
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.GetProvisioningRequest(
|
||||
cert_type, cert_authority, &prov_request,
|
||||
&provisioning_server_url));
|
||||
UrlRequest url_request(provisioning_server_url);
|
||||
EXPECT_TRUE(url_request.is_connected());
|
||||
url_request.PostCertRequestInQueryString(prov_request);
|
||||
std::string message;
|
||||
bool ok = url_request.GetResponse(&message);
|
||||
EXPECT_TRUE(ok);
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.HandleProvisioningResponse(message, &cert,
|
||||
&wrapped_key));
|
||||
}
|
||||
|
||||
void GenerateKeyRequest(const std::string& key_id,
|
||||
const std::string& init_data_type_string) {
|
||||
@@ -138,6 +403,9 @@ class WvCdmEngineTest : public testing::Test {
|
||||
const std::string& client_auth,
|
||||
bool expect_success) {
|
||||
// Use secure connection and chunk transfer coding.
|
||||
|
||||
LOGV("GetKeyRequestResponse: server_url: %s", server_url.c_str());
|
||||
|
||||
UrlRequest url_request(server_url + client_auth);
|
||||
if (!url_request.is_connected()) {
|
||||
return "";
|
||||
@@ -146,7 +414,7 @@ class WvCdmEngineTest : public testing::Test {
|
||||
url_request.PostRequest(key_msg_);
|
||||
std::string response;
|
||||
bool ok = url_request.GetResponse(&response);
|
||||
LOGD("response: %s\n", response.c_str());
|
||||
LOGV("response: %s\n", response.c_str());
|
||||
EXPECT_TRUE(ok);
|
||||
|
||||
int status_code = url_request.GetStatusCode(response);
|
||||
@@ -180,37 +448,147 @@ class WvCdmEngineTest : public testing::Test {
|
||||
EXPECT_EQ(KEY_ADDED, cdm_engine_.RenewKey(session_id_, resp));
|
||||
}
|
||||
|
||||
FileSystem file_system_;
|
||||
CdmEngine cdm_engine_;
|
||||
std::string key_msg_;
|
||||
std::string session_id_;
|
||||
std::string server_url_;
|
||||
};
|
||||
|
||||
// Test that provisioning works, even if device is already provisioned.
|
||||
TEST_F(WvCdmEngineTest, ProvisioningTest) {
|
||||
// Test that service certificate is initially absent.
|
||||
TEST_F(WvCdmEnginePreProvTestStaging, ServiceCertificateInitialNoneTest) {
|
||||
ASSERT_FALSE(cdm_engine_.HasServiceCertificate());
|
||||
};
|
||||
|
||||
// Test that service certificate can be properly installed.
|
||||
TEST_F(WvCdmEnginePreProvTestStaging, ServiceCertificateGoodTest) {
|
||||
ASSERT_EQ(cdm_engine_.SetServiceCertificate(g_license_service_certificate),
|
||||
NO_ERROR);
|
||||
ASSERT_TRUE(cdm_engine_.HasServiceCertificate());
|
||||
};
|
||||
|
||||
// Test that service certificate can be retrieved from the license server.
|
||||
TEST_F(WvCdmEnginePreProvTestStaging, ServiceCertificateRequestResponse) {
|
||||
CdmKeyMessage request;
|
||||
std::string certificate;
|
||||
|
||||
// Initial condition - no service certificate.
|
||||
ASSERT_FALSE(cdm_engine_.HasServiceCertificate());
|
||||
|
||||
// Generate request.
|
||||
// The request will be a serialized protobuf message.
|
||||
ASSERT_TRUE(cdm_engine_.GetServiceCertificateRequest(&request));
|
||||
|
||||
std::string response;
|
||||
ASSERT_TRUE(LicenseServerRequestResponse(request, &response));
|
||||
|
||||
// Extract the service certificate
|
||||
ASSERT_EQ(cdm_engine_.ParseServiceCertificateResponse(response, &certificate),
|
||||
NO_ERROR);
|
||||
|
||||
ASSERT_TRUE(cdm_engine_.HasServiceCertificate());
|
||||
LOGV("ret'd service certificate:\n%s\n", b2a_hex(certificate).c_str());
|
||||
};
|
||||
|
||||
// Test that service certificate can be retrieved from the license server.
|
||||
TEST_F(WvCdmEnginePreProvTestUat, ServiceCertificateRequestResponse) {
|
||||
CdmKeyMessage request;
|
||||
std::string certificate;
|
||||
|
||||
// Initial condition - no service certificate.
|
||||
ASSERT_FALSE(cdm_engine_.HasServiceCertificate());
|
||||
|
||||
// Generate request.
|
||||
// The request will be a serialized protobuf message.
|
||||
ASSERT_TRUE(cdm_engine_.GetServiceCertificateRequest(&request));
|
||||
|
||||
std::string response;
|
||||
ASSERT_TRUE(LicenseServerRequestResponse(request, &response));
|
||||
|
||||
// Extract the service certificate
|
||||
ASSERT_EQ(cdm_engine_.ParseServiceCertificateResponse(response, &certificate),
|
||||
NO_ERROR);
|
||||
|
||||
ASSERT_TRUE(cdm_engine_.HasServiceCertificate());
|
||||
LOGV("ret'd service certificate:\n%s\n", b2a_hex(certificate).c_str());
|
||||
};
|
||||
|
||||
// Test that service certificate can be retrieved from the license server.
|
||||
TEST_F(WvCdmEnginePreProvTestProd, ServiceCertificateRequestResponse) {
|
||||
CdmKeyMessage request;
|
||||
std::string certificate;
|
||||
|
||||
// Initial condition - no service certificate.
|
||||
ASSERT_FALSE(cdm_engine_.HasServiceCertificate());
|
||||
|
||||
// Generate request.
|
||||
// The request will be a serialized protobuf message.
|
||||
ASSERT_TRUE(cdm_engine_.GetServiceCertificateRequest(&request));
|
||||
|
||||
std::string response;
|
||||
ASSERT_TRUE(LicenseServerRequestResponse(request, &response));
|
||||
|
||||
// Extract the service certificate
|
||||
ASSERT_EQ(cdm_engine_.ParseServiceCertificateResponse(response, &certificate),
|
||||
NO_ERROR);
|
||||
|
||||
ASSERT_TRUE(cdm_engine_.HasServiceCertificate());
|
||||
LOGV("ret'd service certificate:\n%s\n", b2a_hex(certificate).c_str());
|
||||
};
|
||||
|
||||
// Test that empty service certificate fails.
|
||||
TEST_F(WvCdmEnginePreProvTestStaging, ServiceCertificateEmptyFailTest) {
|
||||
std::string empty_cert;
|
||||
ASSERT_EQ(cdm_engine_.SetServiceCertificate(g_license_service_certificate),
|
||||
NO_ERROR);
|
||||
ASSERT_TRUE(cdm_engine_.HasServiceCertificate());
|
||||
};
|
||||
|
||||
TEST_F(WvCdmEnginePreProvTestStaging, ProvisioningTest) {
|
||||
uint32_t nonce = 0;
|
||||
uint8_t buffer[1];
|
||||
size_t size = 0;
|
||||
|
||||
int result = OEMCrypto_RewrapDeviceRSAKey(
|
||||
0, buffer, 0, buffer, 0, &nonce, buffer, 0, buffer, buffer, &size);
|
||||
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
int result30 = OEMCrypto_RewrapDeviceRSAKey30(
|
||||
0, &nonce, buffer, 0, buffer, 0, buffer, buffer, &size);
|
||||
int method = OEMCrypto_GetProvisioningMethod(kLevelDefault);
|
||||
|
||||
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED &&
|
||||
result30 == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
LOGW("WARNING: Skipping ProvisioningTest because the device does not "
|
||||
"support provisioning. If you are using a baked-in certificate, this "
|
||||
"is expected. Otherwise, something is wrong.");
|
||||
return;
|
||||
"support provisioning. If you are using a baked-in certificate, "
|
||||
"this is expected. Otherwise, something is wrong.");
|
||||
ASSERT_EQ(method, OEMCrypto_DrmCertificate);
|
||||
} else {
|
||||
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
|
||||
ASSERT_EQ(method, OEMCrypto_OEMCertificate);
|
||||
} else {
|
||||
ASSERT_EQ(method, OEMCrypto_Keybox);
|
||||
}
|
||||
}
|
||||
|
||||
Provision();
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEnginePreProvTestStagingProv30, ProvisioningTest) {
|
||||
Provision();
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEnginePreProvTestStagingProv30Binary, ProvisioningTest) {
|
||||
Provision();
|
||||
}
|
||||
|
||||
// Test that provisioning works, even if device is already provisioned.
|
||||
TEST_F(WvCdmEngineTest, ProvisioningTest) {
|
||||
|
||||
Provision();
|
||||
}
|
||||
|
||||
TEST_F(WvCdmEngineTest, BaseIsoBmffMessageTest) {
|
||||
GenerateKeyRequest(g_key_id_pssh, kCencMimeType);
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||
}
|
||||
|
||||
// TODO(juce): Set up with correct test data.
|
||||
TEST_F(WvCdmEngineTest, BaseWebmMessageTest) {
|
||||
TEST_F(WvCdmEngineTest, DISABLED_BaseWebmMessageTest) {
|
||||
GenerateKeyRequest(g_key_id_unwrapped, kWebmMimeType);
|
||||
GetKeyRequestResponse(g_license_server, g_client_auth);
|
||||
}
|
||||
@@ -230,7 +608,7 @@ TEST_F(WvCdmEngineTest, NormalDecryptionIsoBmff) {
|
||||
}
|
||||
|
||||
// TODO(juce): Set up with correct test data.
|
||||
TEST_F(WvCdmEngineTest, NormalDecryptionWebm) {
|
||||
TEST_F(WvCdmEngineTest, DISABLED_NormalDecryptionWebm) {
|
||||
GenerateKeyRequest(g_key_id_unwrapped, kWebmMimeType);
|
||||
VerifyNewKeyResponse(g_license_server, g_client_auth);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
@@ -176,7 +177,7 @@ TEST_F(CdmSessionTest, InitWithBuiltInCertificate) {
|
||||
EXPECT_CALL(*crypto_session_, GetPreProvisionTokenType())
|
||||
.WillOnce(Return(kClientTokenDrmCert));
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull(),
|
||||
NotNull(), NotNull()))
|
||||
NotNull(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||
@@ -206,7 +207,7 @@ TEST_F(CdmSessionTest, InitWithCertificate) {
|
||||
.WillOnce(Return(kClientTokenKeybox));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull(),
|
||||
NotNull(), NotNull()))
|
||||
NotNull(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||
@@ -260,7 +261,7 @@ TEST_F(CdmSessionTest, ReInitFail) {
|
||||
.WillOnce(Return(kClientTokenKeybox));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull(),
|
||||
NotNull(), NotNull()))
|
||||
NotNull(), _))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||
@@ -299,7 +300,7 @@ TEST_F(CdmSessionTest, InitNeedsProvisioning) {
|
||||
.WillOnce(Return(kClientTokenKeybox));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull(),
|
||||
NotNull(), NotNull()))
|
||||
NotNull(), _))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
Properties::set_use_certificates_as_identification(true);
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "config_test_env.h"
|
||||
#include "string_conversions.h"
|
||||
|
||||
// Holds the data needed to talk to the various provisioning and
|
||||
// license servers.
|
||||
//
|
||||
// Define a series of configurations, and specify the specific
|
||||
// data items needed for that configuration.
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
@@ -8,9 +15,100 @@ namespace {
|
||||
|
||||
const std::string kWidevineKeySystem = "com.widevine.alpha";
|
||||
|
||||
// For staging servers
|
||||
// NOTE: This matches the service cert returned by the staging
|
||||
// server. This is the one that the staging provisioning server uses.
|
||||
// NOTE: Provider ID = license.widevine.com
|
||||
const std::string kStagingServiceCertificate =
|
||||
"0ac102080312101705b917cc1204868b06333a2f772a8c1882b482920522"
|
||||
"8e023082010a028201010099ed5b3b327dab5e24efc3b62a95b598520ad5"
|
||||
"bccb37503e0645b814d876b8df40510441ad8ce3adb11bb88c4e725a5e4a"
|
||||
"9e0795291d58584023a7e1af0e38a91279393008610b6f158c878c7e21bf"
|
||||
"fbfeea77e1019e1e5781e8a45f46263d14e60e8058a8607adce04fac8457"
|
||||
"b137a8d67ccdeb33705d983a21fb4eecbd4a10ca47490ca47eaa5d438218"
|
||||
"ddbaf1cade3392f13d6ffb6442fd31e1bf40b0c604d1c4ba4c9520a4bf97"
|
||||
"eebd60929afceef55bbaf564e2d0e76cd7c55c73a082b996120b8359edce"
|
||||
"24707082680d6f67c6d82c4ac5f3134490a74eec37af4b2f010c59e82843"
|
||||
"e2582f0b6b9f5db0fc5e6edf64fbd308b4711bcf1250019c9f5a09020301"
|
||||
"00013a146c6963656e73652e7769646576696e652e636f6d128003ae3473"
|
||||
"14b5a835297f271388fb7bb8cb5277d249823cddd1da30b93339511eb3cc"
|
||||
"bdea04b944b927c121346efdbdeac9d413917e6ec176a10438460a503bc1"
|
||||
"952b9ba4e4ce0fc4bfc20a9808aaaf4bfcd19c1dcfcdf574ccac28d1b410"
|
||||
"416cf9de8804301cbdb334cafcd0d40978423a642e54613df0afcf96ca4a"
|
||||
"9249d855e42b3a703ef1767f6a9bd36d6bf82be76bbf0cba4fde59d2abcc"
|
||||
"76feb64247b85c431fbca52266b619fc36979543fca9cbbdbbfafa0e1a55"
|
||||
"e755a3c7bce655f9646f582ab9cf70aa08b979f867f63a0b2b7fdb362c5b"
|
||||
"c4ecd555d85bcaa9c593c383c857d49daab77e40b7851ddfd24998808e35"
|
||||
"b258e75d78eac0ca16f7047304c20d93ede4e8ff1c6f17e6243e3f3da8fc"
|
||||
"1709870ec45fba823a263f0cefa1f7093b1909928326333705043a29bda6"
|
||||
"f9b4342cc8df543cb1a1182f7c5fff33f10490faca5b25360b76015e9c5a"
|
||||
"06ab8ee02f00d2e8d5986104aacc4dd475fd96ee9ce4e326f21b83c70585"
|
||||
"77b38732cddabc6a6bed13fb0d49d38a45eb87a5f4";
|
||||
|
||||
// NOTE: Provider ID = staging.google.com
|
||||
const std::string kProdServiceCertificate =
|
||||
"0ABF020803121028703454C008F63618ADE7443DB6C4C8188BE7F9900522"
|
||||
"8E023082010A0282010100B52112B8D05D023FCC5D95E2C251C1C649B417"
|
||||
"7CD8D2BEEF355BB06743DE661E3D2ABC3182B79946D55FDC08DFE9540781"
|
||||
"5E9A6274B322A2C7F5E067BB5F0AC07A89D45AEA94B2516F075B66EF811D"
|
||||
"0D26E1B9A6B894F2B9857962AA171C4F66630D3E4C602718897F5E1EF9B6"
|
||||
"AAF5AD4DBA2A7E14176DF134A1D3185B5A218AC05A4C41F081EFFF80A3A0"
|
||||
"40C50B09BBC740EEDCD8F14D675A91980F92CA7DDC646A06ADAD5101F74A"
|
||||
"0E498CC01F00532BAC217850BD905E90923656B7DFEFEF42486767F33EF6"
|
||||
"283D4F4254AB72589390BEE55808F1D668080D45D893C2BCA2F74D60A0C0"
|
||||
"D0A0993CEF01604703334C3638139486BC9DAF24FD67A07F9AD943020301"
|
||||
"00013A1273746167696E672E676F6F676C652E636F6D128003983E303526"
|
||||
"75F40BA715FC249BDAE5D4AC7249A2666521E43655739529721FF880E0AA"
|
||||
"EFC5E27BC980DAEADABF3FC386D084A02C82537848CC753FF497B011A7DA"
|
||||
"97788A00E2AA6B84CD7D71C07A48EBF61602CCA5A3F32030A7295C30DA91"
|
||||
"5B91DC18B9BC9593B8DE8BB50F0DEDC12938B8E9E039CDDE18FA82E81BB0"
|
||||
"32630FE955D85A566CE154300BF6D4C1BD126966356B287D657B18CE63D0"
|
||||
"EFD45FC5269E97EAB11CB563E55643B26FF49F109C2101AFCAF35B832F28"
|
||||
"8F0D9D45960E259E85FB5D24DBD2CF82764C5DD9BF727EFBE9C861F86932"
|
||||
"1F6ADE18905F4D92F9A6DA6536DB8475871D168E870BB2303CF70C6E9784"
|
||||
"C93D2DE845AD8262BE7E0D4E2E4A0759CEF82D109D2592C72429F8C01742"
|
||||
"BAE2B3DECADBC33C3E5F4BAF5E16ECB74EADBAFCB7C6705F7A9E3B6F3940"
|
||||
"383F9C5116D202A20C9229EE969C2519718303B50D0130C3352E06B014D8"
|
||||
"38540F8A0C227C0011E0F5B38E4E298ED2CB301EB4564965F55C5D79757A"
|
||||
"250A4EB9C84AB3E6539F6B6FDF56899EA29914";
|
||||
|
||||
// For UAT License servers
|
||||
// NOTE: This matches the service cert returned by the UAT server.
|
||||
// NOTE: Provider ID = staging.google.com
|
||||
const std::string kUatServiceCertificate =
|
||||
"0ABF020803121028703454C008F63618ADE7443DB6C4C8188BE7F9900522"
|
||||
"8E023082010A0282010100B52112B8D05D023FCC5D95E2C251C1C649B417"
|
||||
"7CD8D2BEEF355BB06743DE661E3D2ABC3182B79946D55FDC08DFE9540781"
|
||||
"5E9A6274B322A2C7F5E067BB5F0AC07A89D45AEA94B2516F075B66EF811D"
|
||||
"0D26E1B9A6B894F2B9857962AA171C4F66630D3E4C602718897F5E1EF9B6"
|
||||
"AAF5AD4DBA2A7E14176DF134A1D3185B5A218AC05A4C41F081EFFF80A3A0"
|
||||
"40C50B09BBC740EEDCD8F14D675A91980F92CA7DDC646A06ADAD5101F74A"
|
||||
"0E498CC01F00532BAC217850BD905E90923656B7DFEFEF42486767F33EF6"
|
||||
"283D4F4254AB72589390BEE55808F1D668080D45D893C2BCA2F74D60A0C0"
|
||||
"D0A0993CEF01604703334C3638139486BC9DAF24FD67A07F9AD943020301"
|
||||
"00013A1273746167696E672E676F6F676C652E636F6D128003983E303526"
|
||||
"75F40BA715FC249BDAE5D4AC7249A2666521E43655739529721FF880E0AA"
|
||||
"EFC5E27BC980DAEADABF3FC386D084A02C82537848CC753FF497B011A7DA"
|
||||
"97788A00E2AA6B84CD7D71C07A48EBF61602CCA5A3F32030A7295C30DA91"
|
||||
"5B91DC18B9BC9593B8DE8BB50F0DEDC12938B8E9E039CDDE18FA82E81BB0"
|
||||
"32630FE955D85A566CE154300BF6D4C1BD126966356B287D657B18CE63D0"
|
||||
"EFD45FC5269E97EAB11CB563E55643B26FF49F109C2101AFCAF35B832F28"
|
||||
"8F0D9D45960E259E85FB5D24DBD2CF82764C5DD9BF727EFBE9C861F86932"
|
||||
"1F6ADE18905F4D92F9A6DA6536DB8475871D168E870BB2303CF70C6E9784"
|
||||
"C93D2DE845AD8262BE7E0D4E2E4A0759CEF82D109D2592C72429F8C01742"
|
||||
"BAE2B3DECADBC33C3E5F4BAF5E16ECB74EADBAFCB7C6705F7A9E3B6F3940"
|
||||
"383F9C5116D202A20C9229EE969C2519718303B50D0130C3352E06B014D8"
|
||||
"38540F8A0C227C0011E0F5B38E4E298ED2CB301EB4564965F55C5D79757A"
|
||||
"250A4EB9C84AB3E6539F6B6FDF56899EA29914";
|
||||
|
||||
// Content Protection license server (Production) data
|
||||
const std::string kCpProdLicenseServer =
|
||||
"https://widevine-proxy.appspot.com/proxy";
|
||||
|
||||
// Content Protection license server (UAT) data
|
||||
const std::string kCpUatLicenseServer =
|
||||
"http://widevine-proxy.appspot.com/proxy";
|
||||
"https://proxy.uat.widevine.com/proxy";
|
||||
|
||||
const std::string kCpClientAuth = "";
|
||||
const std::string kCpKeyId =
|
||||
"00000042" // blob size
|
||||
@@ -31,52 +129,10 @@ const std::string kCpOfflineKeyId =
|
||||
// pssh data:
|
||||
"08011a0d7769646576696e655f746573"
|
||||
"74220d6f66666c696e655f636c697032";
|
||||
const std::string kCpUatServiceCertificate =
|
||||
"0ABF020803121028703454C008F63618ADE7443DB6C4C8188BE7F99005228E023082010A02"
|
||||
"82010100B52112B8D05D023FCC5D95E2C251C1C649B4177CD8D2BEEF355BB06743DE661E3D"
|
||||
"2ABC3182B79946D55FDC08DFE95407815E9A6274B322A2C7F5E067BB5F0AC07A89D45AEA94"
|
||||
"B2516F075B66EF811D0D26E1B9A6B894F2B9857962AA171C4F66630D3E4C602718897F5E1E"
|
||||
"F9B6AAF5AD4DBA2A7E14176DF134A1D3185B5A218AC05A4C41F081EFFF80A3A040C50B09BB"
|
||||
"C740EEDCD8F14D675A91980F92CA7DDC646A06ADAD5101F74A0E498CC01F00532BAC217850"
|
||||
"BD905E90923656B7DFEFEF42486767F33EF6283D4F4254AB72589390BEE55808F1D668080D"
|
||||
"45D893C2BCA2F74D60A0C0D0A0993CEF01604703334C3638139486BC9DAF24FD67A07F9AD9"
|
||||
"4302030100013A1273746167696E672E676F6F676C652E636F6D128003983E30352675F40B"
|
||||
"A715FC249BDAE5D4AC7249A2666521E43655739529721FF880E0AAEFC5E27BC980DAEADABF"
|
||||
"3FC386D084A02C82537848CC753FF497B011A7DA97788A00E2AA6B84CD7D71C07A48EBF616"
|
||||
"02CCA5A3F32030A7295C30DA915B91DC18B9BC9593B8DE8BB50F0DEDC12938B8E9E039CDDE"
|
||||
"18FA82E81BB032630FE955D85A566CE154300BF6D4C1BD126966356B287D657B18CE63D0EF"
|
||||
"D45FC5269E97EAB11CB563E55643B26FF49F109C2101AFCAF35B832F288F0D9D45960E259E"
|
||||
"85FB5D24DBD2CF82764C5DD9BF727EFBE9C861F869321F6ADE18905F4D92F9A6DA6536DB84"
|
||||
"75871D168E870BB2303CF70C6E9784C93D2DE845AD8262BE7E0D4E2E4A0759CEF82D109D25"
|
||||
"92C72429F8C01742BAE2B3DECADBC33C3E5F4BAF5E16ECB74EADBAFCB7C6705F7A9E3B6F39"
|
||||
"40383F9C5116D202A20C9229EE969C2519718303B50D0130C3352E06B014D838540F8A0C22"
|
||||
"7C0011E0F5B38E4E298ED2CB301EB4564965F55C5D79757A250A4EB9C84AB3E6539F6B6FDF"
|
||||
"56899EA29914";
|
||||
|
||||
// Content Protection license server (staging) data
|
||||
const std::string kCpStagingLicenseServer =
|
||||
"http://wv-staging-proxy.appspot.com/proxy";
|
||||
const std::string kCpStagingServiceCertificate =
|
||||
"0AC102080312101705B917CC1204868B06333A2F772A8C1882B4829205228E023082010A02"
|
||||
"8201010099ED5B3B327DAB5E24EFC3B62A95B598520AD5BCCB37503E0645B814D876B8DF40"
|
||||
"510441AD8CE3ADB11BB88C4E725A5E4A9E0795291D58584023A7E1AF0E38A9127939300861"
|
||||
"0B6F158C878C7E21BFFBFEEA77E1019E1E5781E8A45F46263D14E60E8058A8607ADCE04FAC"
|
||||
"8457B137A8D67CCDEB33705D983A21FB4EECBD4A10CA47490CA47EAA5D438218DDBAF1CADE"
|
||||
"3392F13D6FFB6442FD31E1BF40B0C604D1C4BA4C9520A4BF97EEBD60929AFCEEF55BBAF564"
|
||||
"E2D0E76CD7C55C73A082B996120B8359EDCE24707082680D6F67C6D82C4AC5F3134490A74E"
|
||||
"EC37AF4B2F010C59E82843E2582F0B6B9F5DB0FC5E6EDF64FBD308B4711BCF1250019C9F5A"
|
||||
"0902030100013A146C6963656E73652E7769646576696E652E636F6D128003AE347314B5A8"
|
||||
"35297F271388FB7BB8CB5277D249823CDDD1DA30B93339511EB3CCBDEA04B944B927C12134"
|
||||
"6EFDBDEAC9D413917E6EC176A10438460A503BC1952B9BA4E4CE0FC4BFC20A9808AAAF4BFC"
|
||||
"D19C1DCFCDF574CCAC28D1B410416CF9DE8804301CBDB334CAFCD0D40978423A642E54613D"
|
||||
"F0AFCF96CA4A9249D855E42B3A703EF1767F6A9BD36D6BF82BE76BBF0CBA4FDE59D2ABCC76"
|
||||
"FEB64247B85C431FBCA52266B619FC36979543FCA9CBBDBBFAFA0E1A55E755A3C7BCE655F9"
|
||||
"646F582AB9CF70AA08B979F867F63A0B2B7FDB362C5BC4ECD555D85BCAA9C593C383C857D4"
|
||||
"9DAAB77E40B7851DDFD24998808E35B258E75D78EAC0CA16F7047304C20D93EDE4E8FF1C6F"
|
||||
"17E6243E3F3DA8FC1709870EC45FBA823A263F0CEFA1F7093B1909928326333705043A29BD"
|
||||
"A6F9B4342CC8DF543CB1A1182F7C5FFF33F10490FACA5B25360B76015E9C5A06AB8EE02F00"
|
||||
"D2E8D5986104AACC4DD475FD96EE9CE4E326F21B83C7058577B38732CDDABC6A6BED13FB0D"
|
||||
"49D38A45EB87A5F4";
|
||||
"https://proxy.staging.widevine.com/proxy";
|
||||
|
||||
// Google Play license server data
|
||||
const std::string kGpLicenseServer =
|
||||
@@ -116,31 +172,58 @@ const std::string kWrongKeyId =
|
||||
"0901121094889920e8d6520098577df8"
|
||||
"f2dd5546";
|
||||
|
||||
// URL of provisioning server (returned by GetProvisioningRequest())
|
||||
// URL of provisioning server (overrides value from GetProvisioningRequest())
|
||||
const std::string kProductionProvisioningServerUrl =
|
||||
"https://www.googleapis.com/"
|
||||
"certificateprovisioning/v1/devicecertificates/create"
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
|
||||
const std::string kStagingProvisioningServerUrl =
|
||||
"https://staging-www.sandbox.googleapis.com/"
|
||||
"certificateprovisioning/v1/devicecertificates/create"
|
||||
"?key=AIzaSyB-5OLKTx2iU5mko18DfdwK5611JIjbUhE";
|
||||
|
||||
const ConfigTestEnv::LicenseServerConfiguration license_servers[] = {
|
||||
{kGooglePlayServer, kGpLicenseServer, kGpClientAuth, kGpKeyId,
|
||||
kGpOfflineKeyId, ""},
|
||||
{kContentProtectionUatServer, kCpUatLicenseServer, kCpClientAuth,
|
||||
kCpKeyId, kCpOfflineKeyId, kCpUatServiceCertificate},
|
||||
{kContentProtectionStagingServer, kCpStagingLicenseServer,
|
||||
kCpClientAuth, kCpKeyId, kCpOfflineKeyId, kCpStagingServiceCertificate},
|
||||
{kGooglePlayServer, kGpLicenseServer, "", kGpClientAuth, kGpKeyId,
|
||||
kGpOfflineKeyId, kStagingProvisioningServerUrl, ""},
|
||||
|
||||
{kContentProtectionProdLicense, kCpProdLicenseServer,
|
||||
kProdServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
|
||||
kProductionProvisioningServerUrl, kProdServiceCertificate},
|
||||
|
||||
{kContentProtectionUatLicense, kCpUatLicenseServer,
|
||||
kProdServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
|
||||
kProductionProvisioningServerUrl, kProdServiceCertificate},
|
||||
|
||||
{kContentProtectionStagingLicense, kCpStagingLicenseServer,
|
||||
kProdServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
|
||||
kStagingProvisioningServerUrl, kStagingServiceCertificate},
|
||||
|
||||
{kContentProtectionProdPlusProv30, kCpProdLicenseServer,
|
||||
kProdServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
|
||||
kStagingProvisioningServerUrl, kStagingServiceCertificate},
|
||||
|
||||
{kContentProtectionUatPlusProv30, kCpUatLicenseServer,
|
||||
kProdServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
|
||||
kStagingProvisioningServerUrl, kStagingServiceCertificate},
|
||||
|
||||
{kContentProtectionStagingPlusProv30, kCpStagingLicenseServer,
|
||||
kStagingServiceCertificate, kCpClientAuth, kCpKeyId, kCpOfflineKeyId,
|
||||
kStagingProvisioningServerUrl, kStagingServiceCertificate},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ConfigTestEnv::ConfigTestEnv(LicenseServerId server_id) { Init(server_id); }
|
||||
ConfigTestEnv::ConfigTestEnv(ServerConfigurationId server_id) {
|
||||
Init(server_id);
|
||||
}
|
||||
|
||||
ConfigTestEnv::ConfigTestEnv(LicenseServerId server_id, bool streaming) {
|
||||
ConfigTestEnv::ConfigTestEnv(ServerConfigurationId server_id, bool streaming) {
|
||||
Init(server_id);
|
||||
if (!streaming) key_id_ = license_servers[server_id].offline_key_id;
|
||||
}
|
||||
|
||||
ConfigTestEnv::ConfigTestEnv(LicenseServerId server_id, bool streaming,
|
||||
ConfigTestEnv::ConfigTestEnv(ServerConfigurationId server_id, bool streaming,
|
||||
bool renew, bool release) {
|
||||
Init(server_id);
|
||||
if (!streaming) {
|
||||
@@ -158,13 +241,16 @@ ConfigTestEnv::ConfigTestEnv(LicenseServerId server_id, bool streaming,
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigTestEnv::Init(LicenseServerId server_id) {
|
||||
void ConfigTestEnv::Init(ServerConfigurationId server_id) {
|
||||
client_auth_ = license_servers[server_id].client_tag;
|
||||
key_id_ = license_servers[server_id].key_id;
|
||||
key_system_ = kWidevineKeySystem;
|
||||
license_server_ = license_servers[server_id].url;
|
||||
provisioning_server_url_ = kProductionProvisioningServerUrl;
|
||||
service_certificate_ = license_servers[server_id].service_certificate;
|
||||
license_server_ = license_servers[server_id].license_server_url;
|
||||
provisioning_server_ = license_servers[server_id].provisioning_server_url;
|
||||
license_service_certificate_ =
|
||||
a2bs_hex(license_servers[server_id].license_service_certificate);
|
||||
provisioning_service_certificate_ =
|
||||
a2bs_hex(license_servers[server_id].provisioning_service_certificate);
|
||||
wrong_key_id_ = kWrongKeyId;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,28 +6,50 @@
|
||||
#include <string>
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
// Declare class ConfigTestEnv - holds the configuration settings needed
|
||||
// to talk to the various provisioning and license servers.
|
||||
//
|
||||
// License Servers
|
||||
// QA - early test server (corporate access only, not generally usable).
|
||||
// UAT - test server with non-production data.
|
||||
// Staging - test server with access to production data.
|
||||
// Production - live, production server.
|
||||
// Google Play - Allows testing on Google Play servers (very stale).
|
||||
//
|
||||
// Provisioning Servers
|
||||
// UAT - early access provisioning server.
|
||||
// Staging - early access to features.
|
||||
// Production - live production server.
|
||||
|
||||
// Useful configurations
|
||||
namespace wvcdm {
|
||||
typedef enum {
|
||||
kGooglePlayServer,
|
||||
kContentProtectionUatServer,
|
||||
kContentProtectionStagingServer,
|
||||
} LicenseServerId;
|
||||
kGooglePlayServer, // not tested recently
|
||||
kContentProtectionProdLicense,
|
||||
kContentProtectionUatLicense,
|
||||
kContentProtectionStagingLicense,
|
||||
kContentProtectionProdPlusProv30,
|
||||
kContentProtectionUatPlusProv30,
|
||||
kContentProtectionStagingPlusProv30,
|
||||
} ServerConfigurationId;
|
||||
|
||||
// Configures default test environment.
|
||||
class ConfigTestEnv {
|
||||
public:
|
||||
typedef struct {
|
||||
LicenseServerId id;
|
||||
std::string url;
|
||||
ServerConfigurationId id;
|
||||
std::string license_server_url;
|
||||
std::string license_service_certificate;
|
||||
std::string client_tag;
|
||||
std::string key_id;
|
||||
std::string offline_key_id;
|
||||
std::string service_certificate;
|
||||
std::string provisioning_server_url;
|
||||
std::string provisioning_service_certificate;
|
||||
} LicenseServerConfiguration;
|
||||
|
||||
explicit ConfigTestEnv(LicenseServerId server_id);
|
||||
ConfigTestEnv(LicenseServerId server_id, bool streaming);
|
||||
ConfigTestEnv(LicenseServerId server_id, bool streaming, bool renew,
|
||||
explicit ConfigTestEnv(ServerConfigurationId server_id);
|
||||
ConfigTestEnv(ServerConfigurationId server_id, bool streaming);
|
||||
ConfigTestEnv(ServerConfigurationId server_id, bool streaming, bool renew,
|
||||
bool release);
|
||||
~ConfigTestEnv() {};
|
||||
|
||||
@@ -35,11 +57,14 @@ class ConfigTestEnv {
|
||||
const KeyId& key_id() const { return key_id_; }
|
||||
const CdmKeySystem& key_system() const { return key_system_; }
|
||||
const std::string& license_server() const { return license_server_; }
|
||||
const std::string& provisioning_server_url() const {
|
||||
return provisioning_server_url_;
|
||||
const std::string& provisioning_server() const {
|
||||
return provisioning_server_;
|
||||
}
|
||||
const std::string& service_certificate() const {
|
||||
return service_certificate_;
|
||||
const std::string& license_service_certificate() const {
|
||||
return license_service_certificate_;
|
||||
}
|
||||
const std::string& provisioning_service_certificate() const {
|
||||
return provisioning_service_certificate_;
|
||||
}
|
||||
const KeyId& wrong_key_id() const { return wrong_key_id_; }
|
||||
|
||||
@@ -52,14 +77,15 @@ class ConfigTestEnv {
|
||||
}
|
||||
|
||||
private:
|
||||
void Init(LicenseServerId server_id);
|
||||
void Init(ServerConfigurationId server_id);
|
||||
|
||||
std::string client_auth_;
|
||||
KeyId key_id_;
|
||||
CdmKeySystem key_system_;
|
||||
std::string license_server_;
|
||||
std::string provisioning_server_url_;
|
||||
std::string service_certificate_;
|
||||
std::string provisioning_server_;
|
||||
std::string license_service_certificate_;
|
||||
std::string provisioning_service_certificate_;
|
||||
KeyId wrong_key_id_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(ConfigTestEnv);
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef CDM_TEST_DEFAULT_SERVICE_CERTIFICATE_H_
|
||||
#define CDM_TEST_DEFAULT_SERVICE_CERTIFICATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "string_conversions.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string kDefaultServiceCertificate = wvcdm::a2bs_hex(
|
||||
"0ABF020803121028703454C008F63618ADE7443DB6C4C8188BE7F99005228E023082010A02"
|
||||
"82010100B52112B8D05D023FCC5D95E2C251C1C649B4177CD8D2BEEF355BB06743DE661E3D"
|
||||
"2ABC3182B79946D55FDC08DFE95407815E9A6274B322A2C7F5E067BB5F0AC07A89D45AEA94"
|
||||
"B2516F075B66EF811D0D26E1B9A6B894F2B9857962AA171C4F66630D3E4C602718897F5E1E"
|
||||
"F9B6AAF5AD4DBA2A7E14176DF134A1D3185B5A218AC05A4C41F081EFFF80A3A040C50B09BB"
|
||||
"C740EEDCD8F14D675A91980F92CA7DDC646A06ADAD5101F74A0E498CC01F00532BAC217850"
|
||||
"BD905E90923656B7DFEFEF42486767F33EF6283D4F4254AB72589390BEE55808F1D668080D"
|
||||
"45D893C2BCA2F74D60A0C0D0A0993CEF01604703334C3638139486BC9DAF24FD67A07F9AD9"
|
||||
"4302030100013A1273746167696E672E676F6F676C652E636F6D128003983E30352675F40B"
|
||||
"A715FC249BDAE5D4AC7249A2666521E43655739529721FF880E0AAEFC5E27BC980DAEADABF"
|
||||
"3FC386D084A02C82537848CC753FF497B011A7DA97788A00E2AA6B84CD7D71C07A48EBF616"
|
||||
"02CCA5A3F32030A7295C30DA915B91DC18B9BC9593B8DE8BB50F0DEDC12938B8E9E039CDDE"
|
||||
"18FA82E81BB032630FE955D85A566CE154300BF6D4C1BD126966356B287D657B18CE63D0EF"
|
||||
"D45FC5269E97EAB11CB563E55643B26FF49F109C2101AFCAF35B832F288F0D9D45960E259E"
|
||||
"85FB5D24DBD2CF82764C5DD9BF727EFBE9C861F869321F6ADE18905F4D92F9A6DA6536DB84"
|
||||
"75871D168E870BB2303CF70C6E9784C93D2DE845AD8262BE7E0D4E2E4A0759CEF82D109D25"
|
||||
"92C72429F8C01742BAE2B3DECADBC33C3E5F4BAF5E16ECB74EADBAFCB7C6705F7A9E3B6F39"
|
||||
"40383F9C5116D202A20C9229EE969C2519718303B50D0130C3352E06B014D838540F8A0C22"
|
||||
"7C0011E0F5B38E4E298ED2CB301EB4564965F55C5D79757A250A4EB9C84AB3E6539F6B6FDF"
|
||||
"56899EA29914");
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // CDM_TEST_DEFAULT_SERVICE_CERTIFICATE_H_
|
||||
@@ -1634,7 +1634,8 @@ TEST_F(DeviceCertificateStoreTest, StoreCertificate) {
|
||||
EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key));
|
||||
}
|
||||
|
||||
TEST_F(DeviceCertificateTest, ReadCertificate) {
|
||||
// TODO(tinskip): Fix. kTestCertificateFileData appears to be incorect.
|
||||
TEST_F(DeviceCertificateTest, DISABLED_ReadCertificate) {
|
||||
MockFileSystem file_system;
|
||||
std::string device_certificate_path =
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName();
|
||||
@@ -1664,7 +1665,7 @@ TEST_F(DeviceCertificateTest, ReadCertificate) {
|
||||
&serial_number, &system_id));
|
||||
EXPECT_EQ(kTestCertificate, b2a_hex(certificate));
|
||||
EXPECT_EQ(kTestWrappedPrivateKey, b2a_hex(wrapped_private_key));
|
||||
EXPECT_EQ(0, system_id);
|
||||
EXPECT_EQ(0u, system_id);
|
||||
EXPECT_EQ("", b2a_hex(serial_number));
|
||||
}
|
||||
|
||||
@@ -2328,5 +2329,4 @@ TEST_P(DeviceFilesHlsAttributesTest, Delete) {
|
||||
INSTANTIATE_TEST_CASE_P(HlsAttributes, DeviceFilesHlsAttributesTest,
|
||||
::testing::Range(&kHlsAttributesTestData[0],
|
||||
&kHlsAttributesTestData[2]));
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -171,7 +171,7 @@ TEST_F(FileTest, ListFiles) {
|
||||
EXPECT_TRUE(file_system.List(path_dir, &names));
|
||||
|
||||
// Should find three files. Order not important.
|
||||
EXPECT_EQ(3, names.size());
|
||||
EXPECT_EQ(3u, names.size());
|
||||
EXPECT_THAT(names, ::testing::UnorderedElementsAre(kTestFileName,
|
||||
kTestFileName2,
|
||||
kTestFileName3));
|
||||
@@ -180,14 +180,14 @@ TEST_F(FileTest, ListFiles) {
|
||||
EXPECT_TRUE(file_system.Remove(wild_card_path));
|
||||
EXPECT_TRUE(file_system.List(path_dir, &names));
|
||||
|
||||
EXPECT_EQ(1, names.size());
|
||||
EXPECT_EQ(1u, names.size());
|
||||
EXPECT_TRUE(names[0].compare(kTestFileName3) == 0);
|
||||
|
||||
std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3;
|
||||
EXPECT_TRUE(file_system.Remove(wild_card_path2));
|
||||
EXPECT_TRUE(file_system.List(path_dir, &names));
|
||||
|
||||
EXPECT_EQ(0, names.size());
|
||||
EXPECT_EQ(0u, names.size());
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -10,8 +10,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "cdm_engine.h"
|
||||
|
||||
#include "default_service_certificate.h"
|
||||
#include "config_test_env.h"
|
||||
#include "license_request.h"
|
||||
#include "log.h"
|
||||
#include "oec_session_util.h"
|
||||
@@ -25,6 +24,52 @@ namespace {
|
||||
|
||||
const std::string kKeySystem = "com.widevine.alpha";
|
||||
|
||||
std::string g_provisioning_server;
|
||||
std::string g_license_service_certificate;
|
||||
std::string g_provisioning_service_certificate;
|
||||
|
||||
/*
|
||||
* Locate the portion of the server's response message that is between
|
||||
* the strings jason_start_substr and json_end_substr. Returns the string
|
||||
* through *result. If the start substring match fails, assume the entire
|
||||
* string represents a serialized protobuf mesaage and return true with
|
||||
* the entire string. If the end_substring match fails, return false with
|
||||
* an empty *result.
|
||||
*/
|
||||
bool ExtractSignedMessage(const std::string& response,
|
||||
const std::string& json_start_substr,
|
||||
const std::string& json_end_substr,
|
||||
std::string* result) {
|
||||
std::string b64_string;
|
||||
size_t start = response.find(json_start_substr);
|
||||
|
||||
if (start == response.npos) {
|
||||
// Assume web safe protobuf
|
||||
b64_string.assign(response);
|
||||
} else {
|
||||
// Assume JSON-wrapped protobuf
|
||||
size_t end = response.find(json_end_substr,
|
||||
start + json_start_substr.length());
|
||||
if (end == response.npos) {
|
||||
LOGE("ExtractSignedMessage cannot locate end substring");
|
||||
result->clear();
|
||||
return false;
|
||||
}
|
||||
size_t b64_string_size = end - start - json_start_substr.length();
|
||||
b64_string.assign(response, start + json_start_substr.length(),
|
||||
b64_string_size);
|
||||
}
|
||||
|
||||
if (b64_string.empty()) {
|
||||
LOGE("Response message is empty");
|
||||
result->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
result->swap(b64_string);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -34,6 +79,15 @@ class WvGenericOperationsTest : public testing::Test {
|
||||
virtual void SetUp() {
|
||||
::testing::Test::SetUp();
|
||||
|
||||
ConfigTestEnv config(kContentProtectionStagingPlusProv30);
|
||||
|
||||
g_provisioning_service_certificate.assign(
|
||||
config.provisioning_service_certificate());
|
||||
g_license_service_certificate.assign(config.license_service_certificate());
|
||||
g_provisioning_server.assign(config.provisioning_server());
|
||||
|
||||
cdm_engine_ = NULL;
|
||||
|
||||
// TODO(fredgc or gmorgan): This should be updated for provisioning 3.0
|
||||
// Load test keybox. This keybox will be used by any CryptoSession
|
||||
// created by the CDM under test.
|
||||
@@ -42,6 +96,8 @@ class WvGenericOperationsTest : public testing::Test {
|
||||
// Perform CdmEngine setup
|
||||
cdm_engine_ = new CdmEngine(&file_system_);
|
||||
|
||||
Provision();
|
||||
|
||||
CdmResponseType status =
|
||||
cdm_engine_->OpenSession(kKeySystem, NULL, NULL, &session_id_);
|
||||
if (status == NEED_PROVISIONING) {
|
||||
@@ -66,7 +122,9 @@ class WvGenericOperationsTest : public testing::Test {
|
||||
|
||||
virtual void TearDown() {
|
||||
oec_util_session_.close();
|
||||
cdm_engine_->CloseSession(session_id_);
|
||||
if (cdm_engine_ != NULL) {
|
||||
cdm_engine_->CloseSession(session_id_);
|
||||
}
|
||||
// OEMCrypto_Terminate() will be performed during the test class's
|
||||
// destruction (specifically by the CryptoSession destructor)
|
||||
}
|
||||
@@ -156,26 +214,55 @@ class WvGenericOperationsTest : public testing::Test {
|
||||
}
|
||||
|
||||
protected:
|
||||
void Provision() {
|
||||
|
||||
virtual void Provision() {
|
||||
LOGE("WvCdmEnginePreProvTest::Provision: url=%s",
|
||||
g_provisioning_server.c_str());
|
||||
CdmProvisioningRequest prov_request;
|
||||
std::string provisioning_server_url;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority;
|
||||
std::string cert, wrapped_key;
|
||||
cdm_engine_->SetServiceCertificate(kDefaultServiceCertificate);
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
cdm_engine_->GetProvisioningRequest(
|
||||
cert_type, cert_authority, &prov_request,
|
||||
&provisioning_server_url));
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_->SetServiceCertificate(
|
||||
g_provisioning_service_certificate));
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_->GetProvisioningRequest(
|
||||
cert_type, cert_authority, &prov_request,
|
||||
&provisioning_server_url));
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: req=%s", prov_request.c_str());
|
||||
|
||||
// Ignore URL provided by CdmEngine. Use ours, as configured
|
||||
// for test vs. production server.
|
||||
provisioning_server_url.assign(g_provisioning_server);
|
||||
UrlRequest url_request(provisioning_server_url);
|
||||
EXPECT_TRUE(url_request.is_connected());
|
||||
url_request.PostCertRequestInQueryString(prov_request);
|
||||
std::string message;
|
||||
bool ok = url_request.GetResponse(&message);
|
||||
std::string http_message;
|
||||
bool ok = url_request.GetResponse(&http_message);
|
||||
EXPECT_TRUE(ok);
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: http_message: \n%s\n",
|
||||
http_message.c_str());
|
||||
|
||||
// extract provisioning response from received message
|
||||
// Extracts signed response from JSON string, decodes base64 signed response
|
||||
const std::string kMessageStart = "\"signedResponse\": \"";
|
||||
const std::string kMessageEnd = "\"";
|
||||
std::string base64_response;
|
||||
EXPECT_TRUE (ExtractSignedMessage(http_message, kMessageStart, kMessageEnd,
|
||||
&base64_response)) <<
|
||||
"Failed to extract signed serialized response from JSON response";
|
||||
|
||||
LOGV("WvCdmEnginePreProvTest::Provision: extracted response "
|
||||
"message: \n%s\n", base64_response.c_str());
|
||||
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
cdm_engine_->HandleProvisioningResponse(message, &cert,
|
||||
&wrapped_key));
|
||||
cdm_engine_->HandleProvisioningResponse(base64_response,
|
||||
&cert, &wrapped_key));
|
||||
|
||||
ASSERT_EQ(NO_ERROR,
|
||||
cdm_engine_->SetServiceCertificate(
|
||||
g_license_service_certificate));
|
||||
}
|
||||
|
||||
// This CryptoSession object handles Initialization and Termination
|
||||
|
||||
@@ -317,7 +317,7 @@ class LicenseKeysTest : public ::testing::Test {
|
||||
}
|
||||
|
||||
|
||||
int content_key_count_;
|
||||
size_t content_key_count_;
|
||||
LicenseKeys license_keys_;
|
||||
License license_;
|
||||
};
|
||||
@@ -495,7 +495,7 @@ TEST_F(LicenseKeysTest, ExtractKeyStatuses) {
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageOperatorSessionKeys();
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(0, key_status_map.size());
|
||||
EXPECT_EQ(0u, key_status_map.size());
|
||||
StageContentKeys();
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
#include "clock.h"
|
||||
#include "crypto_session.h"
|
||||
#include "default_service_certificate.h"
|
||||
#include "initialization_data.h"
|
||||
#include "license.h"
|
||||
#include "policy_engine.h"
|
||||
@@ -220,7 +219,8 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
|
||||
DoAll(SetArgPointee<2>(kLicenseRequestSignature), Return(true)));
|
||||
|
||||
CreateCdmLicense();
|
||||
service_cert_.Init(kDefaultServiceCertificate);
|
||||
// TODO(gmorgan) fix below - no default service certificate
|
||||
//service_cert_.Init(kDefaultServiceCertificate);
|
||||
EXPECT_TRUE(cdm_license_->Init(
|
||||
&service_cert_, kToken, kClientTokenDrmCert, kEmptyString,
|
||||
crypto_session_, policy_engine_));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "crypto_session.h"
|
||||
#include "license.h"
|
||||
#include "policy_engine.h"
|
||||
@@ -212,15 +213,27 @@ class PolicyEngineConstraintsTest : public Test {
|
||||
TEST_F(PolicyEngineConstraintsTest, IsPermissiveWithoutAResolution) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).Times(2);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
|
||||
{
|
||||
Sequence key_change;
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusOutputNotAllowed,
|
||||
kKeyId3, kKeyStatusUsable,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, true);
|
||||
}
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId2));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId3));
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
@@ -247,7 +260,6 @@ TEST_F(PolicyEngineConstraintsTest, HandlesResolutionsBasedOnConstraints) {
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(true)));
|
||||
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||
policy_engine_->OnTimerEvent();
|
||||
@@ -285,17 +297,34 @@ TEST_F(PolicyEngineConstraintsTest,
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
|
||||
{
|
||||
Sequence key_change;
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusOutputNotAllowed,
|
||||
kKeyId3, kKeyStatusUsable,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, true);
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2_2),
|
||||
Return(false)))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2_2),
|
||||
Return(false)));
|
||||
}
|
||||
int64_t start_time = current_time_ + 5;
|
||||
{
|
||||
InSequence calls;
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2_2),
|
||||
Return(true)));
|
||||
Return(false)));
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(start_time + kHdcpInterval / 2))
|
||||
.WillOnce(Return(start_time + kHdcpInterval));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2_2),
|
||||
Return(false)))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2_2),
|
||||
Return(true)));
|
||||
@@ -371,14 +400,13 @@ TEST_F(PolicyEngineConstraintsTest, HandlesNoHdcp) {
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusOutputNotAllowed,
|
||||
kKeyId3, kKeyStatusUsable,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, false);
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, true);
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusOutputNotAllowed,
|
||||
kKeyId3, kKeyStatusOutputNotAllowed,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, false);
|
||||
}
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NONE),
|
||||
@@ -405,7 +433,7 @@ TEST_F(PolicyEngineConstraintsTest, HandlesNoHdcp) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, IgnoresHdcpWithoutAResolution) {
|
||||
TEST_F(PolicyEngineConstraintsTest, UsesDefaultHdcpWhenResolutionNotSet) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<2; ++i) {
|
||||
@@ -413,16 +441,28 @@ TEST_F(PolicyEngineConstraintsTest, IgnoresHdcpWithoutAResolution) {
|
||||
.WillOnce(Return(i * 10));
|
||||
}
|
||||
}
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
|
||||
{
|
||||
Sequence key_change;
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusOutputNotAllowed,
|
||||
kKeyId3, kKeyStatusUsable,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, true);
|
||||
}
|
||||
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _)).Times(0);
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId2));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId3));
|
||||
EXPECT_TRUE(policy_engine_->CanDecryptContent(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId6));
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
using namespace testing;
|
||||
|
||||
namespace {
|
||||
const int64_t kDurationUnlimited = 0;
|
||||
const int64_t kLicenseStartTime = 1413517500; // ~ 01/01/2013
|
||||
@@ -52,6 +54,11 @@ int64_t ParseInt(const std::string& str) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
class HdcpOnlyMockCryptoSession : public CryptoSession {
|
||||
public:
|
||||
MOCK_METHOD2(GetHdcpCapabilities, bool(HdcpCapability*, HdcpCapability*));
|
||||
};
|
||||
|
||||
class MockCdmEventListener : public WvCdmEventListener {
|
||||
public:
|
||||
MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId& session_id));
|
||||
@@ -85,7 +92,8 @@ class PolicyEngineTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
policy_engine_.reset(
|
||||
new PolicyEngine(kSessionId, &mock_event_listener_, NULL));
|
||||
new PolicyEngine(kSessionId, &mock_event_listener_,
|
||||
&crypto_session_));
|
||||
InjectMockClock();
|
||||
|
||||
license_.set_license_start_time(kLicenseStartTime);
|
||||
@@ -141,6 +149,7 @@ class PolicyEngineTest : public ::testing::Test {
|
||||
expected_has_new_usable_key));
|
||||
}
|
||||
|
||||
StrictMock<HdcpOnlyMockCryptoSession> crypto_session_;
|
||||
StrictMock<MockCdmEventListener> mock_event_listener_;
|
||||
MockClock* mock_clock_;
|
||||
scoped_ptr<PolicyEngine> policy_engine_;
|
||||
@@ -164,6 +173,11 @@ TEST_F(PolicyEngineTest, PlaybackSuccess_OfflineLicense) {
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
OnExpirationUpdate(_, kPlaybackStartTime + kPlaybackDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(true)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->BeginDecryption();
|
||||
policy_engine_->OnTimerEvent();
|
||||
@@ -185,6 +199,11 @@ TEST_F(PolicyEngineTest, PlaybackSuccess_StreamingLicense) {
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
OnExpirationUpdate(_, kLicenseStartTime + kLowDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->BeginDecryption();
|
||||
policy_engine_->OnTimerEvent();
|
||||
@@ -203,6 +222,11 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanPlayFalse) {
|
||||
|
||||
ExpectSessionKeysChange(kKeyStatusExpired, false);
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId));
|
||||
|
||||
@@ -223,6 +247,11 @@ TEST_F(PolicyEngineTest, LicenseExpired_RentalDurationExpiredWithoutPlayback) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration - 1))
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -253,6 +282,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalDurationPassedWithPlayback) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration - 1))
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -283,6 +317,11 @@ TEST_F(PolicyEngineTest, PlaybackFails_PlaybackDurationExpired) {
|
||||
.WillOnce(Return(playback_start_time + kPlaybackDuration - 2))
|
||||
.WillOnce(Return(playback_start_time + kPlaybackDuration + 2));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -315,6 +354,11 @@ TEST_F(PolicyEngineTest, LicenseExpired_LicenseDurationExpiredWithoutPlayback) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration - 1))
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -346,6 +390,11 @@ TEST_F(PolicyEngineTest, PlaybackFails_ExpiryBeforeRenewalDelay_Offline) {
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 1))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -381,6 +430,11 @@ TEST_F(PolicyEngineTest, PlaybackFails_ExpiryBeforeRenewalDelay_Streaming) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration - 1))
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -411,6 +465,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_RentalDuration0) {
|
||||
.WillOnce(Return(kLicenseStartTime + kRentalDuration + 10))
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -443,6 +502,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_PlaybackDuration0) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration - 2))
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration + 2));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -477,6 +541,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_LicenseDuration0) {
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 1))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -514,6 +583,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_PlaybackAndRental0) {
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
OnExpirationUpdate(_, kLicenseStartTime + kLicenseDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->BeginDecryption();
|
||||
policy_engine_->OnTimerEvent();
|
||||
@@ -537,6 +611,16 @@ TEST_F(PolicyEngineTest, PlaybackOk_Durations0) {
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, NEVER_EXPIRES));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -555,6 +639,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_LicenseWithFutureStartTime) {
|
||||
.WillOnce(Return(kLicenseStartTime))
|
||||
.WillOnce(Return(kPlaybackStartTime));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusPending, false);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -589,6 +678,11 @@ TEST_F(PolicyEngineTest, PlaybackFailed_CanRenewFalse) {
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 10))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -630,6 +724,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess) {
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||
kLicenseRenewalRetryInterval + 10));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -682,6 +781,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccess_WithFutureStartTime) {
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 30))
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 60));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -734,6 +838,11 @@ TEST_F(PolicyEngineTest, LicenseExpired_RenewFailedVersionNotUpdated) {
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 40))
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration + 10));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -792,6 +901,11 @@ TEST_F(PolicyEngineTest, PlaybackFailed_RepeatedRenewFailures) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration - 15))
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -848,6 +962,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterExpiry) {
|
||||
.WillOnce(Return(new_license_start_time))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 20));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -918,6 +1037,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewSuccessAfterFailures) {
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 67))
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay + 200));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -972,6 +1096,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_RenewedWithUsage) {
|
||||
.WillOnce(Return(kLicenseStartTime + 20))
|
||||
.WillOnce(Return(kLicenseStartTime + 40));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1030,6 +1159,11 @@ TEST_F(PolicyEngineTest, MultipleKeysInLicense) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(kLicenseStartTime + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||
|
||||
@@ -1052,6 +1186,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_SoftEnforcePlaybackDuration) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration - 5))
|
||||
.WillOnce(Return(kLicenseStartTime + kLicenseDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence seq;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1085,6 +1224,11 @@ TEST_F(PolicyEngineTest, LicenseExpired_SoftEnforceLoadBeforeExpire) {
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 5))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 10));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence seq;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1109,6 +1253,11 @@ TEST_F(PolicyEngineTest, LicenseExpired_SoftEnforceLoadAfterExpire) {
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 5))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 10));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence seq;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1138,6 +1287,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_GracePeriod) {
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration - 5))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence seq;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1177,6 +1331,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_GracePeriodWithLoad) {
|
||||
.WillOnce(Return(kNewPlaybackStartTime + kPlaybackDuration - 5))
|
||||
.WillOnce(Return(kNewPlaybackStartTime + kPlaybackDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence seq;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1215,6 +1374,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_GracePeriodWithExpiredLoad) {
|
||||
.WillOnce(Return(kNewPlaybackStartTime))
|
||||
.WillOnce(Return(kNewPlaybackStartTime));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence seq;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1242,6 +1406,11 @@ TEST_F(PolicyEngineTest, PlaybackOk_CanStoreGracePeriod) {
|
||||
.WillOnce(Return(kPlaybackStartTime + 50))
|
||||
.WillOnce(Return(kPlaybackStartTime + kGracePeriod + 2));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
InSequence seq;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -1383,6 +1552,11 @@ TEST_F(PolicyEngineKeyAllowedUsageTest, AllowedUsageBasic) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(kLicenseStartTime + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||
|
||||
@@ -1438,6 +1612,11 @@ TEST_F(PolicyEngineKeyAllowedUsageTest, AllowedUsageGeneric) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(kLicenseStartTime + 1));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||
|
||||
@@ -1463,7 +1642,7 @@ class PolicyEngineQueryTest : public PolicyEngineTest {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
PolicyEngineTest::SetUp();
|
||||
policy_engine_.reset(new PolicyEngine(kSessionId, NULL, NULL));
|
||||
policy_engine_.reset(new PolicyEngine(kSessionId, NULL, &crypto_session_));
|
||||
InjectMockClock();
|
||||
|
||||
// Use a STREAMING license policy.
|
||||
@@ -1501,6 +1680,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess) {
|
||||
.WillOnce(Return(kLicenseStartTime + 1))
|
||||
.WillOnce(Return(kLicenseStartTime + 100));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
CdmQueryMap query_info;
|
||||
@@ -1523,6 +1707,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_PlaybackNotBegun) {
|
||||
.WillOnce(Return(kLicenseStartTime + 100))
|
||||
.WillOnce(Return(kLicenseStartTime + 200));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
CdmQueryMap query_info;
|
||||
@@ -1559,6 +1748,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_PlaybackBegun) {
|
||||
.WillOnce(Return(kLicenseStartTime + 150))
|
||||
.WillOnce(Return(kLicenseStartTime + 200));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(true)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
CdmQueryMap query_info;
|
||||
@@ -1608,6 +1802,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_Offline) {
|
||||
.WillOnce(Return(kLicenseStartTime + 200))
|
||||
.WillOnce(Return(kLicenseStartTime + 300));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->OnTimerEvent();
|
||||
@@ -1690,6 +1889,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_CanPlayFalse) {
|
||||
.WillOnce(Return(kLicenseStartTime + 5))
|
||||
.WillOnce(Return(kLicenseStartTime + 100));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
EXPECT_FALSE(policy_engine_->CanDecryptContent(kKeyId));
|
||||
|
||||
@@ -1725,6 +1929,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_RentalDurationExpired) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration))
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -1763,6 +1972,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_PlaybackDurationExpired) {
|
||||
.WillOnce(Return(playback_start_time + 2 + kLowDuration))
|
||||
.WillOnce(Return(playback_start_time + 5 + kLowDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -1797,6 +2011,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_LicenseDurationExpired) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration))
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -1835,6 +2054,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_RentalDuration0) {
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration))
|
||||
.WillOnce(Return(kLicenseStartTime + kLowDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -1876,6 +2100,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_PlaybackDuration0) {
|
||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 2))
|
||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -1928,6 +2157,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_LicenseDuration0) {
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration))
|
||||
.WillOnce(Return(kPlaybackStartTime + kPlaybackDuration + 5));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -1965,6 +2199,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_Durations0) {
|
||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 9))
|
||||
.WillOnce(Return(kLicenseStartTime + kHighDuration + 15));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -1998,6 +2237,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_LicenseWithFutureStartTime) {
|
||||
.WillOnce(Return(kLicenseStartTime + 10))
|
||||
.WillOnce(Return(kLicenseStartTime + 25));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->OnTimerEvent();
|
||||
@@ -2049,6 +2293,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_Renew) {
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||
kLicenseRenewalRetryInterval + 15));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -2102,6 +2351,11 @@ TEST_F(PolicyEngineQueryTest, QuerySuccess_RenewWithFutureStartTime) {
|
||||
.WillOnce(Return(kLicenseStartTime + license_renewal_delay +
|
||||
kLicenseRenewalRetryInterval + 40));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->BeginDecryption();
|
||||
@@ -2177,6 +2431,11 @@ TEST_F(PolicyEngineTest, SetLicenseForReleaseAfterSetLicense) {
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
OnExpirationUpdate(_, kPlaybackStartTime + kPlaybackDuration));
|
||||
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(false)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->BeginDecryption();
|
||||
policy_engine_->OnTimerEvent();
|
||||
|
||||
@@ -136,9 +136,11 @@ TEST_F(ServiceCertificateTest, InitServiceCertificatePresent) {
|
||||
Properties::AddSessionPropertySet(kTestSessionId1, &property_set);
|
||||
|
||||
CreateServiceCertificate();
|
||||
std::string service_certificate;
|
||||
EXPECT_TRUE(Properties::GetServiceCertificate(kTestSessionId1,
|
||||
&service_certificate));
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
service_certificate_->Init(
|
||||
Properties::service_certificate(kTestSessionId1));
|
||||
service_certificate_->Init(service_certificate));
|
||||
EXPECT_TRUE(service_certificate_->HasCertificate());
|
||||
}
|
||||
|
||||
@@ -151,7 +153,7 @@ TEST_F(ServiceCertificateTest, SetServiceCertificate) {
|
||||
Properties::AddSessionPropertySet(kTestSessionId1, &property_set);
|
||||
|
||||
CreateServiceCertificate();
|
||||
EXPECT_EQ(NO_ERROR, service_certificate_->Init(kTestSignedCertificate);
|
||||
EXPECT_EQ(NO_ERROR, service_certificate_->Init(kTestSignedCertificate));
|
||||
EXPECT_TRUE(service_certificate_->HasCertificate());
|
||||
}
|
||||
|
||||
|
||||
@@ -249,6 +249,12 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
case RELEASE_ALL_USAGE_INFO_ERROR_2:
|
||||
*os << "RELEASE_ALL_USAGE_INFO_ERROR_2";
|
||||
break;
|
||||
case RELEASE_ALL_USAGE_INFO_ERROR_3:
|
||||
*os << "RELEASE_ALL_USAGE_INFO_ERROR_3";
|
||||
break;
|
||||
case RELEASE_ALL_USAGE_INFO_ERROR_4:
|
||||
*os << "RELEASE_ALL_USAGE_INFO_ERROR_4";
|
||||
break;
|
||||
case RELEASE_KEY_ERROR: *os << "RELEASE_KEY_ERROR";
|
||||
break;
|
||||
case RELEASE_KEY_REQUEST_ERROR: *os << "RELEASE_KEY_REQUEST_ERROR";
|
||||
@@ -302,8 +308,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case STORE_LICENSE_ERROR_2: *os << "STORE_LICENSE_ERROR_2";
|
||||
break;
|
||||
case STORE_LICENSE_ERROR_3: *os << "STORE_LICENSE_ERROR_3";
|
||||
break;
|
||||
case STORE_USAGE_INFO_ERROR: *os << "STORE_USAGE_INFO_ERROR";
|
||||
break;
|
||||
case UNPROVISION_ERROR_1: *os << "UNPROVISION_ERROR_1";
|
||||
@@ -318,18 +322,12 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case USAGE_INFO_NOT_FOUND: *os << "USAGE_INFO_NOT_FOUND";
|
||||
break;
|
||||
case LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR:
|
||||
*os << "LICENSE_RENEWAL_SERVICE_CERTIFICATE_GENERATION_ERROR";
|
||||
break;
|
||||
case EMPTY_PROVISIONING_CERTIFICATE_2:
|
||||
*os << "EMPTY_PROVISIONING_CERTIFICATE_2";
|
||||
break;
|
||||
case PARSE_SERVICE_CERTIFICATE_ERROR:
|
||||
*os << "PARSE_SERVICE_CERTIFICATE_ERROR";
|
||||
break;
|
||||
case SERVICE_CERTIFICATE_TYPE_ERROR:
|
||||
*os << "SERVICE_CERTIFICATE_TYPE_ERROR";
|
||||
break;
|
||||
case CLIENT_ID_GENERATE_RANDOM_ERROR:
|
||||
*os << "CLIENT_ID_GENERATE_RANDOM_ERROR";
|
||||
break;
|
||||
@@ -354,9 +352,6 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case INVALID_PARAMETERS_LIC_7: *os << "INVALID_PARAMETERS_LIC_7";
|
||||
break;
|
||||
case LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR:
|
||||
*os << "LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR";
|
||||
break;
|
||||
case CENC_INIT_DATA_UNAVAILABLE: *os << "CENC_INIT_DATA_UNAVAILABLE";
|
||||
break;
|
||||
case PREPARE_CENC_CONTENT_ID_FAILED:
|
||||
@@ -449,6 +444,10 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_17: *os << "INVALID_PARAMETERS_ENG_17";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_18: *os << "INVALID_PARAMETERS_ENG_18";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_19: *os << "INVALID_PARAMETERS_ENG_19";
|
||||
break;
|
||||
case CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1:
|
||||
*os << "CERT_PROVISIONING_CLIENT_TOKEN_ERROR_1";
|
||||
break;
|
||||
@@ -458,6 +457,36 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
case LICENSING_CLIENT_TOKEN_ERROR_1:
|
||||
*os << "LICENSING_CLIENT_TOKEN_ERROR_1";
|
||||
break;
|
||||
case LIST_LICENSE_ERROR_1: *os << "LIST_LICENSE_ERROR_1";
|
||||
break;
|
||||
case LIST_LICENSE_ERROR_2: *os << "LIST_LICENSE_ERROR_2";
|
||||
break;
|
||||
case LIST_USAGE_ERROR_1: *os << "LIST_USAGE_ERROR_1";
|
||||
break;
|
||||
case LIST_USAGE_ERROR_2: *os << "LIST_USAGE_ERROR_2";
|
||||
break;
|
||||
case DELETE_USAGE_ERROR_1: *os << "DELETE_USAGE_ERROR_1";
|
||||
break;
|
||||
case DELETE_USAGE_ERROR_2: *os << "DELETE_USAGE_ERROR_2";
|
||||
break;
|
||||
case DELETE_USAGE_ERROR_3: *os << "DELETE_USAGE_ERROR_3";
|
||||
break;
|
||||
case PRIVACY_MODE_ERROR_1: *os << "PRIVACY_MODE_ERROR_1";
|
||||
break;
|
||||
case PRIVACY_MODE_ERROR_2: *os << "PRIVACY_MODE_ERROR_2";
|
||||
break;
|
||||
case PRIVACY_MODE_ERROR_3: *os << "PRIVACY_MODE_ERROR_3";
|
||||
break;
|
||||
case EMPTY_RESPONSE_ERROR_1: *os << "EMPTY_RESPONSE_ERROR_1";
|
||||
break;
|
||||
case PARSE_RESPONSE_ERROR_1: *os << "PARSE_RESPONSE_ERROR_1";
|
||||
break;
|
||||
case PARSE_RESPONSE_ERROR_2: *os << "PARSE_RESPONSE_ERROR_2";
|
||||
break;
|
||||
case PARSE_RESPONSE_ERROR_3: *os << "PARSE_RESPONSE_ERROR_3";
|
||||
break;
|
||||
case PARSE_RESPONSE_ERROR_4: *os << "PARSE_RESPONSE_ERROR_4";
|
||||
break;
|
||||
default:
|
||||
*os << "Unknown CdmResponseType";
|
||||
break;
|
||||
@@ -472,8 +501,6 @@ void PrintTo(const enum CdmLicenseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case kLicenseTypeRelease: *os << "kLicenseTypeRelease";
|
||||
break;
|
||||
case kLicenseTypeDeferred: *os << "kLicenseTypeDeferred";
|
||||
break;
|
||||
default:
|
||||
*os << "Unknown CdmLicenseType";
|
||||
break;
|
||||
|
||||
@@ -167,10 +167,11 @@ bool UrlRequest::PostRequest(const std::string& data) {
|
||||
|
||||
bool UrlRequest::PostCertRequestInQueryString(const std::string& data) {
|
||||
std::string path = socket_.resource_path();
|
||||
path.append("&signedRequest=");
|
||||
path.append((path.find('?') == std::string::npos) ? "?" : "&");
|
||||
path.append("signedRequest=");
|
||||
path.append(data);
|
||||
|
||||
return PostRequestWithPath(path, "");
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
Reference in New Issue
Block a user