File util, generic crypto, and key query
This CL merges several CLs from the widevine repo: http://go/wvgerrit/18012 Add support for querying allowed usage for key. http://go/wvgerrit/17971 Add per-origin storage. http://go/wvgerrit/18152 Add OEMCrypto's generic crypto operations to CDM. http://go/wvgerrit/17911 QueryKeyControlInfo => QueryOemCryptoSessionId Note: numbering in wv_cdm_types.h was added in this CL and will be back ported to wvgerrit in a future CL. Change-Id: Idb9e9a67e94f62f25dc16c5307f75a08b3430b64
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "certificate_provisioning.h"
|
||||
#include "crypto_session.h"
|
||||
#include "file_store.h"
|
||||
#include "initialization_data.h"
|
||||
#include "lock.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
@@ -26,26 +27,24 @@ typedef std::map<CdmKeySetId, CdmSessionId> CdmReleaseKeySetMap;
|
||||
|
||||
class CdmEngine {
|
||||
public:
|
||||
CdmEngine();
|
||||
CdmEngine(FileSystem* file_system);
|
||||
virtual ~CdmEngine();
|
||||
|
||||
// Session related methods
|
||||
virtual CdmResponseType OpenSession(const CdmKeySystem& key_system,
|
||||
CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
const CdmSessionId& forced_session_id,
|
||||
WvCdmEventListener* event_listener);
|
||||
virtual CdmResponseType OpenSession(const CdmKeySystem& key_system,
|
||||
CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener,
|
||||
CdmSessionId* session_id);
|
||||
virtual CdmResponseType CloseSession(const CdmSessionId& session_id);
|
||||
virtual bool IsOpenSession(const CdmSessionId& session_id);
|
||||
|
||||
virtual CdmResponseType OpenKeySetSession(
|
||||
const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set,
|
||||
const std::string& origin, WvCdmEventListener* event_listener);
|
||||
virtual CdmResponseType OpenKeySetSession(const CdmKeySetId& key_set_id,
|
||||
CdmClientPropertySet* property_set,
|
||||
WvCdmEventListener* event_listener);
|
||||
virtual CdmResponseType CloseKeySetSession(const CdmKeySetId& key_set_id);
|
||||
|
||||
// License related methods
|
||||
@@ -93,38 +92,48 @@ class CdmEngine {
|
||||
|
||||
// Query system information
|
||||
virtual CdmResponseType QueryStatus(SecurityLevel security_level,
|
||||
const std::string& key,
|
||||
std::string* value);
|
||||
const std::string& query_token,
|
||||
std::string* query_response);
|
||||
|
||||
// Query session information
|
||||
virtual CdmResponseType QuerySessionStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
CdmQueryMap* query_response);
|
||||
virtual bool IsReleaseSession(const CdmSessionId& session_id);
|
||||
virtual bool IsOfflineSession(const CdmSessionId& session_id);
|
||||
|
||||
// Query license information
|
||||
virtual CdmResponseType QueryKeyStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
CdmQueryMap* query_response);
|
||||
|
||||
// Query session control information
|
||||
virtual CdmResponseType QueryKeyControlInfo(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info);
|
||||
// Query the types of usage permitted for the specified key.
|
||||
virtual CdmResponseType QueryKeyAllowedUsage(const CdmSessionId& session_id,
|
||||
const std::string& key_id,
|
||||
CdmKeyAllowedUsage* key_usage);
|
||||
|
||||
// Query the types of usage permitted for the specified key.
|
||||
// Apply the query across all sessions. If the key is found in more than
|
||||
// one session, return the allowed usage settings only if the usage settings
|
||||
// are identical for each instance of the key. Otherwise, clear the settings
|
||||
// and return KEY_CONFLICT_1.
|
||||
virtual CdmResponseType QueryKeyAllowedUsage(const std::string& key_id,
|
||||
CdmKeyAllowedUsage* key_usage);
|
||||
|
||||
// Query OEMCrypto session ID
|
||||
virtual CdmResponseType QueryOemCryptoSessionId(
|
||||
const CdmSessionId& session_id, CdmQueryMap* query_response);
|
||||
|
||||
// Provisioning related methods
|
||||
virtual CdmResponseType GetProvisioningRequest(
|
||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||
const std::string& origin, CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
CdmProvisioningRequest* request, std::string* default_url);
|
||||
|
||||
virtual CdmResponseType HandleProvisioningResponse(
|
||||
const std::string& origin, const CdmProvisioningResponse& response,
|
||||
std::string* cert, std::string* wrapped_key);
|
||||
const CdmProvisioningResponse& response, std::string* cert,
|
||||
std::string* wrapped_key);
|
||||
|
||||
virtual bool IsProvisioned(CdmSecurityLevel security_level,
|
||||
const std::string& origin);
|
||||
virtual bool IsProvisioned(CdmSecurityLevel security_level);
|
||||
|
||||
virtual CdmResponseType Unprovision(CdmSecurityLevel security_level,
|
||||
const std::string& origin);
|
||||
virtual CdmResponseType Unprovision(CdmSecurityLevel security_level);
|
||||
|
||||
// Usage related methods for streaming licenses
|
||||
// Retrieve a random usage info from the list of all usage infos for this app
|
||||
@@ -147,6 +156,35 @@ class CdmEngine {
|
||||
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters);
|
||||
|
||||
// Generic crypto operations - provides basic crypto operations that an
|
||||
// application can use outside of content stream processing
|
||||
|
||||
// Encrypts a buffer of app-level data.
|
||||
virtual CdmResponseType 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);
|
||||
|
||||
// Decrypts a buffer of app-level data.
|
||||
virtual CdmResponseType GenericDecrypt(
|
||||
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);
|
||||
|
||||
// Computes the signature for a message.
|
||||
virtual CdmResponseType GenericSign(const std::string& session_id,
|
||||
const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
std::string* signature);
|
||||
|
||||
// Verifies the signature on a buffer of app-level data.
|
||||
virtual CdmResponseType GenericVerify(const std::string& session_id,
|
||||
const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature);
|
||||
|
||||
virtual size_t SessionSize() const { return sessions_.size(); }
|
||||
|
||||
// Is the key known to any session?
|
||||
@@ -170,7 +208,6 @@ class CdmEngine {
|
||||
// private methods
|
||||
CdmResponseType OpenSession(const CdmKeySystem& key_system,
|
||||
CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener,
|
||||
const CdmSessionId* forced_session_id,
|
||||
CdmSessionId* session_id);
|
||||
@@ -190,6 +227,7 @@ class CdmEngine {
|
||||
CdmReleaseKeySetMap release_key_sets_;
|
||||
scoped_ptr<CertificateProvisioning> cert_provisioning_;
|
||||
SecurityLevel cert_provisioning_requested_security_level_;
|
||||
FileSystem* file_system_;
|
||||
|
||||
static bool seeded_;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "crypto_session.h"
|
||||
#include "device_files.h"
|
||||
#include "file_store.h"
|
||||
#include "initialization_data.h"
|
||||
#include "license.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
@@ -22,24 +23,7 @@ class WvCdmEventListener;
|
||||
|
||||
class CdmSession {
|
||||
public:
|
||||
CdmSession(const std::string& origin)
|
||||
: initialized_(false),
|
||||
origin_(origin),
|
||||
crypto_session_(new CryptoSession),
|
||||
file_handle_(new DeviceFiles),
|
||||
license_received_(false),
|
||||
is_offline_(false),
|
||||
is_release_(false),
|
||||
is_temporary_(false),
|
||||
security_level_(kSecurityLevelUninitialized),
|
||||
requested_security_level_(kLevelDefault),
|
||||
is_initial_decryption_(true),
|
||||
has_decrypted_since_last_report_(false),
|
||||
is_initial_usage_update_(true),
|
||||
is_usage_update_needed_(false),
|
||||
mock_license_parser_in_use_(false),
|
||||
mock_policy_engine_in_use_(false) {}
|
||||
|
||||
CdmSession(FileSystem* file_system);
|
||||
virtual ~CdmSession();
|
||||
|
||||
virtual CdmResponseType Init(CdmClientPropertySet* cdm_client_property_set);
|
||||
@@ -63,13 +47,17 @@ class CdmSession {
|
||||
virtual CdmResponseType AddKey(const CdmKeyResponse& key_response);
|
||||
|
||||
// Query session status
|
||||
virtual CdmResponseType QueryStatus(CdmQueryMap* key_info);
|
||||
virtual CdmResponseType QueryStatus(CdmQueryMap* query_response);
|
||||
|
||||
// Query license information
|
||||
virtual CdmResponseType QueryKeyStatus(CdmQueryMap* key_info);
|
||||
virtual CdmResponseType QueryKeyStatus(CdmQueryMap* query_response);
|
||||
|
||||
// Query session control info
|
||||
virtual CdmResponseType QueryKeyControlInfo(CdmQueryMap* key_info);
|
||||
// Query allowed usages for key
|
||||
virtual CdmResponseType QueryKeyAllowedUsage(const std::string& key_id,
|
||||
CdmKeyAllowedUsage* key_usage);
|
||||
|
||||
// Query OEMCrypto session ID
|
||||
virtual CdmResponseType QueryOemCryptoSessionId(CdmQueryMap* query_response);
|
||||
|
||||
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||
@@ -131,11 +119,41 @@ class CdmSession {
|
||||
|
||||
bool DeleteLicense();
|
||||
|
||||
// Generate unique ID for each new session.
|
||||
CdmSessionId GenerateSessionId();
|
||||
|
||||
// Generic crypto operations - provides basic crypto operations that an
|
||||
// application can use outside of content stream processing
|
||||
|
||||
// Encrypts a buffer of app-level data.
|
||||
virtual CdmResponseType GenericEncrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer);
|
||||
|
||||
// Decrypts a buffer of app-level data.
|
||||
virtual CdmResponseType GenericDecrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer);
|
||||
|
||||
// Computes the signature for a message.
|
||||
virtual CdmResponseType GenericSign(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
std::string* signature);
|
||||
|
||||
// Verifies the signature on a buffer of app-level data.
|
||||
virtual CdmResponseType GenericVerify(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature);
|
||||
|
||||
private:
|
||||
friend class CdmSessionTest;
|
||||
|
||||
// Generate unique ID for each new session.
|
||||
CdmSessionId GenerateSessionId();
|
||||
bool GenerateKeySetId(CdmKeySetId* key_set_id);
|
||||
|
||||
CdmResponseType StoreLicense();
|
||||
@@ -150,7 +168,6 @@ class CdmSession {
|
||||
// instance variables
|
||||
bool initialized_;
|
||||
CdmSessionId session_id_;
|
||||
const std::string origin_;
|
||||
scoped_ptr<CdmLicense> license_parser_;
|
||||
scoped_ptr<CryptoSession> crypto_session_;
|
||||
scoped_ptr<PolicyEngine> policy_engine_;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace wvcdm {
|
||||
|
||||
class CdmSession;
|
||||
class FileSystem;
|
||||
|
||||
class CertificateProvisioning {
|
||||
public:
|
||||
@@ -26,7 +27,7 @@ class CertificateProvisioning {
|
||||
CdmProvisioningRequest* request,
|
||||
std::string* default_url);
|
||||
CdmResponseType HandleProvisioningResponse(
|
||||
const std::string& origin,
|
||||
FileSystem* file_system,
|
||||
const CdmProvisioningResponse& response,
|
||||
std::string* cert,
|
||||
std::string* wrapped_key);
|
||||
|
||||
@@ -103,6 +103,25 @@ class CryptoSession {
|
||||
virtual bool GetNumberOfOpenSessions(size_t* count);
|
||||
virtual bool GetMaxNumberOfSessions(size_t* max);
|
||||
|
||||
virtual CdmResponseType GenericEncrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer);
|
||||
virtual CdmResponseType GenericDecrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer);
|
||||
virtual CdmResponseType GenericSign(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
std::string* signature);
|
||||
virtual CdmResponseType GenericVerify(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature);
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void Terminate();
|
||||
@@ -114,9 +133,17 @@ class CryptoSession {
|
||||
bool GenerateRsaSignature(const std::string& message, std::string* signature);
|
||||
size_t GetOffset(std::string message, std::string field);
|
||||
bool SetDestinationBufferType();
|
||||
|
||||
bool SelectKey(const std::string& key_id);
|
||||
|
||||
static const OEMCrypto_Algorithm kInvalidAlgorithm =
|
||||
static_cast<OEMCrypto_Algorithm>(-1);
|
||||
|
||||
OEMCrypto_Algorithm GenericSigningAlgorithm(CdmSigningAlgorithm algorithm);
|
||||
OEMCrypto_Algorithm GenericEncryptionAlgorithm(
|
||||
CdmEncryptionAlgorithm algorithm);
|
||||
size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm);
|
||||
|
||||
static const size_t kAes128BlockSize = 16; // Block size for AES_CBC_128
|
||||
static const size_t kSignatureSize = 32; // size for HMAC-SHA256 signature
|
||||
static Lock crypto_lock_;
|
||||
static bool initialized_;
|
||||
@@ -130,7 +157,7 @@ class CryptoSession {
|
||||
bool is_destination_buffer_type_valid_;
|
||||
SecurityLevel requested_security_level_;
|
||||
|
||||
KeyId key_id_;
|
||||
KeyId cached_key_id_;
|
||||
|
||||
uint64_t request_id_base_;
|
||||
static uint64_t request_id_index_;
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class File;
|
||||
class FileSystem;
|
||||
|
||||
class DeviceFiles {
|
||||
public:
|
||||
@@ -28,7 +28,7 @@ class DeviceFiles {
|
||||
kLicenseStateUnknown,
|
||||
} LicenseState;
|
||||
|
||||
DeviceFiles();
|
||||
DeviceFiles(FileSystem*);
|
||||
virtual ~DeviceFiles();
|
||||
|
||||
virtual bool Init(CdmSecurityLevel security_level);
|
||||
@@ -36,14 +36,12 @@ class DeviceFiles {
|
||||
return Init(security_level);
|
||||
}
|
||||
|
||||
virtual bool StoreCertificate(const std::string& origin,
|
||||
const std::string& certificate,
|
||||
virtual bool StoreCertificate(const std::string& certificate,
|
||||
const std::string& wrapped_private_key);
|
||||
virtual bool RetrieveCertificate(const std::string& origin,
|
||||
std::string* certificate,
|
||||
virtual bool RetrieveCertificate(std::string* certificate,
|
||||
std::string* wrapped_private_key);
|
||||
virtual bool HasCertificate(const std::string& origin);
|
||||
virtual bool RemoveCertificate(const std::string& origin);
|
||||
virtual bool HasCertificate();
|
||||
virtual bool RemoveCertificate();
|
||||
|
||||
virtual bool StoreLicense(const std::string& key_set_id,
|
||||
const LicenseState state,
|
||||
@@ -113,18 +111,11 @@ class DeviceFiles {
|
||||
bool RemoveFile(const std::string& name);
|
||||
ssize_t GetFileSize(const std::string& name);
|
||||
|
||||
// Certificate and offline licenses are now stored in security
|
||||
// level specific directories. In an earlier version they were
|
||||
// stored in a common directory and need to be copied over.
|
||||
virtual void SecurityLevelPathBackwardCompatibility();
|
||||
|
||||
static std::string GetCertificateFileName(const std::string& origin);
|
||||
static std::string GetCertificateFileName();
|
||||
static std::string GetLicenseFileNameExtension();
|
||||
static std::string GetUsageInfoFileName(const std::string& app_id);
|
||||
static std::string GetFileNameSafeHash(const std::string& input);
|
||||
|
||||
// For testing only:
|
||||
void SetTestFile(File* file);
|
||||
#if defined(UNIT_TEST)
|
||||
FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel);
|
||||
FRIEND_TEST(DeviceCertificateStoreTest, StoreCertificate);
|
||||
@@ -135,7 +126,6 @@ class DeviceFiles {
|
||||
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem);
|
||||
FRIEND_TEST(DeviceFilesTest, RetrieveLicenses);
|
||||
FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility);
|
||||
FRIEND_TEST(DeviceFilesTest, SecurityLevelPathBackwardCompatibility);
|
||||
FRIEND_TEST(DeviceFilesTest, StoreLicenses);
|
||||
FRIEND_TEST(DeviceFilesTest, UpdateLicenseState);
|
||||
FRIEND_TEST(DeviceFilesUsageInfoTest, Delete);
|
||||
@@ -153,12 +143,10 @@ class DeviceFiles {
|
||||
|
||||
static std::set<std::string> reserved_license_ids_;
|
||||
|
||||
scoped_ptr<File> file_;
|
||||
FileSystem* file_system_;
|
||||
CdmSecurityLevel security_level_;
|
||||
bool initialized_;
|
||||
|
||||
bool test_file_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(DeviceFiles);
|
||||
};
|
||||
|
||||
|
||||
@@ -15,39 +15,54 @@ namespace wvcdm {
|
||||
|
||||
// File class. The implementation is platform dependent.
|
||||
class File {
|
||||
public:
|
||||
virtual ssize_t Read(char* buffer, size_t bytes);
|
||||
virtual ssize_t Write(const char* buffer, size_t bytes);
|
||||
virtual void Close();
|
||||
|
||||
protected:
|
||||
class Impl;
|
||||
|
||||
File(Impl*);
|
||||
virtual ~File();
|
||||
|
||||
private:
|
||||
Impl* impl_;
|
||||
|
||||
friend class FileSystem;
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(File);
|
||||
};
|
||||
|
||||
class FileSystem {
|
||||
public:
|
||||
class Impl;
|
||||
|
||||
// defines as bit flag
|
||||
enum OpenFlags {
|
||||
kNoFlags = 0,
|
||||
kBinary = 1,
|
||||
kCreate = 2,
|
||||
kReadOnly = 4, // defaults to read and write access
|
||||
kTruncate = 8
|
||||
kCreate = 1,
|
||||
kReadOnly = 2, // defaults to read and write access
|
||||
kTruncate = 4
|
||||
};
|
||||
|
||||
File();
|
||||
virtual ~File();
|
||||
FileSystem();
|
||||
FileSystem(const std::string& origin, void* extra_data);
|
||||
virtual ~FileSystem();
|
||||
|
||||
virtual bool Open(const std::string& file_path, int flags);
|
||||
virtual ssize_t Read(char* buffer, size_t bytes);
|
||||
virtual ssize_t Write(const char* buffer, size_t bytes);
|
||||
virtual void Close();
|
||||
virtual File* Open(const std::string& file_path, int flags);
|
||||
|
||||
virtual bool Exists(const std::string& file_path);
|
||||
virtual bool Remove(const std::string& file_path);
|
||||
virtual bool Copy(const std::string& old_path, const std::string& new_path);
|
||||
virtual bool List(const std::string& path, std::vector<std::string>* files);
|
||||
virtual bool CreateDirectory(const std::string dir_path);
|
||||
virtual bool IsDirectory(const std::string& dir_path);
|
||||
virtual bool IsRegularFile(const std::string& file_path);
|
||||
virtual ssize_t FileSize(const std::string& file_path);
|
||||
|
||||
const std::string& origin() const { return origin_; }
|
||||
void SetOrigin(const std::string& origin);
|
||||
|
||||
private:
|
||||
Impl* impl_;
|
||||
std::string origin_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(File);
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(FileSystem);
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
139
libwvdrmengine/cdm/core/include/license_key_status.h
Normal file
139
libwvdrmengine/cdm/core/include/license_key_status.h
Normal file
@@ -0,0 +1,139 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef WVCDM_CORE_LICENSE_KEY_STATUS_H_
|
||||
#define WVCDM_CORE_LICENSE_KEY_STATUS_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "crypto_session.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class LicenseKeyStatus;
|
||||
|
||||
// Holds all content and operator session keys for a session.
|
||||
class LicenseKeys {
|
||||
public:
|
||||
LicenseKeys() {}
|
||||
virtual ~LicenseKeys() { Clear(); }
|
||||
|
||||
virtual bool Empty() { return keys_.empty(); }
|
||||
|
||||
// Returns true if the key is a content key (not an operator session key)
|
||||
virtual bool IsContentKey(const KeyId& key_id);
|
||||
|
||||
// Returns true if the key is currently usable for content decryption.
|
||||
virtual bool CanDecryptContent(const KeyId& key_id);
|
||||
|
||||
// Returns the allowed usages for a key.
|
||||
virtual bool GetAllowedUsage(const KeyId& key_id,
|
||||
CdmKeyAllowedUsage* allowed_usage);
|
||||
|
||||
// Applies a new status to each content key.
|
||||
// Returns true if any statuses changed, and sets new_usable_keys to
|
||||
// true if the status changes resulted in keys becoming usable.
|
||||
virtual bool ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_keys);
|
||||
|
||||
// Populates the CdmKeyStatusMap with the current content keys.
|
||||
virtual void ExtractKeyStatuses(CdmKeyStatusMap* content_keys);
|
||||
|
||||
// Determines whether the specified key can be used under the current
|
||||
// resolution and/or hdcp constraints. If no constraints have been applied
|
||||
// to the key, returns true.
|
||||
virtual bool MeetsConstraints(const KeyId& key_id);
|
||||
|
||||
// Applies a resolution and/or hdcp change to each key, updating their
|
||||
// useability under their constraints.
|
||||
virtual void ApplyConstraints(uint32_t new_resolution,
|
||||
CryptoSession::HdcpCapability new_hdcp_level);
|
||||
|
||||
// Extracts the keys from a license and makes them available for
|
||||
// querying usage and constraint settings.
|
||||
virtual void SetFromLicense(
|
||||
const video_widevine_server::sdk::License& license);
|
||||
|
||||
private:
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer;
|
||||
typedef std::map<wvcdm::KeyId, LicenseKeyStatus*>::const_iterator
|
||||
LicenseKeyStatusIterator;
|
||||
|
||||
void Clear();
|
||||
|
||||
bool is_initialized_;
|
||||
std::map<KeyId, LicenseKeyStatus*> keys_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(LicenseKeys);
|
||||
};
|
||||
|
||||
// Holds the current license status of a key.
|
||||
class LicenseKeyStatus {
|
||||
friend class LicenseKeys;
|
||||
|
||||
public:
|
||||
// Returns true if the key is a content key (not an operator session key)
|
||||
virtual bool IsContentKey() { return is_content_key_; }
|
||||
|
||||
// Returns true if the key is currently usable for content decryption
|
||||
virtual bool CanDecryptContent();
|
||||
|
||||
// Returns the usages allowed for this key.
|
||||
virtual bool GetAllowedUsage(CdmKeyAllowedUsage* allowed_usage);
|
||||
|
||||
// Returns the current status of the key.
|
||||
virtual CdmKeyStatus GetKeyStatus() const { return key_status_; }
|
||||
|
||||
// Applies a new status to this key.
|
||||
// Returns true if the status changed, and sets new_usable_keys to
|
||||
// true if the status changes resulted in the key becoming usable.
|
||||
virtual bool ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_keys);
|
||||
|
||||
// Returns the current constraint status of this key. The result
|
||||
// may change due to calls to ApplyConstraints().
|
||||
// Note: this will return true until the first call to ApplyConstraints().
|
||||
virtual bool MeetsConstraints() const { return meets_constraints_; }
|
||||
|
||||
// Applies the given changes in resolution or HDCP settings.
|
||||
virtual void ApplyConstraints(
|
||||
uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level);
|
||||
|
||||
protected:
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer;
|
||||
typedef KeyContainer::OperatorSessionKeyPermissions
|
||||
OperatorSessionKeyPermissions;
|
||||
typedef KeyContainer::OutputProtection OutputProtection;
|
||||
typedef KeyContainer::VideoResolutionConstraint VideoResolutionConstraint;
|
||||
typedef ::google::protobuf::RepeatedPtrField<VideoResolutionConstraint>
|
||||
ConstraintList;
|
||||
|
||||
LicenseKeyStatus(const KeyContainer& key);
|
||||
|
||||
virtual ~LicenseKeyStatus() {}
|
||||
|
||||
private:
|
||||
|
||||
void ParseContentKey(const KeyContainer& key);
|
||||
void ParseOperatorSessionKey(const KeyContainer& key);
|
||||
|
||||
bool HasConstraints() {
|
||||
return is_content_key_ && constraints_.size() != 0;
|
||||
}
|
||||
|
||||
void SetConstraints(const ConstraintList& constraints);
|
||||
|
||||
bool is_content_key_;
|
||||
CdmKeyStatus key_status_;
|
||||
bool meets_constraints_;
|
||||
CdmKeyAllowedUsage allowed_usage_;
|
||||
CryptoSession::HdcpCapability default_hdcp_level_;
|
||||
ConstraintList constraints_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(LicenseKeyStatus);
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_LICENSE_KEY_STATUS_H_
|
||||
@@ -1,105 +0,0 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
|
||||
#ifndef WVCDM_CORE_MAX_RES_ENGINE_H_
|
||||
#define WVCDM_CORE_MAX_RES_ENGINE_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "crypto_session.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "lock.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class Clock;
|
||||
class MaxResEngineTest;
|
||||
|
||||
// Similar to the Policy Engine, this acts as an oracle that basically says
|
||||
// "Yes(true) you may still decrypt or no(false) you may not decrypt this data
|
||||
// anymore."
|
||||
class MaxResEngine {
|
||||
public:
|
||||
explicit MaxResEngine(CryptoSession* crypto_session);
|
||||
virtual ~MaxResEngine();
|
||||
|
||||
// The value returned is computed during the last call to SetLicense/
|
||||
// SetResolution/OnTimerEvent and may be out of sync depending on the amount
|
||||
// of time elapsed. The current decryption status is not calculated when this
|
||||
// function is called to avoid overhead in the decryption path.
|
||||
virtual bool CanDecrypt(const KeyId& key_id);
|
||||
|
||||
// SetLicense is used in handling the initial license response. It stores
|
||||
// an exact copy of the key constraints from the license.
|
||||
virtual void SetLicense(const video_widevine_server::sdk::License& license);
|
||||
|
||||
// SetResolution is called when the current output resolution is updated by
|
||||
// the decoder. The max-res engine will recalculate the current resolution
|
||||
// constraints, (if any) which may affect the results for CanDecrypt().
|
||||
virtual void SetResolution(uint32_t width, uint32_t height);
|
||||
|
||||
// OnTimerEvent is called when a timer fires. The max-res engine may check the
|
||||
// current HDCP level using the crypto session, which may affect the results
|
||||
// for CanDecrypt().
|
||||
virtual void OnTimerEvent();
|
||||
|
||||
private:
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer::OutputProtection
|
||||
OutputProtection;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer::
|
||||
VideoResolutionConstraint VideoResolutionConstraint;
|
||||
typedef ::google::protobuf::RepeatedPtrField<VideoResolutionConstraint>
|
||||
ConstraintList;
|
||||
|
||||
class KeyStatus {
|
||||
public:
|
||||
explicit KeyStatus(const ConstraintList& constraints);
|
||||
KeyStatus(const ConstraintList& constraints,
|
||||
const OutputProtection::HDCP& default_hdcp_level);
|
||||
|
||||
bool can_decrypt() const { return can_decrypt_; }
|
||||
|
||||
void Update(uint32_t res,
|
||||
CryptoSession::HdcpCapability current_hdcp_level);
|
||||
|
||||
private:
|
||||
void Init(const ConstraintList& constraints);
|
||||
|
||||
VideoResolutionConstraint* GetConstraintForRes(uint32_t res);
|
||||
|
||||
static CryptoSession::HdcpCapability ProtobufHdcpToOemCryptoHdcp(
|
||||
const OutputProtection::HDCP& input);
|
||||
|
||||
bool can_decrypt_;
|
||||
|
||||
CryptoSession::HdcpCapability default_hdcp_level_;
|
||||
ConstraintList constraints_;
|
||||
};
|
||||
|
||||
typedef std::map<wvcdm::KeyId,
|
||||
wvcdm::MaxResEngine::KeyStatus*>::const_iterator KeyIterator;
|
||||
|
||||
void Init(CryptoSession* crypto_session, Clock* clock);
|
||||
|
||||
void DeleteAllKeys();
|
||||
|
||||
Lock status_lock_;
|
||||
std::map<KeyId, KeyStatus*> keys_;
|
||||
uint32_t current_resolution_;
|
||||
int64_t next_check_time_;
|
||||
|
||||
scoped_ptr<Clock> clock_;
|
||||
CryptoSession* crypto_session_;
|
||||
|
||||
// For testing
|
||||
friend class MaxResEngineTest;
|
||||
MaxResEngine(CryptoSession* crypto_session, Clock* clock);
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(MaxResEngine);
|
||||
};
|
||||
|
||||
} // wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_MAX_RES_ENGINE_H_
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "license_key_status.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "max_res_engine.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
@@ -67,7 +67,10 @@ class PolicyEngine {
|
||||
|
||||
virtual void NotifySessionExpiration();
|
||||
|
||||
virtual CdmResponseType Query(CdmQueryMap* key_info);
|
||||
virtual CdmResponseType Query(CdmQueryMap* query_response);
|
||||
|
||||
virtual CdmResponseType QueryKeyAllowedUsage(const KeyId& key_id,
|
||||
CdmKeyAllowedUsage* key_usage);
|
||||
|
||||
virtual const LicenseIdentification& license_id() { return license_id_; }
|
||||
|
||||
@@ -90,6 +93,14 @@ class PolicyEngine {
|
||||
|
||||
private:
|
||||
friend class PolicyEngineTest;
|
||||
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;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
kLicenseStateInitial,
|
||||
@@ -120,9 +131,9 @@ class PolicyEngine {
|
||||
// expiry time changes.
|
||||
void NotifyExpirationUpdate();
|
||||
|
||||
// These setters are for testing only. Takes ownership of the pointers.
|
||||
// set_clock() is for testing only. It alters ownership of the
|
||||
// passed-in pointer.
|
||||
void set_clock(Clock* clock);
|
||||
void set_max_res_engine(MaxResEngine* max_res_engine);
|
||||
|
||||
LicenseState license_state_;
|
||||
|
||||
@@ -154,9 +165,14 @@ class PolicyEngine {
|
||||
CdmSessionId session_id_;
|
||||
WvCdmEventListener* event_listener_;
|
||||
|
||||
scoped_ptr<MaxResEngine> max_res_engine_;
|
||||
// Keys associated with license - holds allowed usage, usage constraints,
|
||||
// and current status (CdmKeyStatus)
|
||||
scoped_ptr<LicenseKeys> license_keys_;
|
||||
|
||||
std::map<KeyId, CdmKeyStatus> keys_status_;
|
||||
// Device checks
|
||||
int64_t next_device_check_;
|
||||
uint32_t current_resolution_;
|
||||
CryptoSession* crypto_session_;
|
||||
|
||||
scoped_ptr<Clock> clock_;
|
||||
|
||||
|
||||
@@ -218,6 +218,33 @@ enum CdmResponseType {
|
||||
INVALID_PARAMETERS_ENG_5,
|
||||
DECRYPT_ERROR,
|
||||
INSUFFICIENT_OUTPUT_PROTECTION,
|
||||
SESSION_NOT_FOUND_12, /* 180 */
|
||||
KEY_NOT_FOUND_1,
|
||||
KEY_NOT_FOUND_2,
|
||||
KEY_CONFLICT_1,
|
||||
INVALID_PARAMETERS_ENG_6,
|
||||
INVALID_PARAMETERS_ENG_7, /* 185 */
|
||||
INVALID_PARAMETERS_ENG_8,
|
||||
INVALID_PARAMETERS_ENG_9,
|
||||
INVALID_PARAMETERS_ENG_10,
|
||||
INVALID_PARAMETERS_ENG_11, /* 190 */
|
||||
INVALID_PARAMETERS_ENG_12,
|
||||
SESSION_NOT_FOUND_13,
|
||||
SESSION_NOT_FOUND_14,
|
||||
SESSION_NOT_FOUND_15,
|
||||
SESSION_NOT_FOUND_16, /* 195 */
|
||||
KEY_NOT_FOUND_3,
|
||||
KEY_NOT_FOUND_4,
|
||||
KEY_NOT_FOUND_5,
|
||||
KEY_NOT_FOUND_6,
|
||||
KEY_ERROR_1, /* 200 */
|
||||
KEY_ERROR_2,
|
||||
KEY_ERROR_3,
|
||||
KEY_ERROR_4,
|
||||
INVALID_PARAMETERS_ENG_13,
|
||||
INVALID_PARAMETERS_ENG_14, /* 205 */
|
||||
INVALID_PARAMETERS_ENG_15,
|
||||
INVALID_PARAMETERS_ENG_16,
|
||||
};
|
||||
|
||||
enum CdmKeyStatus {
|
||||
@@ -274,6 +301,59 @@ enum CdmCipherMode {
|
||||
kCipherModeCbc,
|
||||
};
|
||||
|
||||
enum CdmEncryptionAlgorithm {
|
||||
kEncryptionAlgorithmUnknown,
|
||||
kEncryptionAlgorithmAesCbc128
|
||||
};
|
||||
|
||||
enum CdmSigningAlgorithm {
|
||||
kSigningAlgorithmUnknown,
|
||||
kSigningAlgorithmHmacSha256
|
||||
};
|
||||
|
||||
class CdmKeyAllowedUsage {
|
||||
public:
|
||||
CdmKeyAllowedUsage() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool Valid() const { return valid_; }
|
||||
void SetValid() { valid_ = true; }
|
||||
|
||||
void Clear() {
|
||||
decrypt_to_clear_buffer = false;
|
||||
decrypt_to_secure_buffer = false;
|
||||
generic_encrypt = false;
|
||||
generic_decrypt = false;
|
||||
generic_sign = false;
|
||||
generic_verify = false;
|
||||
valid_ = false;
|
||||
}
|
||||
|
||||
bool Equals(const CdmKeyAllowedUsage& other) {
|
||||
if (!valid_ || !other.Valid() ||
|
||||
decrypt_to_clear_buffer != other.decrypt_to_clear_buffer ||
|
||||
decrypt_to_secure_buffer != other.decrypt_to_secure_buffer ||
|
||||
generic_encrypt != other.generic_encrypt ||
|
||||
generic_decrypt != other.generic_decrypt ||
|
||||
generic_sign != other.generic_sign ||
|
||||
generic_verify != other.generic_verify) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool decrypt_to_clear_buffer;
|
||||
bool decrypt_to_secure_buffer;
|
||||
bool generic_encrypt;
|
||||
bool generic_decrypt;
|
||||
bool generic_sign;
|
||||
bool generic_verify;
|
||||
|
||||
private:
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
// For schemes that do not use pattern encryption (cenc and cbc1), encrypt
|
||||
// and skip should be set to 0. For those that do (cens and cbcs), it is
|
||||
// recommended that encrypt+skip bytes sum to 10 and for cbcs that a 1:9
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "license_protocol.pb.h"
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "string_conversions.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_event_listener.h"
|
||||
@@ -55,11 +54,13 @@ class UsagePropertySet : public CdmClientPropertySet {
|
||||
|
||||
bool CdmEngine::seeded_ = false;
|
||||
|
||||
CdmEngine::CdmEngine()
|
||||
CdmEngine::CdmEngine(FileSystem* file_system)
|
||||
: cert_provisioning_(NULL),
|
||||
cert_provisioning_requested_security_level_(kLevelDefault),
|
||||
file_system_(file_system),
|
||||
usage_session_(NULL),
|
||||
last_usage_information_update_time_(0) {
|
||||
assert(file_system);
|
||||
Properties::Init();
|
||||
if (!seeded_) {
|
||||
Clock clock;
|
||||
@@ -79,25 +80,22 @@ CdmEngine::~CdmEngine() {
|
||||
|
||||
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
const CdmSessionId& forced_session_id,
|
||||
WvCdmEventListener* event_listener) {
|
||||
return OpenSession(key_system, property_set, origin, event_listener,
|
||||
return OpenSession(key_system, property_set, event_listener,
|
||||
&forced_session_id, NULL);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener,
|
||||
CdmSessionId* session_id) {
|
||||
return OpenSession(key_system, property_set, origin, event_listener,
|
||||
NULL, session_id);
|
||||
return OpenSession(key_system, property_set, event_listener, NULL,
|
||||
session_id);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
CdmClientPropertySet* property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener,
|
||||
const CdmSessionId* forced_session_id,
|
||||
CdmSessionId* session_id) {
|
||||
@@ -119,7 +117,8 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
}
|
||||
}
|
||||
|
||||
scoped_ptr<CdmSession> new_session(new CdmSession(origin));
|
||||
scoped_ptr<CdmSession> new_session(new CdmSession(file_system_));
|
||||
|
||||
CdmResponseType sts = new_session->Init(property_set, forced_session_id,
|
||||
event_listener);
|
||||
if (sts != NO_ERROR) {
|
||||
@@ -141,7 +140,7 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
|
||||
CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
const CdmKeySetId& key_set_id, CdmClientPropertySet* property_set,
|
||||
const std::string& origin, WvCdmEventListener* event_listener) {
|
||||
WvCdmEventListener* event_listener) {
|
||||
LOGI("CdmEngine::OpenKeySetSession");
|
||||
|
||||
if (key_set_id.empty()) {
|
||||
@@ -150,9 +149,8 @@ CdmResponseType CdmEngine::OpenKeySetSession(
|
||||
}
|
||||
|
||||
CdmSessionId session_id;
|
||||
CdmResponseType sts =
|
||||
OpenSession(KEY_SYSTEM, property_set, origin, event_listener,
|
||||
NULL /* forced_session_id */, &session_id);
|
||||
CdmResponseType sts = OpenSession(KEY_SYSTEM, property_set, event_listener,
|
||||
NULL /* forced_session_id */, &session_id);
|
||||
|
||||
if (sts != NO_ERROR) return sts;
|
||||
|
||||
@@ -313,7 +311,9 @@ CdmResponseType CdmEngine::AddKey(const CdmSessionId& session_id,
|
||||
}
|
||||
|
||||
CdmResponseType sts = iter->second->AddKey(key_data);
|
||||
*key_set_id = iter->second->key_set_id();
|
||||
if (key_set_id) {
|
||||
*key_set_id = iter->second->key_set_id();
|
||||
}
|
||||
|
||||
switch (sts) {
|
||||
case KEY_ADDED:
|
||||
@@ -425,8 +425,8 @@ CdmResponseType CdmEngine::RenewKey(const CdmSessionId& session_id,
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
const std::string& key,
|
||||
std::string* value) {
|
||||
const std::string& query_token,
|
||||
std::string* query_response) {
|
||||
LOGI("CdmEngine::QueryStatus");
|
||||
CryptoSession crypto_session;
|
||||
if (security_level == kLevel3) {
|
||||
@@ -434,36 +434,41 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
if (NO_ERROR != status) return INVALID_QUERY_STATUS;
|
||||
}
|
||||
|
||||
if (key == QUERY_KEY_SECURITY_LEVEL) {
|
||||
if (!query_response) {
|
||||
LOGE("CdmEngine::QueryStatus: no query response destination");
|
||||
return INVALID_PARAMETERS_ENG_6;
|
||||
}
|
||||
|
||||
if (query_token == QUERY_KEY_SECURITY_LEVEL) {
|
||||
CdmSecurityLevel security_level = crypto_session.GetSecurityLevel();
|
||||
switch (security_level) {
|
||||
case kSecurityLevelL1:
|
||||
*value = QUERY_VALUE_SECURITY_LEVEL_L1;
|
||||
*query_response = QUERY_VALUE_SECURITY_LEVEL_L1;
|
||||
break;
|
||||
case kSecurityLevelL2:
|
||||
*value = QUERY_VALUE_SECURITY_LEVEL_L2;
|
||||
*query_response = QUERY_VALUE_SECURITY_LEVEL_L2;
|
||||
break;
|
||||
case kSecurityLevelL3:
|
||||
*value = QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||
*query_response = QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||
break;
|
||||
case kSecurityLevelUninitialized:
|
||||
case kSecurityLevelUnknown:
|
||||
*value = QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
|
||||
*query_response = QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
LOGW("CdmEngine::QueryStatus: Unknown security level: %d",
|
||||
security_level);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
} else if (key == QUERY_KEY_DEVICE_ID) {
|
||||
} else if (query_token == QUERY_KEY_DEVICE_ID) {
|
||||
std::string deviceId;
|
||||
if (!crypto_session.GetDeviceUniqueId(&deviceId)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetDeviceUniqueId failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
*value = deviceId;
|
||||
} else if (key == QUERY_KEY_SYSTEM_ID) {
|
||||
*query_response = deviceId;
|
||||
} else if (query_token == QUERY_KEY_SYSTEM_ID) {
|
||||
uint32_t system_id;
|
||||
if (!crypto_session.GetSystemId(&system_id)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetSystemId failed");
|
||||
@@ -472,35 +477,36 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
|
||||
std::ostringstream system_id_stream;
|
||||
system_id_stream << system_id;
|
||||
*value = system_id_stream.str();
|
||||
} else if (key == QUERY_KEY_PROVISIONING_ID) {
|
||||
*query_response = system_id_stream.str();
|
||||
} else if (query_token == QUERY_KEY_PROVISIONING_ID) {
|
||||
std::string provisioning_id;
|
||||
if (!crypto_session.GetProvisioningId(&provisioning_id)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetProvisioningId failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
*value = provisioning_id;
|
||||
} else if (key == QUERY_KEY_CURRENT_HDCP_LEVEL ||
|
||||
key == QUERY_KEY_MAX_HDCP_LEVEL) {
|
||||
*query_response = provisioning_id;
|
||||
} else if (query_token == QUERY_KEY_CURRENT_HDCP_LEVEL ||
|
||||
query_token == QUERY_KEY_MAX_HDCP_LEVEL) {
|
||||
CryptoSession::HdcpCapability current_hdcp;
|
||||
CryptoSession::HdcpCapability max_hdcp;
|
||||
if (!crypto_session.GetHdcpCapabilities(¤t_hdcp, &max_hdcp)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetHdcpCapabilities failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
*value = MapHdcpVersion(key == QUERY_KEY_CURRENT_HDCP_LEVEL ? current_hdcp
|
||||
: max_hdcp);
|
||||
} else if (key == QUERY_KEY_USAGE_SUPPORT) {
|
||||
*query_response =
|
||||
MapHdcpVersion(query_token == QUERY_KEY_CURRENT_HDCP_LEVEL ?
|
||||
current_hdcp : max_hdcp);
|
||||
} else if (query_token == QUERY_KEY_USAGE_SUPPORT) {
|
||||
bool supports_usage_reporting;
|
||||
if (!crypto_session.UsageInformationSupport(&supports_usage_reporting)) {
|
||||
LOGW("CdmEngine::QueryStatus: UsageInformationSupport failed");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
*value = supports_usage_reporting ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
} else if (key == QUERY_KEY_NUMBER_OF_OPEN_SESSIONS) {
|
||||
*query_response =
|
||||
supports_usage_reporting ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
} else if (query_token == QUERY_KEY_NUMBER_OF_OPEN_SESSIONS) {
|
||||
size_t number_of_open_sessions;
|
||||
if (!crypto_session.GetNumberOfOpenSessions(&number_of_open_sessions)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetNumberOfOpenSessions failed");
|
||||
@@ -509,8 +515,8 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
|
||||
std::ostringstream open_sessions_stream;
|
||||
open_sessions_stream << number_of_open_sessions;
|
||||
*value = open_sessions_stream.str();
|
||||
} else if (key == QUERY_KEY_MAX_NUMBER_OF_SESSIONS) {
|
||||
*query_response = open_sessions_stream.str();
|
||||
} else if (query_token == QUERY_KEY_MAX_NUMBER_OF_SESSIONS) {
|
||||
size_t maximum_number_of_sessions;
|
||||
if (!crypto_session.GetMaxNumberOfSessions(&maximum_number_of_sessions)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetMaxNumberOfOpenSessions failed");
|
||||
@@ -519,8 +525,8 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
|
||||
std::ostringstream max_sessions_stream;
|
||||
max_sessions_stream << maximum_number_of_sessions;
|
||||
*value = max_sessions_stream.str();
|
||||
} else if (key == QUERY_KEY_OEMCRYPTO_API_VERSION) {
|
||||
*query_response = max_sessions_stream.str();
|
||||
} else if (query_token == QUERY_KEY_OEMCRYPTO_API_VERSION) {
|
||||
uint32_t api_version;
|
||||
if (!crypto_session.GetApiVersion(&api_version)) {
|
||||
LOGW("CdmEngine::QueryStatus: GetApiVersion failed");
|
||||
@@ -529,10 +535,10 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
|
||||
std::ostringstream api_version_stream;
|
||||
api_version_stream << api_version;
|
||||
*value = api_version_stream.str();
|
||||
*query_response = api_version_stream.str();
|
||||
} else {
|
||||
LOGW("CdmEngine::QueryStatus: Unknown status requested, key = %s",
|
||||
key.c_str());
|
||||
LOGW("CdmEngine::QueryStatus: Unknown status requested, token = %s",
|
||||
query_token.c_str());
|
||||
return INVALID_QUERY_KEY;
|
||||
}
|
||||
|
||||
@@ -540,7 +546,7 @@ CdmResponseType CdmEngine::QueryStatus(SecurityLevel security_level,
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QuerySessionStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info) {
|
||||
CdmQueryMap* query_response) {
|
||||
LOGI("CdmEngine::QuerySessionStatus");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
@@ -548,7 +554,7 @@ CdmResponseType CdmEngine::QuerySessionStatus(const CdmSessionId& session_id,
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_8;
|
||||
}
|
||||
return iter->second->QueryStatus(key_info);
|
||||
return iter->second->QueryStatus(query_response);
|
||||
}
|
||||
|
||||
bool CdmEngine::IsReleaseSession(const CdmSessionId& session_id) {
|
||||
@@ -574,7 +580,7 @@ bool CdmEngine::IsOfflineSession(const CdmSessionId& session_id) {
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryKeyStatus(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info) {
|
||||
CdmQueryMap* query_response) {
|
||||
LOGI("CdmEngine::QueryKeyStatus");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
@@ -582,19 +588,72 @@ CdmResponseType CdmEngine::QueryKeyStatus(const CdmSessionId& session_id,
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_9;
|
||||
}
|
||||
return iter->second->QueryKeyStatus(key_info);
|
||||
return iter->second->QueryKeyStatus(query_response);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryKeyControlInfo(const CdmSessionId& session_id,
|
||||
CdmQueryMap* key_info) {
|
||||
LOGI("CdmEngine::QueryKeyControlInfo");
|
||||
CdmResponseType CdmEngine::QueryKeyAllowedUsage(const CdmSessionId& session_id,
|
||||
const std::string& key_id,
|
||||
CdmKeyAllowedUsage* key_usage) {
|
||||
LOGI("CdmEngine::QueryKeyAllowedUsage");
|
||||
if (!key_usage) {
|
||||
LOGE("CdmEngine::QueryKeyAllowedUsage: no response destination");
|
||||
return INVALID_PARAMETERS_ENG_12;
|
||||
}
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::QueryKeyControlInfo: session_id not found = %s",
|
||||
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);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryKeyAllowedUsage(const std::string& key_id,
|
||||
CdmKeyAllowedUsage* key_usage) {
|
||||
LOGI("CdmEngine::QueryKeyAllowedUsage (all sessions)");
|
||||
CdmResponseType session_sts;
|
||||
CdmKeyAllowedUsage found_in_this_session;
|
||||
bool found = false;
|
||||
if (!key_usage) {
|
||||
LOGE("CdmEngine::QueryKeyAllowedUsage: no response destination");
|
||||
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);
|
||||
if (session_sts == NO_ERROR) {
|
||||
if (found) {
|
||||
// Found another key. If usage settings do not match, fail.
|
||||
if (!key_usage->Equals(found_in_this_session)) {
|
||||
key_usage->Clear();
|
||||
return KEY_CONFLICT_1;
|
||||
}
|
||||
} else {
|
||||
*key_usage = found_in_this_session;
|
||||
found = true;
|
||||
}
|
||||
} else if (session_sts != KEY_NOT_FOUND_1) {
|
||||
LOGE("CdmEngine::QueryKeyAllowedUsage (all sessions) FAILED = %d",
|
||||
session_sts);
|
||||
key_usage->Clear();
|
||||
return session_sts;
|
||||
}
|
||||
}
|
||||
return (found) ? NO_ERROR : KEY_NOT_FOUND_2;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::QueryOemCryptoSessionId(
|
||||
const CdmSessionId& session_id, CdmQueryMap* query_response) {
|
||||
LOGI("CdmEngine::QueryOemCryptoSessionId");
|
||||
CdmSessionMap::iterator iter = sessions_.find(session_id);
|
||||
if (iter == sessions_.end()) {
|
||||
LOGE("CdmEngine::QueryOemCryptoSessionId: session_id not found = %s",
|
||||
session_id.c_str());
|
||||
return SESSION_NOT_FOUND_10;
|
||||
}
|
||||
return iter->second->QueryKeyControlInfo(key_info);
|
||||
return iter->second->QueryOemCryptoSessionId(query_response);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -606,8 +665,7 @@ CdmResponseType CdmEngine::QueryKeyControlInfo(const CdmSessionId& session_id,
|
||||
*/
|
||||
CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
CdmCertificateType cert_type, const std::string& cert_authority,
|
||||
const std::string& origin, CdmProvisioningRequest* request,
|
||||
std::string* default_url) {
|
||||
CdmProvisioningRequest* request, std::string* default_url) {
|
||||
if (!request) {
|
||||
LOGE("CdmEngine::GetProvisioningRequest: invalid output parameters");
|
||||
return INVALID_PROVISIONING_REQUEST_PARAM_1;
|
||||
@@ -624,7 +682,7 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
}
|
||||
CdmResponseType ret = cert_provisioning_->GetProvisioningRequest(
|
||||
cert_provisioning_requested_security_level_, cert_type, cert_authority,
|
||||
origin, request, default_url);
|
||||
file_system_->origin(), request, default_url);
|
||||
if (ret != NO_ERROR) {
|
||||
cert_provisioning_.reset(NULL); // Release resources.
|
||||
}
|
||||
@@ -639,8 +697,8 @@ CdmResponseType CdmEngine::GetProvisioningRequest(
|
||||
* Returns NO_ERROR for success and CdmResponseType error code if fails.
|
||||
*/
|
||||
CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
const std::string& origin, const CdmProvisioningResponse& response,
|
||||
std::string* cert, std::string* wrapped_key) {
|
||||
const CdmProvisioningResponse& response, std::string* cert,
|
||||
std::string* wrapped_key) {
|
||||
if (response.empty()) {
|
||||
LOGE("CdmEngine::HandleProvisioningResponse: Empty provisioning response.");
|
||||
cert_provisioning_.reset(NULL);
|
||||
@@ -672,7 +730,7 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
return EMPTY_PROVISIONING_CERTIFICATE_2;
|
||||
}
|
||||
CdmSecurityLevel security_level = crypto_session.GetSecurityLevel();
|
||||
if (!IsProvisioned(security_level, origin)) {
|
||||
if (!IsProvisioned(security_level)) {
|
||||
LOGE(
|
||||
"CdmEngine::HandleProvisioningResponse: provisioning object "
|
||||
"missing.");
|
||||
@@ -682,7 +740,7 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
}
|
||||
|
||||
CdmResponseType ret = cert_provisioning_->HandleProvisioningResponse(
|
||||
origin, response, cert, wrapped_key);
|
||||
file_system_, response, cert, wrapped_key);
|
||||
// Release resources only on success. It is possible that a provisioning
|
||||
// attempt was made after this one was requested but before the response was
|
||||
// received, which will cause this attempt to fail. Not releasing will
|
||||
@@ -691,28 +749,25 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CdmEngine::IsProvisioned(CdmSecurityLevel security_level,
|
||||
const std::string& origin) {
|
||||
DeviceFiles handle;
|
||||
bool CdmEngine::IsProvisioned(CdmSecurityLevel security_level) {
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::IsProvisioned: unable to initialize device files");
|
||||
return false;
|
||||
}
|
||||
return handle.HasCertificate(origin);
|
||||
return handle.HasCertificate();
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level,
|
||||
const std::string& origin) {
|
||||
DeviceFiles handle;
|
||||
CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(security_level)) {
|
||||
LOGE("CdmEngine::Unprovision: unable to initialize device files");
|
||||
return UNPROVISION_ERROR_1;
|
||||
}
|
||||
|
||||
if (origin != EMPTY_ORIGIN) {
|
||||
if (!handle.RemoveCertificate(origin)) {
|
||||
LOGE("CdmEngine::Unprovision: unable to delete certificate for origin %s",
|
||||
origin.c_str());
|
||||
if (!file_system_->origin().empty()) {
|
||||
if (!handle.RemoveCertificate()) {
|
||||
LOGE("CdmEngine::Unprovision: unable to delete certificate");
|
||||
return UNPROVISION_ERROR_2;
|
||||
}
|
||||
return NO_ERROR;
|
||||
@@ -743,15 +798,19 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
if (NULL == usage_property_set_.get()) {
|
||||
usage_property_set_.reset(new UsagePropertySet());
|
||||
}
|
||||
if (!usage_info) {
|
||||
LOGE("CdmEngine::GetUsageInfo: no usage info destination");
|
||||
return INVALID_PARAMETERS_ENG_8;
|
||||
}
|
||||
usage_property_set_->set_security_level(kLevelDefault);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
usage_session_.reset(new CdmSession(EMPTY_ORIGIN));
|
||||
usage_session_.reset(new CdmSession(file_system_));
|
||||
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: session init error");
|
||||
return status;
|
||||
}
|
||||
DeviceFiles handle;
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(usage_session_->GetSecurityLevel())) {
|
||||
LOGE("CdmEngine::GetUsageInfo: device file init error");
|
||||
return GET_USAGE_INFO_ERROR_1;
|
||||
@@ -763,7 +822,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
&license_response)) {
|
||||
usage_property_set_->set_security_level(kLevel3);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
usage_session_.reset(new CdmSession(EMPTY_ORIGIN));
|
||||
usage_session_.reset(new CdmSession(file_system_));
|
||||
status = usage_session_->Init(usage_property_set_.get());
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: session init error");
|
||||
@@ -808,6 +867,10 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
// Return a random usage report from a random security level
|
||||
SecurityLevel security_level = ((rand() % 2) == 0) ? kLevelDefault : kLevel3;
|
||||
CdmResponseType status = UNKNOWN_ERROR;
|
||||
if (!usage_info) {
|
||||
LOGE("CdmEngine::GetUsageInfo: no usage info destination");
|
||||
return INVALID_PARAMETERS_ENG_9;
|
||||
}
|
||||
do {
|
||||
status = GetUsageInfo(app_id, security_level, usage_info);
|
||||
|
||||
@@ -833,7 +896,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
usage_property_set_->set_security_level(requested_security_level);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
|
||||
usage_session_.reset(new CdmSession(EMPTY_ORIGIN));
|
||||
usage_session_.reset(new CdmSession(file_system_));
|
||||
|
||||
CdmResponseType status = usage_session_->Init(usage_property_set_.get());
|
||||
if (NO_ERROR != status) {
|
||||
@@ -841,7 +904,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
return status;
|
||||
}
|
||||
|
||||
DeviceFiles handle;
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(usage_session_->GetSecurityLevel())) {
|
||||
LOGE("CdmEngine::GetUsageInfo: unable to initialize device files");
|
||||
return GET_USAGE_INFO_ERROR_3;
|
||||
@@ -853,12 +916,15 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
return GET_USAGE_INFO_ERROR_4;
|
||||
}
|
||||
|
||||
if (!usage_info) {
|
||||
LOGE("CdmEngine::GetUsageInfo: no usage info destination");
|
||||
return INVALID_PARAMETERS_ENG_10;
|
||||
}
|
||||
if (0 == license_info.size()) {
|
||||
usage_info->resize(0);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
std::string server_url;
|
||||
usage_info->resize(kUsageReportsPerRequest);
|
||||
|
||||
uint32_t index = rand() % license_info.size();
|
||||
@@ -901,7 +967,7 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
|
||||
|
||||
CdmResponseType status = NO_ERROR;
|
||||
for (int j = kSecurityLevelL1; j < kSecurityLevelUnknown; ++j) {
|
||||
DeviceFiles handle;
|
||||
DeviceFiles handle(file_system_);
|
||||
if (handle.Init(static_cast<CdmSecurityLevel>(j))) {
|
||||
std::vector<std::string> provider_session_tokens;
|
||||
if (!handle.DeleteAllUsageInfoForApp(app_id, &provider_session_tokens)) {
|
||||
@@ -914,7 +980,7 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
|
||||
? kLevel3
|
||||
: kLevelDefault;
|
||||
usage_property_set_->set_security_level(security_level);
|
||||
usage_session_.reset(new CdmSession(EMPTY_ORIGIN));
|
||||
usage_session_.reset(new CdmSession(file_system_));
|
||||
usage_session_->Init(usage_property_set_.get());
|
||||
CdmResponseType status2 = usage_session_->
|
||||
DeleteMultipleUsageInformation(provider_session_tokens);
|
||||
@@ -966,7 +1032,12 @@ CdmResponseType CdmEngine::LoadUsageSession(const CdmKeySetId& key_set_id,
|
||||
return SESSION_NOT_FOUND_11;
|
||||
}
|
||||
|
||||
DeviceFiles handle;
|
||||
if (!release_message) {
|
||||
LOGE("CdmEngine::LoadUsageSession: no release message destination");
|
||||
return INVALID_PARAMETERS_ENG_11;
|
||||
}
|
||||
|
||||
DeviceFiles handle(file_system_);
|
||||
if (!handle.Init(iter->second->GetSecurityLevel())) {
|
||||
LOGE("CdmEngine::LoadUsageSession: unable to initialize device files");
|
||||
return LOAD_USAGE_INFO_FILE_ERROR;
|
||||
@@ -1061,6 +1132,61 @@ CdmResponseType CdmEngine::Decrypt(const CdmSessionId& session_id,
|
||||
return session_iter->second->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()) {
|
||||
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);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GenericDecrypt(
|
||||
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()) {
|
||||
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);
|
||||
}
|
||||
|
||||
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()) {
|
||||
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);
|
||||
}
|
||||
|
||||
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()) {
|
||||
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);
|
||||
}
|
||||
|
||||
bool CdmEngine::IsKeyLoaded(const KeyId& key_id) {
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
@@ -1083,7 +1209,8 @@ bool CdmEngine::FindSessionForKey(const KeyId& key_id,
|
||||
|
||||
CdmSessionMap::iterator session_iter = sessions_.end();
|
||||
int64_t seconds_remaining = 0;
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin(); iter != sessions_.end(); ++iter) {
|
||||
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) {
|
||||
@@ -1196,9 +1323,8 @@ void CdmEngine::DeleteAllUsageReportsUponFactoryReset() {
|
||||
Properties::GetDeviceFilesBasePath(kSecurityLevelL3,
|
||||
&device_base_path_level3);
|
||||
|
||||
File file;
|
||||
if (!file.Exists(device_base_path_level1) &&
|
||||
!file.Exists(device_base_path_level3)) {
|
||||
if (!file_system_->Exists(device_base_path_level1) &&
|
||||
!file_system_->Exists(device_base_path_level3)) {
|
||||
scoped_ptr<CryptoSession> crypto_session(new CryptoSession());
|
||||
CdmResponseType status = crypto_session->Open(
|
||||
cert_provisioning_requested_security_level_);
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
|
||||
#include "cdm_engine.h"
|
||||
#include "clock.h"
|
||||
#include "crypto_session.h"
|
||||
#include "device_files.h"
|
||||
#include "file_store.h"
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
@@ -25,6 +23,23 @@ const size_t kKeySetIdLength = 14;
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
CdmSession::CdmSession(FileSystem* file_system) :
|
||||
initialized_(false),
|
||||
crypto_session_(new CryptoSession),
|
||||
file_handle_(new DeviceFiles(file_system)),
|
||||
license_received_(false),
|
||||
is_offline_(false),
|
||||
is_release_(false),
|
||||
is_temporary_(false),
|
||||
security_level_(kSecurityLevelUninitialized),
|
||||
requested_security_level_(kLevelDefault),
|
||||
is_initial_decryption_(true),
|
||||
has_decrypted_since_last_report_(false),
|
||||
is_initial_usage_update_(true),
|
||||
is_usage_update_needed_(false),
|
||||
mock_license_parser_in_use_(false),
|
||||
mock_policy_engine_in_use_(false) {}
|
||||
|
||||
CdmSession::~CdmSession() {
|
||||
if (!key_set_id_.empty()) {
|
||||
// Unreserve the license ID.
|
||||
@@ -45,6 +60,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
LOGE("CdmSession::Init: Failed due to previous initialization");
|
||||
return SESSION_INIT_ERROR_2;
|
||||
}
|
||||
|
||||
if (cdm_client_property_set &&
|
||||
cdm_client_property_set->security_level() ==
|
||||
QUERY_VALUE_SECURITY_LEVEL_L3) {
|
||||
@@ -63,7 +79,7 @@ CdmResponseType CdmSession::Init(CdmClientPropertySet* cdm_client_property_set,
|
||||
std::string token;
|
||||
if (Properties::use_certificates_as_identification()) {
|
||||
std::string wrapped_key;
|
||||
if (!file_handle_->RetrieveCertificate(origin_, &token, &wrapped_key) ||
|
||||
if (!file_handle_->RetrieveCertificate(&token, &wrapped_key) ||
|
||||
!crypto_session_->LoadCertificatePrivateKey(wrapped_key)) {
|
||||
return NEED_PROVISIONING;
|
||||
}
|
||||
@@ -301,7 +317,7 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response) {
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
|
||||
CdmResponseType CdmSession::QueryStatus(CdmQueryMap* query_response) {
|
||||
if (crypto_session_.get() == NULL) {
|
||||
LOGE("CdmSession::QueryStatus: Invalid crypto session");
|
||||
return INVALID_CRYPTO_SESSION_3;
|
||||
@@ -314,17 +330,20 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
|
||||
|
||||
switch (security_level_) {
|
||||
case kSecurityLevelL1:
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1;
|
||||
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
|
||||
QUERY_VALUE_SECURITY_LEVEL_L1;
|
||||
break;
|
||||
case kSecurityLevelL2:
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L2;
|
||||
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
|
||||
QUERY_VALUE_SECURITY_LEVEL_L2;
|
||||
break;
|
||||
case kSecurityLevelL3:
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
|
||||
QUERY_VALUE_SECURITY_LEVEL_L3;
|
||||
break;
|
||||
case kSecurityLevelUninitialized:
|
||||
case kSecurityLevelUnknown:
|
||||
(*key_info)[QUERY_KEY_SECURITY_LEVEL] =
|
||||
(*query_response)[QUERY_KEY_SECURITY_LEVEL] =
|
||||
QUERY_VALUE_SECURITY_LEVEL_UNKNOWN;
|
||||
break;
|
||||
default:
|
||||
@@ -333,24 +352,30 @@ CdmResponseType CdmSession::QueryStatus(CdmQueryMap* key_info) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* key_info) {
|
||||
return policy_engine_->Query(key_info);
|
||||
CdmResponseType CdmSession::QueryKeyStatus(CdmQueryMap* query_response) {
|
||||
return policy_engine_->Query(query_response);
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::QueryKeyControlInfo(CdmQueryMap* key_info) {
|
||||
CdmResponseType CdmSession::QueryKeyAllowedUsage(
|
||||
const std::string& key_id, CdmKeyAllowedUsage* key_usage) {
|
||||
return policy_engine_->QueryKeyAllowedUsage(key_id, key_usage);
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::QueryOemCryptoSessionId(
|
||||
CdmQueryMap* query_response) {
|
||||
if (crypto_session_.get() == NULL) {
|
||||
LOGW("CdmSession::QueryKeyControlInfo: Invalid crypto session");
|
||||
LOGW("CdmSession::QueryOemCryptoSessionId: Invalid crypto session");
|
||||
return INVALID_CRYPTO_SESSION_4;
|
||||
}
|
||||
|
||||
if (!crypto_session_->IsOpen()) {
|
||||
LOGW("CdmSession::QueryKeyControlInfo: Crypto session not open");
|
||||
LOGW("CdmSession::QueryOemCryptoSessionId: Crypto session not open");
|
||||
return CRYPTO_SESSION_OPEN_ERROR_4;
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << crypto_session_->oec_session_id();
|
||||
(*key_info)[QUERY_KEY_OEMCRYPTO_SESSION_ID] = ss.str();
|
||||
(*query_response)[QUERY_KEY_OEMCRYPTO_SESSION_ID] = ss.str();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -545,6 +570,11 @@ bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
|
||||
policy_engine_->GetLastPlaybackTime(), app_parameters_);
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::ReleaseCrypto() {
|
||||
crypto_session_->Close();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
bool CdmSession::DeleteLicense() {
|
||||
if (!is_offline_ && license_parser_->provider_session_token().empty())
|
||||
return false;
|
||||
@@ -596,11 +626,52 @@ CdmResponseType CdmSession::UpdateUsageInformation() {
|
||||
return crypto_session_->UpdateUsageInformation();
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::ReleaseCrypto() {
|
||||
crypto_session_->Close();
|
||||
return NO_ERROR;
|
||||
CdmResponseType CdmSession::GenericEncrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer) {
|
||||
if (!out_buffer) {
|
||||
LOGE("CdmSession::GenericEncrypt: No output destination provided");
|
||||
return INVALID_PARAMETERS_ENG_6;
|
||||
}
|
||||
return crypto_session_->GenericEncrypt(in_buffer, key_id, iv, algorithm,
|
||||
out_buffer);
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::GenericDecrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer) {
|
||||
if (!out_buffer) {
|
||||
LOGE("CdmSession::GenericDecrypt: No output destination provided");
|
||||
return INVALID_PARAMETERS_ENG_7;
|
||||
}
|
||||
return crypto_session_->GenericDecrypt(in_buffer, key_id, iv, algorithm,
|
||||
out_buffer);
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::GenericSign(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
std::string* signature) {
|
||||
if (!signature) {
|
||||
LOGE("CdmSession::GenericSign: No output destination provided");
|
||||
return INVALID_PARAMETERS_ENG_8;
|
||||
}
|
||||
return crypto_session_->GenericSign(message, key_id, algorithm, signature);
|
||||
}
|
||||
|
||||
CdmResponseType CdmSession::GenericVerify(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature) {
|
||||
return crypto_session_->GenericVerify(message, key_id, algorithm, signature);
|
||||
}
|
||||
|
||||
// For testing only - takes ownership of pointers
|
||||
|
||||
void CdmSession::set_license_parser(CdmLicense* license_parser) {
|
||||
license_parser_.reset(license_parser);
|
||||
mock_license_parser_in_use_ = true;
|
||||
|
||||
@@ -189,7 +189,7 @@ bool CertificateProvisioning::ParseJsonResponse(
|
||||
* Returns NO_ERROR for success and CERT_PROVISIONING_RESPONSE_ERROR_? if fails.
|
||||
*/
|
||||
CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
const std::string& origin, const CdmProvisioningResponse& response,
|
||||
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\": \"";
|
||||
@@ -259,12 +259,12 @@ CdmResponseType CertificateProvisioning::HandleProvisioningResponse(
|
||||
const std::string& device_certificate =
|
||||
provisioning_response.device_certificate();
|
||||
|
||||
DeviceFiles handle;
|
||||
DeviceFiles handle(file_system);
|
||||
if (!handle.Init(crypto_session_.GetSecurityLevel())) {
|
||||
LOGE("HandleProvisioningResponse: failed to init DeviceFiles");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_7;
|
||||
}
|
||||
if (!handle.StoreCertificate(origin, device_certificate, wrapped_rsa_key)) {
|
||||
if (!handle.StoreCertificate(device_certificate, wrapped_rsa_key)) {
|
||||
LOGE("HandleProvisioningResponse: failed to save provisioning certificate");
|
||||
return CERT_PROVISIONING_RESPONSE_ERROR_8;
|
||||
}
|
||||
|
||||
@@ -56,17 +56,19 @@ void CryptoSession::Init() {
|
||||
LOGV("CryptoSession::Init");
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
session_count_ += 1;
|
||||
if (initialized_) return;
|
||||
OEMCryptoResult sts = OEMCrypto_Initialize();
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("OEMCrypto_Initialize failed: %d", sts);
|
||||
return;
|
||||
if (!initialized_) {
|
||||
OEMCryptoResult sts = OEMCrypto_Initialize();
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("OEMCrypto_Initialize failed: %d", sts);
|
||||
return;
|
||||
}
|
||||
initialized_ = true;
|
||||
}
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
void CryptoSession::Terminate() {
|
||||
LOGV("CryptoSession::Terminate");
|
||||
LOGE("CryptoSession::Terminate: initialized_=%d, session_count_=%d",
|
||||
initialized_, session_count_);
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (session_count_ > 0) {
|
||||
session_count_ -= 1;
|
||||
@@ -252,16 +254,15 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
|
||||
LOGV("OpenSession: id= %ld", (uint32_t)oec_session_id_);
|
||||
open_ = true;
|
||||
} else if (OEMCrypto_ERROR_TOO_MANY_SESSIONS == sts) {
|
||||
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", sts,
|
||||
session_count_, (int)initialized_);
|
||||
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d",
|
||||
sts, session_count_, (int)initialized_);
|
||||
return INSUFFICIENT_CRYPTO_RESOURCES;
|
||||
}
|
||||
if (!open_) {
|
||||
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d", sts,
|
||||
session_count_, (int)initialized_);
|
||||
LOGE("OEMCrypto_Open failed: %d, open sessions: %ld, initialized: %d",
|
||||
sts, session_count_, (int)initialized_);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
OEMCrypto_GetRandom(reinterpret_cast<uint8_t*>(&request_id_base_),
|
||||
sizeof(request_id_base_));
|
||||
++request_id_index_;
|
||||
@@ -507,12 +508,22 @@ bool CryptoSession::RefreshKeys(const std::string& message,
|
||||
}
|
||||
|
||||
bool CryptoSession::SelectKey(const std::string& key_id) {
|
||||
// Crypto session lock already locked.
|
||||
if (!cached_key_id_.empty() && cached_key_id_ == key_id) {
|
||||
// Already using the desired key.
|
||||
return true;
|
||||
}
|
||||
|
||||
cached_key_id_ = key_id;
|
||||
|
||||
const uint8_t* key_id_string =
|
||||
reinterpret_cast<const uint8_t*>(key_id.data());
|
||||
reinterpret_cast<const uint8_t*>(cached_key_id_.data());
|
||||
|
||||
OEMCryptoResult sts =
|
||||
OEMCrypto_SelectKey(oec_session_id_, key_id_string, key_id.size());
|
||||
OEMCrypto_SelectKey(oec_session_id_, key_id_string,
|
||||
cached_key_id_.size());
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
cached_key_id_.clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -567,78 +578,76 @@ bool CryptoSession::GenerateDerivedKeys(const std::string& message,
|
||||
bool CryptoSession::GenerateSignature(const std::string& message,
|
||||
std::string* signature) {
|
||||
LOGV("GenerateSignature: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!signature) return false;
|
||||
if (!signature) {
|
||||
LOGE("GenerateSignature: null signature string");
|
||||
return false;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
size_t length = signature->size();
|
||||
OEMCryptoResult sts = OEMCrypto_GenerateSignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
LOGE("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retry with proper-sized signature buffer
|
||||
signature->resize(length);
|
||||
// At most two attempts.
|
||||
// The first attempt may fail due to buffer too short
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
sts = OEMCrypto_GenerateSignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||
return false;
|
||||
if (OEMCrypto_SUCCESS == sts) {
|
||||
// Trim signature buffer and done
|
||||
signature->resize(length);
|
||||
return true;
|
||||
}
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Retry with proper-sized signature buffer
|
||||
signature->resize(length);
|
||||
}
|
||||
|
||||
// Trim signature buffer
|
||||
signature->resize(length);
|
||||
|
||||
return true;
|
||||
LOGE("GenerateSignature: OEMCrypto_GenerateSignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CryptoSession::GenerateRsaSignature(const std::string& message,
|
||||
std::string* signature) {
|
||||
LOGV("GenerateRsaSignature: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!signature) return false;
|
||||
if (!signature) {
|
||||
LOGE("GenerateRsaSignature: null signature string");
|
||||
return false;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
signature->resize(kRsaSignatureLength);
|
||||
size_t length = signature->size();
|
||||
OEMCryptoResult sts = OEMCrypto_GenerateRSASignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())), &length,
|
||||
kSign_RSASSA_PSS);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
LOGE("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retry with proper-sized signature buffer
|
||||
signature->resize(length);
|
||||
// At most two attempts.
|
||||
// The first attempt may fail due to buffer too short
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
sts = OEMCrypto_GenerateRSASignature(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(),
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length, kSign_RSASSA_PSS);
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||
return false;
|
||||
if (OEMCrypto_SUCCESS == sts) {
|
||||
// Trim signature buffer and done
|
||||
signature->resize(length);
|
||||
return true;
|
||||
}
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Retry with proper-sized signature buffer
|
||||
signature->resize(length);
|
||||
}
|
||||
|
||||
// Trim signature buffer
|
||||
signature->resize(length);
|
||||
|
||||
return true;
|
||||
LOGE("GenerateRsaSignature: OEMCrypto_GenerateRSASignature err=%d", sts);
|
||||
return false;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
@@ -693,12 +702,8 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
// Check if key needs to be selected
|
||||
if (params.is_encrypted) {
|
||||
if (key_id_ != *params.key_id) {
|
||||
if (SelectKey(*params.key_id)) {
|
||||
key_id_ = *params.key_id;
|
||||
} else {
|
||||
return NEED_KEY;
|
||||
}
|
||||
if (!SelectKey(*params.key_id)) {
|
||||
return NEED_KEY;
|
||||
}
|
||||
}
|
||||
sts = OEMCrypto_DecryptCENC(
|
||||
@@ -1101,4 +1106,200 @@ bool CryptoSession::GetMaxNumberOfSessions(size_t* max) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenericEncrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer) {
|
||||
LOGV("GenericEncrypt: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!out_buffer) return INVALID_PARAMETERS_ENG_9;
|
||||
|
||||
OEMCrypto_Algorithm oec_algorithm = GenericEncryptionAlgorithm(algorithm);
|
||||
if (iv.size() != GenericEncryptionBlockSize(algorithm) ||
|
||||
oec_algorithm == kInvalidAlgorithm) {
|
||||
return INVALID_PARAMETERS_ENG_13;
|
||||
}
|
||||
|
||||
if (out_buffer->size() < in_buffer.size()) {
|
||||
out_buffer->resize(in_buffer.size());
|
||||
}
|
||||
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (!SelectKey(key_id)) {
|
||||
return KEY_ERROR_1;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts = OEMCrypto_Generic_Encrypt(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(in_buffer.data()),
|
||||
in_buffer.size(), reinterpret_cast<const uint8_t*>(iv.data()),
|
||||
oec_algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(out_buffer->data())));
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("GenericEncrypt: OEMCrypto_Generic_Encrypt err=%d", sts);
|
||||
if (OEMCrypto_ERROR_KEY_EXPIRED == sts ||
|
||||
OEMCrypto_ERROR_NO_CONTENT_KEY == sts) {
|
||||
return KEY_NOT_FOUND_3;
|
||||
} else {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenericDecrypt(const std::string& in_buffer,
|
||||
const std::string& key_id,
|
||||
const std::string& iv,
|
||||
CdmEncryptionAlgorithm algorithm,
|
||||
std::string* out_buffer) {
|
||||
LOGV("GenericDecrypt: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!out_buffer) return INVALID_PARAMETERS_ENG_10;
|
||||
|
||||
OEMCrypto_Algorithm oec_algorithm = GenericEncryptionAlgorithm(algorithm);
|
||||
if (iv.size() != GenericEncryptionBlockSize(algorithm) ||
|
||||
oec_algorithm == kInvalidAlgorithm) {
|
||||
return INVALID_PARAMETERS_ENG_14;
|
||||
}
|
||||
|
||||
if (out_buffer->size() < in_buffer.size()) {
|
||||
out_buffer->resize(in_buffer.size());
|
||||
}
|
||||
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (!SelectKey(key_id)) {
|
||||
return KEY_ERROR_2;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts = OEMCrypto_Generic_Decrypt(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(in_buffer.data()),
|
||||
in_buffer.size(), reinterpret_cast<const uint8_t*>(iv.data()),
|
||||
oec_algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(out_buffer->data())));
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("GenericDecrypt: OEMCrypto_Generic_Decrypt err=%d", sts);
|
||||
if (OEMCrypto_ERROR_KEY_EXPIRED == sts ||
|
||||
OEMCrypto_ERROR_NO_CONTENT_KEY == sts) {
|
||||
return KEY_NOT_FOUND_4;
|
||||
} else {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenericSign(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
std::string* signature) {
|
||||
LOGV("GenericSign: id=%ld", (uint32_t)oec_session_id_);
|
||||
if (!signature) {
|
||||
LOGE("GenerateSign: null signature string");
|
||||
return INVALID_PARAMETERS_ENG_11;
|
||||
}
|
||||
|
||||
OEMCrypto_Algorithm oec_algorithm = GenericSigningAlgorithm(algorithm);
|
||||
if (oec_algorithm == kInvalidAlgorithm) {
|
||||
return INVALID_PARAMETERS_ENG_15;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts;
|
||||
size_t length = signature->size();
|
||||
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (!SelectKey(key_id)) {
|
||||
return KEY_ERROR_3;
|
||||
}
|
||||
|
||||
// At most two attempts.
|
||||
// The first attempt may fail due to buffer too short
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
sts = OEMCrypto_Generic_Sign(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), oec_algorithm,
|
||||
reinterpret_cast<uint8_t*>(const_cast<char*>(signature->data())),
|
||||
&length);
|
||||
|
||||
if (OEMCrypto_SUCCESS == sts) {
|
||||
// Trim signature buffer and done
|
||||
signature->resize(length);
|
||||
return NO_ERROR;
|
||||
}
|
||||
if (OEMCrypto_ERROR_SHORT_BUFFER != sts) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Retry with proper-sized return buffer
|
||||
signature->resize(length);
|
||||
}
|
||||
|
||||
LOGE("GenericSign: OEMCrypto_Generic_Sign err=%d", sts);
|
||||
if (OEMCrypto_ERROR_KEY_EXPIRED == sts ||
|
||||
OEMCrypto_ERROR_NO_CONTENT_KEY == sts) {
|
||||
return KEY_NOT_FOUND_5;
|
||||
} else {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType CryptoSession::GenericVerify(const std::string& message,
|
||||
const std::string& key_id,
|
||||
CdmSigningAlgorithm algorithm,
|
||||
const std::string& signature) {
|
||||
LOGV("GenericVerify: id=%ld", (uint32_t)oec_session_id_);
|
||||
|
||||
OEMCrypto_Algorithm oec_algorithm = GenericSigningAlgorithm(algorithm);
|
||||
if (oec_algorithm == kInvalidAlgorithm) {
|
||||
return INVALID_PARAMETERS_ENG_16;
|
||||
}
|
||||
|
||||
AutoLock auto_lock(crypto_lock_);
|
||||
if (!SelectKey(key_id)) {
|
||||
return KEY_ERROR_4;
|
||||
}
|
||||
|
||||
OEMCryptoResult sts = OEMCrypto_Generic_Verify(
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(message.data()),
|
||||
message.size(), oec_algorithm,
|
||||
reinterpret_cast<const uint8_t*>(signature.data()), signature.size());
|
||||
|
||||
if (OEMCrypto_SUCCESS != sts) {
|
||||
LOGE("GenericVerify: OEMCrypto_Generic_Verify err=%d", sts);
|
||||
if (OEMCrypto_ERROR_KEY_EXPIRED == sts ||
|
||||
OEMCrypto_ERROR_NO_CONTENT_KEY == sts) {
|
||||
return KEY_NOT_FOUND_6;
|
||||
} else {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
OEMCrypto_Algorithm CryptoSession::GenericSigningAlgorithm(
|
||||
CdmSigningAlgorithm algorithm) {
|
||||
if (kSigningAlgorithmHmacSha256 == algorithm) {
|
||||
return OEMCrypto_HMAC_SHA256;
|
||||
} else {
|
||||
return kInvalidAlgorithm;
|
||||
}
|
||||
}
|
||||
|
||||
OEMCrypto_Algorithm CryptoSession::GenericEncryptionAlgorithm(
|
||||
CdmEncryptionAlgorithm algorithm) {
|
||||
if (kEncryptionAlgorithmAesCbc128 == algorithm) {
|
||||
return OEMCrypto_AES_CBC_128_NO_PADDING;
|
||||
} else {
|
||||
return kInvalidAlgorithm;
|
||||
}
|
||||
}
|
||||
|
||||
size_t CryptoSession::GenericEncryptionBlockSize(
|
||||
CdmEncryptionAlgorithm algorithm) {
|
||||
if (kEncryptionAlgorithmAesCbc128 == algorithm) {
|
||||
return kAes128BlockSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -34,19 +34,13 @@ using video_widevine_client::sdk::UsageInfo_ProviderSession;
|
||||
|
||||
namespace {
|
||||
|
||||
const char kCertificateFileNamePrefix[] = "cert";
|
||||
const char kCertificateFileNameExt[] = ".bin";
|
||||
const char kCertificateFileName[] = "cert.bin";
|
||||
const char kHlsAttributesFileNameExt[] = ".hal";
|
||||
const char kUsageInfoFileNamePrefix[] = "usage";
|
||||
const char kUsageInfoFileNameExt[] = ".bin";
|
||||
const char kLicenseFileNameExt[] = ".lic";
|
||||
const char kEmptyFileName[] = "";
|
||||
const char kWildcard[] = "*";
|
||||
const char kDirectoryDelimiter = '/';
|
||||
const char* kSecurityLevelPathCompatibilityExclusionList[] = {
|
||||
"ay64.dat", "ay64.dat2", "ay64.dat3"};
|
||||
size_t kSecurityLevelPathCompatibilityExclusionListSize =
|
||||
sizeof(kSecurityLevelPathCompatibilityExclusionList) /
|
||||
sizeof(*kSecurityLevelPathCompatibilityExclusionList);
|
||||
|
||||
bool Hash(const std::string& data, std::string* hash) {
|
||||
if (!hash) return false;
|
||||
@@ -66,30 +60,30 @@ namespace wvcdm {
|
||||
// static
|
||||
std::set<std::string> DeviceFiles::reserved_license_ids_;
|
||||
|
||||
DeviceFiles::DeviceFiles()
|
||||
: file_(NULL),
|
||||
DeviceFiles::DeviceFiles(FileSystem* file_system)
|
||||
: file_system_(file_system),
|
||||
security_level_(kSecurityLevelUninitialized),
|
||||
initialized_(false),
|
||||
test_file_(false) {}
|
||||
initialized_(false) {}
|
||||
|
||||
DeviceFiles::~DeviceFiles() {
|
||||
if (test_file_) file_.release();
|
||||
}
|
||||
DeviceFiles::~DeviceFiles() {}
|
||||
|
||||
bool DeviceFiles::Init(CdmSecurityLevel security_level) {
|
||||
if (!file_system_) {
|
||||
LOGD("DeviceFiles::Init: Invalid FileSystem given.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level, &path)) {
|
||||
LOGW("DeviceFiles::Init: Unsupported security level %d", security_level);
|
||||
return false;
|
||||
}
|
||||
if (!test_file_) file_.reset(new File());
|
||||
security_level_ = security_level;
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreCertificate(const std::string& origin,
|
||||
const std::string& certificate,
|
||||
bool DeviceFiles::StoreCertificate(const std::string& certificate,
|
||||
const std::string& wrapped_private_key) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::StoreCertificate: not initialized");
|
||||
@@ -109,23 +103,18 @@ bool DeviceFiles::StoreCertificate(const std::string& origin,
|
||||
std::string serialized_file;
|
||||
file.SerializeToString(&serialized_file);
|
||||
|
||||
return StoreFileWithHash(GetCertificateFileName(origin), serialized_file);
|
||||
return StoreFileWithHash(GetCertificateFileName(), serialized_file);
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveCertificate(const std::string& origin,
|
||||
std::string* certificate,
|
||||
bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
std::string* wrapped_private_key) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RetrieveCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Properties::security_level_path_backward_compatibility_support()) {
|
||||
SecurityLevelPathBackwardCompatibility();
|
||||
}
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (!RetrieveHashedFile(GetCertificateFileName(origin), &file)) {
|
||||
if (!RetrieveHashedFile(GetCertificateFileName(), &file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -151,22 +140,22 @@ bool DeviceFiles::RetrieveCertificate(const std::string& origin,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::HasCertificate(const std::string& origin) {
|
||||
bool DeviceFiles::HasCertificate() {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::HasCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return FileExists(GetCertificateFileName(origin));
|
||||
return FileExists(GetCertificateFileName());
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveCertificate(const std::string& origin) {
|
||||
bool DeviceFiles::RemoveCertificate() {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RemoveCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return RemoveFile(GetCertificateFileName(origin));
|
||||
return RemoveFile(GetCertificateFileName());
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreLicense(
|
||||
@@ -536,11 +525,6 @@ bool DeviceFiles::RetrieveUsageInfoByKeySetId(
|
||||
|
||||
bool DeviceFiles::StoreFileWithHash(const std::string& name,
|
||||
const std::string& serialized_file) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::StoreFileWithHash: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
// calculate SHA hash
|
||||
std::string hash;
|
||||
if (!Hash(serialized_file, &hash)) {
|
||||
@@ -561,30 +545,23 @@ bool DeviceFiles::StoreFileWithHash(const std::string& name,
|
||||
|
||||
bool DeviceFiles::StoreFileRaw(const std::string& name,
|
||||
const std::string& serialized_file) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::StoreFileRaw: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::StoreFileRaw: Unable to get base path");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file_->IsDirectory(path)) {
|
||||
if (!file_->CreateDirectory(path)) return false;
|
||||
}
|
||||
|
||||
path += name;
|
||||
|
||||
if (!file_->Open(path, File::kCreate | File::kTruncate | File::kBinary)) {
|
||||
File* file =
|
||||
file_system_->Open(path, FileSystem::kCreate | FileSystem::kTruncate);
|
||||
if (!file) {
|
||||
LOGW("DeviceFiles::StoreFileRaw: File open failed: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t bytes = file_->Write(serialized_file.data(), serialized_file.size());
|
||||
file_->Close();
|
||||
ssize_t bytes = file->Write(serialized_file.data(), serialized_file.size());
|
||||
file->Close();
|
||||
|
||||
if (bytes != static_cast<ssize_t>(serialized_file.size())) {
|
||||
LOGW(
|
||||
@@ -599,16 +576,12 @@ bool DeviceFiles::StoreFileRaw(const std::string& name,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
video_widevine_client::sdk::File* file) {
|
||||
bool DeviceFiles::RetrieveHashedFile(
|
||||
const std::string& name,
|
||||
video_widevine_client::sdk::File* deserialized_file) {
|
||||
std::string serialized_file;
|
||||
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
if (!deserialized_file) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Unspecified file parameter");
|
||||
return false;
|
||||
}
|
||||
@@ -621,29 +594,30 @@ bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
|
||||
path += name;
|
||||
|
||||
if (!file_->Exists(path)) {
|
||||
if (!file_system_->Exists(path)) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: %s does not exist", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t bytes = file_->FileSize(path);
|
||||
ssize_t bytes = file_system_->FileSize(path);
|
||||
if (bytes <= 0) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: File size invalid: %s",
|
||||
path.c_str());
|
||||
// Remove the corrupted file so the caller will not get the same error
|
||||
// when trying to access the file repeatedly, causing the system to stall.
|
||||
file_->Remove(path);
|
||||
file_system_->Remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file_->Open(path, File::kReadOnly | File::kBinary)) {
|
||||
File* file = file_system_->Open(path, FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string serialized_hash_file;
|
||||
serialized_hash_file.resize(bytes);
|
||||
bytes = file_->Read(&serialized_hash_file[0], serialized_hash_file.size());
|
||||
file_->Close();
|
||||
bytes = file->Read(&serialized_hash_file[0], serialized_hash_file.size());
|
||||
file->Close();
|
||||
|
||||
if (bytes != static_cast<ssize_t>(serialized_hash_file.size())) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: read failed");
|
||||
@@ -669,11 +643,11 @@ bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Hash mismatch");
|
||||
// Remove the corrupted file so the caller will not get the same error
|
||||
// when trying to access the file repeatedly, causing the system to stall.
|
||||
file_->Remove(path);
|
||||
file_system_->Remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file->ParseFromString(hash_file.file())) {
|
||||
if (!deserialized_file->ParseFromString(hash_file.file())) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Unable to parse file");
|
||||
return false;
|
||||
}
|
||||
@@ -681,11 +655,6 @@ bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
}
|
||||
|
||||
bool DeviceFiles::FileExists(const std::string& name) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::FileExists: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::FileExists: Unable to get base path");
|
||||
@@ -693,15 +662,10 @@ bool DeviceFiles::FileExists(const std::string& name) {
|
||||
}
|
||||
path += name;
|
||||
|
||||
return file_->Exists(path);
|
||||
return file_system_->Exists(path);
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveFile(const std::string& name) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::RemoveFile: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::RemoveFile: Unable to get base path");
|
||||
@@ -709,15 +673,10 @@ bool DeviceFiles::RemoveFile(const std::string& name) {
|
||||
}
|
||||
path += name;
|
||||
|
||||
return file_->Remove(path);
|
||||
return file_system_->Remove(path);
|
||||
}
|
||||
|
||||
ssize_t DeviceFiles::GetFileSize(const std::string& name) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::GetFileSize: Invalid file handle");
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::GetFileSize: Unable to get base path");
|
||||
@@ -725,79 +684,11 @@ ssize_t DeviceFiles::GetFileSize(const std::string& name) {
|
||||
}
|
||||
path += name;
|
||||
|
||||
return file_->FileSize(path);
|
||||
return file_system_->FileSize(path);
|
||||
}
|
||||
|
||||
void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get base path");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> security_dirs;
|
||||
if (!Properties::GetSecurityLevelDirectories(&security_dirs)) {
|
||||
LOGW(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get security directories");
|
||||
return;
|
||||
}
|
||||
|
||||
size_t pos = std::string::npos;
|
||||
for (size_t i = 0; i < security_dirs.size(); ++i) {
|
||||
pos = path.find(security_dirs[i]);
|
||||
if (pos != std::string::npos && pos > 0 &&
|
||||
pos == path.size() - security_dirs[i].size() &&
|
||||
path[pos - 1] == kDirectoryDelimiter) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == std::string::npos) {
|
||||
LOGV(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Security level "
|
||||
"specific path not found. Check properties?");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string from_dir(path, 0, pos);
|
||||
|
||||
std::vector<std::string> files;
|
||||
if (!file_->List(from_dir, &files)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < files.size(); ++i) {
|
||||
std::string from = from_dir + files[i];
|
||||
bool exclude = false;
|
||||
for (size_t j = 0; j < kSecurityLevelPathCompatibilityExclusionListSize;
|
||||
++j) {
|
||||
if (files[i] == kSecurityLevelPathCompatibilityExclusionList[j]) {
|
||||
exclude = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exclude) continue;
|
||||
if (!file_->IsRegularFile(from)) continue;
|
||||
|
||||
for (size_t j = 0; j < security_dirs.size(); ++j) {
|
||||
std::string to_dir = from_dir + security_dirs[j];
|
||||
if (!file_->Exists(to_dir)) file_->CreateDirectory(to_dir);
|
||||
std::string to = to_dir + files[i];
|
||||
file_->Copy(from, to);
|
||||
}
|
||||
file_->Remove(from);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetCertificateFileName(const std::string& origin) {
|
||||
std::string hash;
|
||||
if (origin != EMPTY_ORIGIN) {
|
||||
hash = GetFileNameSafeHash(origin);
|
||||
}
|
||||
return kCertificateFileNamePrefix + hash + kCertificateFileNameExt;
|
||||
std::string DeviceFiles::GetCertificateFileName() {
|
||||
return kCertificateFileName;
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetLicenseFileNameExtension() {
|
||||
@@ -820,9 +711,4 @@ std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) {
|
||||
return wvcdm::Base64SafeEncode(hash);
|
||||
}
|
||||
|
||||
void DeviceFiles::SetTestFile(File* file) {
|
||||
file_.reset(file);
|
||||
test_file_ = true;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
285
libwvdrmengine/cdm/core/src/license_key_status.cpp
Normal file
285
libwvdrmengine/cdm/core/src/license_key_status.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "license_key_status.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
namespace {
|
||||
// License protocol aliases
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer;
|
||||
typedef KeyContainer::OutputProtection OutputProtection;
|
||||
typedef KeyContainer::VideoResolutionConstraint VideoResolutionConstraint;
|
||||
typedef ::google::protobuf::RepeatedPtrField<VideoResolutionConstraint>
|
||||
ConstraintList;
|
||||
|
||||
// Map the HDCP protection associated with a key in the license to
|
||||
// an equivalent OEMCrypto HDCP protection level
|
||||
wvcdm::CryptoSession::HdcpCapability ProtobufHdcpToOemCryptoHdcp(
|
||||
const OutputProtection::HDCP& input) {
|
||||
switch (input) {
|
||||
case OutputProtection::HDCP_NONE:
|
||||
return HDCP_NONE;
|
||||
case OutputProtection::HDCP_V1:
|
||||
return HDCP_V1;
|
||||
case OutputProtection::HDCP_V2:
|
||||
return HDCP_V2;
|
||||
case OutputProtection::HDCP_V2_1:
|
||||
return HDCP_V2_1;
|
||||
case OutputProtection::HDCP_V2_2:
|
||||
return HDCP_V2_2;
|
||||
case OutputProtection::HDCP_NO_DIGITAL_OUTPUT:
|
||||
return HDCP_NO_DIGITAL_OUTPUT;
|
||||
default:
|
||||
LOGE("ContentKeyStatus::ProtobufHdcpToOemCryptoHdcp: "
|
||||
"Unknown HDCP Level: input=%d, returning HDCP_NO_DIGITAL_OUTPUT",
|
||||
input);
|
||||
return HDCP_NO_DIGITAL_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the constraint from a set of constraints that matches the
|
||||
// specified resolution, or null if none match
|
||||
VideoResolutionConstraint* GetConstraintForRes(
|
||||
uint32_t res, ConstraintList& constraints_from_key) {
|
||||
typedef ConstraintList::pointer_iterator Iterator;
|
||||
for (Iterator i = constraints_from_key.pointer_begin();
|
||||
i != constraints_from_key.pointer_end(); ++i) {
|
||||
VideoResolutionConstraint* constraint = *i;
|
||||
if (constraint->has_min_resolution_pixels() &&
|
||||
constraint->has_max_resolution_pixels() &&
|
||||
res >= constraint->min_resolution_pixels() &&
|
||||
res <= constraint->max_resolution_pixels()) {
|
||||
return constraint;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
bool LicenseKeys::IsContentKey(const std::string& key_id) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->IsContentKey();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LicenseKeys::CanDecryptContent(const std::string& key_id) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->CanDecryptContent();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LicenseKeys::GetAllowedUsage(const KeyId& key_id,
|
||||
CdmKeyAllowedUsage* allowed_usage) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->GetAllowedUsage(allowed_usage);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool LicenseKeys::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_keys) {
|
||||
bool keys_changed = false;
|
||||
bool newly_usable = false;
|
||||
*new_usable_keys = false;
|
||||
for (LicenseKeyStatusIterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
bool usable;
|
||||
if (it->second->ApplyStatusChange(new_status, &usable)) {
|
||||
newly_usable |= usable;
|
||||
keys_changed = true;
|
||||
}
|
||||
}
|
||||
*new_usable_keys = newly_usable;
|
||||
return keys_changed;
|
||||
}
|
||||
|
||||
void LicenseKeys::ExtractKeyStatuses(CdmKeyStatusMap* content_keys) {
|
||||
for (LicenseKeyStatusIterator it = keys_.begin(); it != keys_.end(); ++it) {
|
||||
if (it->second->IsContentKey()) {
|
||||
const KeyId key_id = it->first;
|
||||
CdmKeyStatus key_status = it->second->GetKeyStatus();
|
||||
(*content_keys)[key_id] = key_status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LicenseKeys::MeetsConstraints(const KeyId& key_id) {
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->MeetsConstraints();
|
||||
} else {
|
||||
// If a Key ID is unknown to us, we don't know of any constraints for it,
|
||||
// so never block decryption.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseKeys::ApplyConstraints(
|
||||
uint32_t new_resolution, CryptoSession::HdcpCapability new_hdcp_level) {
|
||||
for (LicenseKeyStatusIterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
i->second->ApplyConstraints(new_resolution, new_hdcp_level);
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseKeys::SetFromLicense(
|
||||
const video_widevine_server::sdk::License& license) {
|
||||
this->Clear();
|
||||
for (int32_t key_index = 0; key_index < license.key_size(); ++key_index) {
|
||||
const KeyContainer& key = license.key(key_index);
|
||||
if (key.has_id() && (key.type() == KeyContainer::CONTENT ||
|
||||
key.type() == KeyContainer::OPERATOR_SESSION)) {
|
||||
const KeyId& key_id = key.id();
|
||||
keys_[key_id] = new LicenseKeyStatus(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LicenseKeyStatus::LicenseKeyStatus(const KeyContainer& key) :
|
||||
is_content_key_(false),
|
||||
key_status_(kKeyStatusInternalError),
|
||||
meets_constraints_(true),
|
||||
default_hdcp_level_(HDCP_NONE) {
|
||||
|
||||
allowed_usage_.Clear();
|
||||
constraints_.Clear();
|
||||
|
||||
if (key.type() == KeyContainer::CONTENT) {
|
||||
ParseContentKey(key);
|
||||
} else if (key.type() == KeyContainer::OPERATOR_SESSION) {
|
||||
ParseOperatorSessionKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseKeyStatus::ParseContentKey(const KeyContainer& key) {
|
||||
is_content_key_ = true;
|
||||
if (key.has_level() &&
|
||||
((key.level() == KeyContainer::HW_SECURE_DECODE) ||
|
||||
(key.level() == KeyContainer::HW_SECURE_ALL))) {
|
||||
allowed_usage_.decrypt_to_clear_buffer = false;
|
||||
allowed_usage_.decrypt_to_secure_buffer = true;
|
||||
} else {
|
||||
allowed_usage_.decrypt_to_clear_buffer = true;
|
||||
allowed_usage_.decrypt_to_secure_buffer = true;
|
||||
}
|
||||
allowed_usage_.SetValid();
|
||||
|
||||
if (key.video_resolution_constraints_size() > 0) {
|
||||
SetConstraints(key.video_resolution_constraints());
|
||||
}
|
||||
|
||||
if (key.has_required_protection()) {
|
||||
default_hdcp_level_ =
|
||||
ProtobufHdcpToOemCryptoHdcp(key.required_protection().hdcp());
|
||||
}
|
||||
}
|
||||
|
||||
void LicenseKeyStatus::ParseOperatorSessionKey(const KeyContainer& key) {
|
||||
is_content_key_ = false;
|
||||
if (key.has_operator_session_key_permissions()) {
|
||||
OperatorSessionKeyPermissions permissions =
|
||||
key.operator_session_key_permissions();
|
||||
if (permissions.has_allow_encrypt())
|
||||
allowed_usage_.generic_encrypt = permissions.allow_encrypt();
|
||||
if (permissions.has_allow_decrypt())
|
||||
allowed_usage_.generic_decrypt = permissions.allow_decrypt();
|
||||
if (permissions.has_allow_sign())
|
||||
allowed_usage_.generic_sign = permissions.allow_sign();
|
||||
if (permissions.has_allow_signature_verify())
|
||||
allowed_usage_.generic_verify = permissions.allow_signature_verify();
|
||||
} else {
|
||||
allowed_usage_.generic_encrypt = false;
|
||||
allowed_usage_.generic_decrypt = false;
|
||||
allowed_usage_.generic_sign = false;
|
||||
allowed_usage_.generic_verify = false;
|
||||
}
|
||||
allowed_usage_.SetValid();
|
||||
}
|
||||
|
||||
void LicenseKeys::Clear() {
|
||||
for (LicenseKeyStatusIterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
delete i->second;
|
||||
}
|
||||
keys_.clear();
|
||||
}
|
||||
|
||||
bool LicenseKeyStatus::CanDecryptContent() {
|
||||
return is_content_key_ && key_status_ == kKeyStatusUsable;
|
||||
}
|
||||
|
||||
bool LicenseKeyStatus::GetAllowedUsage(CdmKeyAllowedUsage* allowed_usage) {
|
||||
if (NULL == allowed_usage)
|
||||
return false;
|
||||
*allowed_usage = allowed_usage_;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LicenseKeyStatus::ApplyStatusChange(CdmKeyStatus new_status,
|
||||
bool* new_usable_key) {
|
||||
*new_usable_key = false;
|
||||
if (!is_content_key_) {
|
||||
return false;
|
||||
}
|
||||
CdmKeyStatus updated_status = new_status;
|
||||
if (updated_status == kKeyStatusUsable) {
|
||||
if (!MeetsConstraints()) {
|
||||
updated_status = kKeyStatusOutputNotAllowed;
|
||||
}
|
||||
}
|
||||
if (key_status_ != updated_status) {
|
||||
key_status_ = updated_status;
|
||||
if (updated_status == kKeyStatusUsable) {
|
||||
*new_usable_key = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the key has constraints, find the constraint that applies.
|
||||
// If none found, then the constraint test fails.
|
||||
// If a constraint is found, verify that the device's current HDCP
|
||||
// level is sufficient. If the constraint has an HDCP setting, use it,
|
||||
// If the key has no constraints, or if the constraint has no HDCP
|
||||
// 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) {
|
||||
|
||||
VideoResolutionConstraint* current_constraint = NULL;
|
||||
if (HasConstraints()) {
|
||||
current_constraint = GetConstraintForRes(new_resolution, constraints_);
|
||||
if (NULL == current_constraint) {
|
||||
meets_constraints_ = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CryptoSession::HdcpCapability desired_hdcp_level;
|
||||
if (current_constraint && current_constraint->has_required_protection()) {
|
||||
desired_hdcp_level = ProtobufHdcpToOemCryptoHdcp(
|
||||
current_constraint->required_protection().hdcp());
|
||||
} else {
|
||||
desired_hdcp_level = default_hdcp_level_;
|
||||
}
|
||||
|
||||
meets_constraints_ = (new_hdcp_level >= desired_hdcp_level);
|
||||
}
|
||||
|
||||
void LicenseKeyStatus::SetConstraints(const ConstraintList& constraints) {
|
||||
if (!is_content_key_) {
|
||||
return;
|
||||
}
|
||||
constraints_.Clear();
|
||||
constraints_.MergeFrom(constraints);
|
||||
meets_constraints_ = true;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
@@ -461,7 +461,7 @@ message EncryptedClientIdentification {
|
||||
optional bytes encrypted_client_id = 3;
|
||||
// Initialization vector needed to decrypt encrypted_client_id.
|
||||
optional bytes encrypted_client_id_iv = 4;
|
||||
// AES-128 privacy key, encrytped with the service public public key using
|
||||
// AES-128 privacy key, encrypted with the service public public key using
|
||||
// RSA-OAEP.
|
||||
optional bytes encrypted_privacy_key = 5;
|
||||
}
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
// Copyright 2014 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "max_res_engine.h"
|
||||
|
||||
#include "clock.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const int64_t kHdcpCheckInterval = 10;
|
||||
const uint32_t kNoResolution = 0;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
MaxResEngine::MaxResEngine(CryptoSession* crypto_session) {
|
||||
Init(crypto_session, new Clock());
|
||||
}
|
||||
|
||||
MaxResEngine::MaxResEngine(CryptoSession* crypto_session, Clock* clock) {
|
||||
Init(crypto_session, clock);
|
||||
}
|
||||
|
||||
MaxResEngine::~MaxResEngine() {
|
||||
AutoLock lock(status_lock_);
|
||||
DeleteAllKeys();
|
||||
}
|
||||
|
||||
bool MaxResEngine::CanDecrypt(const KeyId& key_id) {
|
||||
AutoLock lock(status_lock_);
|
||||
if (keys_.count(key_id) > 0) {
|
||||
return keys_[key_id]->can_decrypt();
|
||||
} else {
|
||||
// If a Key ID is unknown to us, we don't know of any constraints for it,
|
||||
// so never block decryption.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void MaxResEngine::Init(CryptoSession* crypto_session, Clock* clock) {
|
||||
AutoLock lock(status_lock_);
|
||||
current_resolution_ = kNoResolution;
|
||||
clock_.reset(clock);
|
||||
next_check_time_ = clock_->GetCurrentTime();
|
||||
crypto_session_ = crypto_session;
|
||||
}
|
||||
|
||||
void MaxResEngine::SetLicense(
|
||||
const video_widevine_server::sdk::License& license) {
|
||||
AutoLock lock(status_lock_);
|
||||
DeleteAllKeys();
|
||||
for (int32_t key_index = 0; key_index < license.key_size(); ++key_index) {
|
||||
const KeyContainer& key = license.key(key_index);
|
||||
if (key.type() == KeyContainer::CONTENT && key.has_id() &&
|
||||
key.video_resolution_constraints_size() > 0) {
|
||||
const ConstraintList& constraints = key.video_resolution_constraints();
|
||||
const KeyId& key_id = key.id();
|
||||
if (key.has_required_protection()) {
|
||||
keys_[key_id] =
|
||||
new KeyStatus(constraints, key.required_protection().hdcp());
|
||||
} else {
|
||||
keys_[key_id] = new KeyStatus(constraints);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaxResEngine::SetResolution(uint32_t width, uint32_t height) {
|
||||
AutoLock lock(status_lock_);
|
||||
current_resolution_ = width * height;
|
||||
}
|
||||
|
||||
void MaxResEngine::OnTimerEvent() {
|
||||
AutoLock lock(status_lock_);
|
||||
int64_t current_time = clock_->GetCurrentTime();
|
||||
if (!keys_.empty() && current_resolution_ != kNoResolution &&
|
||||
current_time >= next_check_time_) {
|
||||
CryptoSession::HdcpCapability current_hdcp_level;
|
||||
CryptoSession::HdcpCapability ignored;
|
||||
if (!crypto_session_->GetHdcpCapabilities(¤t_hdcp_level, &ignored)) {
|
||||
current_hdcp_level = HDCP_NONE;
|
||||
}
|
||||
for (KeyIterator i = keys_.begin(); i != keys_.end(); ++i) {
|
||||
i->second->Update(current_resolution_, current_hdcp_level);
|
||||
}
|
||||
next_check_time_ = current_time + kHdcpCheckInterval;
|
||||
}
|
||||
}
|
||||
|
||||
void MaxResEngine::DeleteAllKeys() {
|
||||
// This helper method assumes that status_lock_ is already held.
|
||||
for (KeyIterator i = keys_.begin(); i != keys_.end(); ++i) delete i->second;
|
||||
keys_.clear();
|
||||
}
|
||||
|
||||
MaxResEngine::KeyStatus::KeyStatus(const ConstraintList& constraints)
|
||||
: default_hdcp_level_(HDCP_NONE) {
|
||||
Init(constraints);
|
||||
}
|
||||
|
||||
MaxResEngine::KeyStatus::KeyStatus(
|
||||
const ConstraintList& constraints,
|
||||
const OutputProtection::HDCP& default_hdcp_level)
|
||||
: default_hdcp_level_(ProtobufHdcpToOemCryptoHdcp(default_hdcp_level)) {
|
||||
Init(constraints);
|
||||
}
|
||||
|
||||
void MaxResEngine::KeyStatus::Init(const ConstraintList& constraints) {
|
||||
constraints_.Clear();
|
||||
constraints_.MergeFrom(constraints);
|
||||
can_decrypt_ = true;
|
||||
}
|
||||
|
||||
void MaxResEngine::KeyStatus::Update(
|
||||
uint32_t res, CryptoSession::HdcpCapability current_hdcp_level) {
|
||||
VideoResolutionConstraint* current_constraint = GetConstraintForRes(res);
|
||||
|
||||
if (current_constraint == NULL) {
|
||||
can_decrypt_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
CryptoSession::HdcpCapability desired_hdcp_level;
|
||||
if (current_constraint->has_required_protection()) {
|
||||
desired_hdcp_level = ProtobufHdcpToOemCryptoHdcp(
|
||||
current_constraint->required_protection().hdcp());
|
||||
} else {
|
||||
desired_hdcp_level = default_hdcp_level_;
|
||||
}
|
||||
can_decrypt_ = (current_hdcp_level >= desired_hdcp_level);
|
||||
}
|
||||
|
||||
MaxResEngine::VideoResolutionConstraint*
|
||||
MaxResEngine::KeyStatus::GetConstraintForRes(uint32_t res) {
|
||||
typedef ConstraintList::pointer_iterator Iterator;
|
||||
for (Iterator i = constraints_.pointer_begin();
|
||||
i != constraints_.pointer_end(); ++i) {
|
||||
VideoResolutionConstraint* constraint = *i;
|
||||
if (constraint->has_min_resolution_pixels() &&
|
||||
constraint->has_max_resolution_pixels() &&
|
||||
res >= constraint->min_resolution_pixels() &&
|
||||
res <= constraint->max_resolution_pixels()) {
|
||||
return constraint;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CryptoSession::HdcpCapability
|
||||
MaxResEngine::KeyStatus::ProtobufHdcpToOemCryptoHdcp(
|
||||
const OutputProtection::HDCP& input) {
|
||||
switch (input) {
|
||||
case OutputProtection::HDCP_NONE:
|
||||
return HDCP_NONE;
|
||||
case OutputProtection::HDCP_V1:
|
||||
return HDCP_V1;
|
||||
case OutputProtection::HDCP_V2:
|
||||
return HDCP_V2;
|
||||
case OutputProtection::HDCP_V2_1:
|
||||
return HDCP_V2_1;
|
||||
case OutputProtection::HDCP_V2_2:
|
||||
return HDCP_V2_2;
|
||||
case OutputProtection::HDCP_NO_DIGITAL_OUTPUT:
|
||||
return HDCP_NO_DIGITAL_OUTPUT;
|
||||
default:
|
||||
LOGE("MaxResEngine::KeyStatus::ProtobufHdcpToOemCryptoHdcp: "
|
||||
"Unknown HDCP Level");
|
||||
return HDCP_NO_DIGITAL_OUTPUT;
|
||||
}
|
||||
}
|
||||
|
||||
} // wvcdm
|
||||
@@ -452,21 +452,23 @@ class Adapter {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
wvcdm::File file;
|
||||
wvcdm::FileSystem file_system;
|
||||
std::string filename;
|
||||
if (!wvcdm::Properties::GetFactoryKeyboxPath(&filename)) {
|
||||
LOGW("Bad Level 1 Keybox. Falling Back to L3.");
|
||||
level1_.Terminate();
|
||||
return false;
|
||||
}
|
||||
ssize_t size = file.FileSize(filename);
|
||||
if (size <= 0 || !file.Open(filename, file.kBinary | file.kReadOnly)) {
|
||||
ssize_t size = file_system.FileSize(filename);
|
||||
wvcdm::File* file = file_system.Open(filename, file_system.kReadOnly);
|
||||
if (size <= 0 || !file) {
|
||||
LOGW("Could not open %s. Falling Back to L3.", filename.c_str());
|
||||
level1_.Terminate();
|
||||
return false;
|
||||
}
|
||||
uint8_t keybox[size];
|
||||
ssize_t size_read = file.Read(reinterpret_cast<char*>(keybox), size);
|
||||
ssize_t size_read = file->Read(reinterpret_cast<char*>(keybox), size);
|
||||
file->Close();
|
||||
if (level1_.InstallKeybox(keybox, size) != OEMCrypto_SUCCESS) {
|
||||
LOGE("Could NOT install keybox from %s. Falling Back to L3.",
|
||||
filename.c_str());
|
||||
@@ -625,7 +627,6 @@ namespace wvcdm {
|
||||
|
||||
OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session,
|
||||
SecurityLevel level) {
|
||||
|
||||
if (!kAdapter) return OEMCrypto_ERROR_OPEN_SESSION_FAILED;
|
||||
return kAdapter->OpenSession(session, level);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@
|
||||
#include "policy_engine.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "clock.h"
|
||||
#include "log.h"
|
||||
@@ -17,6 +14,13 @@
|
||||
|
||||
using video_widevine_server::sdk::License;
|
||||
|
||||
namespace {
|
||||
|
||||
const int64_t kHdcpCheckInterval = 10;
|
||||
const uint32_t kNoResolution = 0;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
||||
@@ -32,18 +36,43 @@ PolicyEngine::PolicyEngine(CdmSessionId session_id,
|
||||
policy_max_duration_seconds_(0),
|
||||
session_id_(session_id),
|
||||
event_listener_(event_listener),
|
||||
max_res_engine_(new MaxResEngine(crypto_session)),
|
||||
clock_(new Clock) {}
|
||||
license_keys_(new LicenseKeys),
|
||||
clock_(new Clock) {
|
||||
InitDevice(crypto_session);
|
||||
}
|
||||
|
||||
PolicyEngine::~PolicyEngine() {}
|
||||
|
||||
bool PolicyEngine::CanDecrypt(const KeyId& key_id) {
|
||||
if (keys_status_.find(key_id) == keys_status_.end()) {
|
||||
if (license_keys_->IsContentKey(key_id)) {
|
||||
return license_keys_->CanDecryptContent(key_id);
|
||||
} else {
|
||||
LOGE("PolicyEngine::CanDecrypt Key '%s' not in license.",
|
||||
b2a_hex(key_id).c_str());
|
||||
return false;
|
||||
}
|
||||
return keys_status_[key_id] == kKeyStatusUsable;
|
||||
}
|
||||
|
||||
void PolicyEngine::InitDevice(CryptoSession* crypto_session) {
|
||||
current_resolution_ = kNoResolution;
|
||||
next_device_check_ = 0;
|
||||
crypto_session_ = crypto_session;
|
||||
}
|
||||
|
||||
void PolicyEngine::CheckDevice(int64_t current_time) {
|
||||
if (current_time < next_device_check_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!license_keys_->Empty() && current_resolution_ != kNoResolution) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void PolicyEngine::OnTimerEvent() {
|
||||
@@ -57,7 +86,8 @@ void PolicyEngine::OnTimerEvent() {
|
||||
return;
|
||||
}
|
||||
|
||||
max_res_engine_->OnTimerEvent();
|
||||
// Check device conditions that affect playability (HDCP, resolution)
|
||||
CheckDevice(current_time);
|
||||
|
||||
bool renewal_needed = false;
|
||||
|
||||
@@ -110,17 +140,8 @@ void PolicyEngine::SetLicense(const License& license) {
|
||||
license_id_.Clear();
|
||||
license_id_.CopyFrom(license.id());
|
||||
policy_.Clear();
|
||||
|
||||
// Extract content key ids.
|
||||
keys_status_.clear();
|
||||
for (int key_index = 0; key_index < license.key_size(); ++key_index) {
|
||||
const License::KeyContainer& key = license.key(key_index);
|
||||
if (key.type() == License::KeyContainer::CONTENT && key.has_id())
|
||||
keys_status_[key.id()] = kKeyStatusInternalError;
|
||||
}
|
||||
|
||||
license_keys_->SetFromLicense(license);
|
||||
UpdateLicense(license);
|
||||
max_res_engine_->SetLicense(license);
|
||||
}
|
||||
|
||||
void PolicyEngine::SetLicenseForRelease(const License& license) {
|
||||
@@ -130,7 +151,6 @@ void PolicyEngine::SetLicenseForRelease(const License& license) {
|
||||
|
||||
// Expire any old keys.
|
||||
NotifyKeysChange(kKeyStatusExpired);
|
||||
|
||||
UpdateLicense(license);
|
||||
}
|
||||
|
||||
@@ -220,7 +240,7 @@ void PolicyEngine::DecryptionEvent() {
|
||||
}
|
||||
|
||||
void PolicyEngine::NotifyResolution(uint32_t width, uint32_t height) {
|
||||
max_res_engine_->SetResolution(width, height);
|
||||
SetDeviceResolution(width, height);
|
||||
}
|
||||
|
||||
void PolicyEngine::NotifySessionExpiration() {
|
||||
@@ -228,35 +248,46 @@ void PolicyEngine::NotifySessionExpiration() {
|
||||
NotifyKeysChange(kKeyStatusExpired);
|
||||
}
|
||||
|
||||
CdmResponseType PolicyEngine::Query(CdmQueryMap* key_info) {
|
||||
CdmResponseType PolicyEngine::Query(CdmQueryMap* query_response) {
|
||||
std::stringstream ss;
|
||||
int64_t current_time = clock_->GetCurrentTime();
|
||||
|
||||
if (license_state_ == kLicenseStateInitial) {
|
||||
key_info->clear();
|
||||
query_response->clear();
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
(*key_info)[QUERY_KEY_LICENSE_TYPE] =
|
||||
(*query_response)[QUERY_KEY_LICENSE_TYPE] =
|
||||
license_id_.type() == video_widevine_server::sdk::STREAMING
|
||||
? QUERY_VALUE_STREAMING
|
||||
: QUERY_VALUE_OFFLINE;
|
||||
(*key_info)[QUERY_KEY_PLAY_ALLOWED] =
|
||||
(*query_response)[QUERY_KEY_PLAY_ALLOWED] =
|
||||
policy_.can_play() ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
(*key_info)[QUERY_KEY_PERSIST_ALLOWED] =
|
||||
(*query_response)[QUERY_KEY_PERSIST_ALLOWED] =
|
||||
policy_.can_persist() ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
(*key_info)[QUERY_KEY_RENEW_ALLOWED] =
|
||||
(*query_response)[QUERY_KEY_RENEW_ALLOWED] =
|
||||
policy_.can_renew() ? QUERY_VALUE_TRUE : QUERY_VALUE_FALSE;
|
||||
ss << GetLicenseDurationRemaining(current_time);
|
||||
(*key_info)[QUERY_KEY_LICENSE_DURATION_REMAINING] = ss.str();
|
||||
(*query_response)[QUERY_KEY_LICENSE_DURATION_REMAINING] = ss.str();
|
||||
ss.str("");
|
||||
ss << GetPlaybackDurationRemaining(current_time);
|
||||
(*key_info)[QUERY_KEY_PLAYBACK_DURATION_REMAINING] = ss.str();
|
||||
(*key_info)[QUERY_KEY_RENEWAL_SERVER_URL] = policy_.renewal_server_url();
|
||||
(*query_response)[QUERY_KEY_PLAYBACK_DURATION_REMAINING] = ss.str();
|
||||
(*query_response)[QUERY_KEY_RENEWAL_SERVER_URL] = policy_.renewal_server_url();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType PolicyEngine::QueryKeyAllowedUsage(
|
||||
const KeyId& key_id, CdmKeyAllowedUsage* key_usage) {
|
||||
if (NULL == key_usage) {
|
||||
return INVALID_PARAMETERS_ENG_12;
|
||||
}
|
||||
if (license_keys_->GetAllowedUsage(key_id, key_usage)) {
|
||||
return NO_ERROR;
|
||||
}
|
||||
return KEY_NOT_FOUND_1;
|
||||
}
|
||||
|
||||
bool PolicyEngine::GetSecondsSinceStarted(int64_t* seconds_since_started) {
|
||||
if (playback_start_time_ == 0) return false;
|
||||
|
||||
@@ -351,25 +382,14 @@ bool PolicyEngine::IsRenewalRetryIntervalExpired(int64_t current_time) {
|
||||
}
|
||||
|
||||
void PolicyEngine::NotifyKeysChange(CdmKeyStatus new_status) {
|
||||
bool keys_changed = false;
|
||||
bool keys_changed;
|
||||
bool has_new_usable_key = false;
|
||||
for (std::map<KeyId, CdmKeyStatus>::iterator it = keys_status_.begin();
|
||||
it != keys_status_.end(); ++it) {
|
||||
const KeyId key_id = it->first;
|
||||
CdmKeyStatus& key_status = it->second;
|
||||
CdmKeyStatus updated_status = new_status;
|
||||
if (updated_status == kKeyStatusUsable) {
|
||||
if (!max_res_engine_->CanDecrypt(key_id))
|
||||
updated_status = kKeyStatusOutputNotAllowed;
|
||||
}
|
||||
if (key_status != updated_status) {
|
||||
key_status = updated_status;
|
||||
if (updated_status == kKeyStatusUsable) has_new_usable_key = true;
|
||||
keys_changed = true;
|
||||
}
|
||||
}
|
||||
if (keys_changed && event_listener_) {
|
||||
event_listener_->OnSessionKeysChange(session_id_, keys_status_,
|
||||
keys_changed = license_keys_->ApplyStatusChange(new_status,
|
||||
&has_new_usable_key);
|
||||
if (event_listener_ && keys_changed) {
|
||||
CdmKeyStatusMap content_keys;
|
||||
license_keys_->ExtractKeyStatuses(&content_keys);
|
||||
event_listener_->OnSessionKeysChange(session_id_, content_keys,
|
||||
has_new_usable_key);
|
||||
}
|
||||
}
|
||||
@@ -387,8 +407,4 @@ void PolicyEngine::NotifyExpirationUpdate() {
|
||||
|
||||
void PolicyEngine::set_clock(Clock* clock) { clock_.reset(clock); }
|
||||
|
||||
void PolicyEngine::set_max_res_engine(MaxResEngine* max_res_engine) {
|
||||
max_res_engine_.reset(max_res_engine);
|
||||
}
|
||||
|
||||
} // wvcdm
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// This is because we need a valid RSA certificate, and will attempt to connect
|
||||
// to the provisioning server to request one if we don't.
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
@@ -43,6 +44,8 @@ const std::string kWebmMimeType = "video/webm";
|
||||
|
||||
class WvCdmEngineTest : public testing::Test {
|
||||
public:
|
||||
WvCdmEngineTest() : cdm_engine_(&file_system_) {}
|
||||
|
||||
static void SetUpTestCase() {
|
||||
ConfigTestEnv config(kContentProtectionUatServer);
|
||||
g_client_auth.assign(config.client_auth());
|
||||
@@ -52,19 +55,16 @@ class WvCdmEngineTest : public testing::Test {
|
||||
g_key_id_pssh.assign(a2bs_hex(config.key_id()));
|
||||
|
||||
// Extract the key ID from the PSSH box.
|
||||
InitializationData extractor(CENC_INIT_DATA_FORMAT,
|
||||
g_key_id_pssh);
|
||||
InitializationData extractor(CENC_INIT_DATA_FORMAT, g_key_id_pssh);
|
||||
g_key_id_unwrapped = extractor.data();
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
CdmResponseType status =
|
||||
cdm_engine_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, NULL,
|
||||
&session_id_);
|
||||
cdm_engine_.OpenSession(g_key_system, NULL, NULL, &session_id_);
|
||||
if (status == NEED_PROVISIONING) {
|
||||
Provision();
|
||||
status = cdm_engine_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, NULL,
|
||||
&session_id_);
|
||||
status = cdm_engine_.OpenSession(g_key_system, NULL, NULL, &session_id_);
|
||||
}
|
||||
ASSERT_EQ(NO_ERROR, status);
|
||||
ASSERT_NE("", session_id_) << "Could not open CDM session.";
|
||||
@@ -81,15 +81,15 @@ class WvCdmEngineTest : public testing::Test {
|
||||
std::string cert_authority;
|
||||
std::string cert, wrapped_key;
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.GetProvisioningRequest(
|
||||
cert_type, cert_authority, EMPTY_ORIGIN,
|
||||
&prov_request, &provisioning_server_url));
|
||||
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(EMPTY_ORIGIN,
|
||||
message, &cert,
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine_.HandleProvisioningResponse(message, &cert,
|
||||
&wrapped_key));
|
||||
}
|
||||
|
||||
@@ -113,9 +113,8 @@ class WvCdmEngineTest : public testing::Test {
|
||||
|
||||
void GenerateRenewalRequest() {
|
||||
CdmKeyRequest request;
|
||||
|
||||
EXPECT_EQ(KEY_MESSAGE, cdm_engine_.GenerateRenewalRequest(
|
||||
session_id_, &request));
|
||||
EXPECT_EQ(KEY_MESSAGE,
|
||||
cdm_engine_.GenerateRenewalRequest(session_id_, &request));
|
||||
|
||||
key_msg_ = request.message;
|
||||
server_url_ = request.url;
|
||||
@@ -177,6 +176,7 @@ 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_;
|
||||
|
||||
@@ -88,13 +88,12 @@ const std::string kWrappedKey = a2bs_hex(
|
||||
"E74C92B44F9205D22262FB47948654229DE1920F8EDF96A19A88A1CA1552F8856FB4CBF83B"
|
||||
"AA3348419159D207F65FCE9C1A500C6818");
|
||||
|
||||
const std::string kTestOrigin = "com.google";
|
||||
|
||||
class MockDeviceFiles : public DeviceFiles {
|
||||
public:
|
||||
MockDeviceFiles() : DeviceFiles(NULL) {}
|
||||
|
||||
MOCK_METHOD1(Init, bool(CdmSecurityLevel));
|
||||
MOCK_METHOD3(RetrieveCertificate, bool(const std::string&, std::string*,
|
||||
std::string*));
|
||||
MOCK_METHOD2(RetrieveCertificate, bool(std::string*, std::string*));
|
||||
};
|
||||
|
||||
class MockCryptoSession : public CryptoSession {
|
||||
@@ -136,7 +135,7 @@ using ::testing::StrEq;
|
||||
class CdmSessionTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
cdm_session_.reset(new CdmSession(kTestOrigin));
|
||||
cdm_session_.reset(new CdmSession(NULL));
|
||||
// Inject testing mocks.
|
||||
license_parser_ = new MockCdmLicense(cdm_session_->session_id());
|
||||
cdm_session_->set_license_parser(license_parser_);
|
||||
@@ -165,9 +164,8 @@ TEST_F(CdmSessionTest, InitWithCertificate) {
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(StrEq(kTestOrigin), NotNull(),
|
||||
NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||
.InSequence(crypto_session_seq)
|
||||
@@ -213,9 +211,8 @@ TEST_F(CdmSessionTest, ReInitFail) {
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(StrEq(kTestOrigin), NotNull(),
|
||||
NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(kToken), SetArgPointee<2>(kWrappedKey),
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(kToken), SetArgPointee<1>(kWrappedKey),
|
||||
Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, LoadCertificatePrivateKey(StrEq(kWrappedKey)))
|
||||
.InSequence(crypto_session_seq)
|
||||
@@ -249,8 +246,7 @@ TEST_F(CdmSessionTest, InitNeedsProvisioning) {
|
||||
.InSequence(crypto_session_seq)
|
||||
.WillOnce(Return(level));
|
||||
EXPECT_CALL(*file_handle_, Init(Eq(level))).WillOnce(Return(true));
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(StrEq(kTestOrigin), NotNull(),
|
||||
NotNull()))
|
||||
EXPECT_CALL(*file_handle_, RetrieveCertificate(NotNull(), NotNull()))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
Properties::set_use_certificates_as_identification(true);
|
||||
|
||||
@@ -1412,19 +1412,24 @@ const std::string kTestOrigin = "com.google";
|
||||
|
||||
class MockFile : public File {
|
||||
public:
|
||||
MOCK_METHOD2(Open, bool(const std::string&, int flags));
|
||||
MOCK_METHOD0(Close, void());
|
||||
MockFile() : File(NULL) {}
|
||||
~MockFile() {}
|
||||
|
||||
MOCK_METHOD2(Read, ssize_t(char*, size_t));
|
||||
MOCK_METHOD2(Write, ssize_t(const char*, size_t));
|
||||
MOCK_METHOD0(Close, void());
|
||||
};
|
||||
|
||||
class MockFileSystem : public FileSystem {
|
||||
public:
|
||||
MockFileSystem() {}
|
||||
~MockFileSystem() {}
|
||||
|
||||
MOCK_METHOD2(Open, File*(const std::string&, int flags));
|
||||
MOCK_METHOD0(IsFactoryReset, bool());
|
||||
|
||||
MOCK_METHOD1(Exists, bool(const std::string&));
|
||||
MOCK_METHOD1(Remove, bool(const std::string&));
|
||||
MOCK_METHOD2(Copy, bool(const std::string&, const std::string&));
|
||||
MOCK_METHOD2(List, bool(const std::string&, std::vector<std::string>*));
|
||||
MOCK_METHOD1(CreateDirectory, bool(const std::string));
|
||||
MOCK_METHOD1(IsDirectory, bool(const std::string&));
|
||||
MOCK_METHOD1(IsRegularFile, bool(const std::string&));
|
||||
MOCK_METHOD1(FileSize, ssize_t(const std::string&));
|
||||
};
|
||||
|
||||
@@ -1490,21 +1495,9 @@ class DeviceFilesTest : public ::testing::Test {
|
||||
class DeviceFilesStoreTest : public DeviceFilesTest,
|
||||
public ::testing::WithParamInterface<bool> {};
|
||||
|
||||
struct CertStorageVariant {
|
||||
CertStorageVariant(bool dir_exists_value, const std::string& origin_value)
|
||||
: dir_exists(dir_exists_value), origin(origin_value) {}
|
||||
class DeviceCertificateStoreTest : public DeviceFilesTest {};
|
||||
|
||||
const bool dir_exists;
|
||||
const std::string origin;
|
||||
};
|
||||
|
||||
class DeviceCertificateStoreTest
|
||||
: public DeviceFilesTest,
|
||||
public ::testing::WithParamInterface<CertStorageVariant> {};
|
||||
|
||||
class DeviceCertificateTest
|
||||
: public DeviceFilesTest,
|
||||
public ::testing::WithParamInterface<std::string> {};
|
||||
class DeviceCertificateTest : public DeviceFilesTest {};
|
||||
|
||||
class DeviceFilesSecurityLevelTest
|
||||
: public DeviceFilesTest,
|
||||
@@ -1513,8 +1506,7 @@ class DeviceFilesSecurityLevelTest
|
||||
class DeviceFilesUsageInfoTest : public DeviceFilesTest,
|
||||
public ::testing::WithParamInterface<int> {};
|
||||
|
||||
MATCHER(IsCreateFileFlagSet, "") { return File::kCreate & arg; }
|
||||
MATCHER(IsBinaryFileFlagSet, "") { return File::kBinary & arg; }
|
||||
MATCHER(IsCreateFileFlagSet, "") { return FileSystem::kCreate & arg; }
|
||||
MATCHER_P(IsStrEq, str, "") {
|
||||
// Estimating the length of data. We can have gmock provide length
|
||||
// as well as pointer to data but that will introduce a dependency on tr1
|
||||
@@ -1586,105 +1578,78 @@ MATCHER_P7(Contains, str1, str2, str3, str4, str5, str6, map7, "") {
|
||||
data.find(str6) != std::string::npos && map7_entries_present);
|
||||
}
|
||||
|
||||
TEST_P(DeviceCertificateStoreTest, StoreCertificate) {
|
||||
MockFile file;
|
||||
CertStorageVariant params = GetParam();
|
||||
TEST_F(DeviceCertificateStoreTest, StoreCertificate) {
|
||||
MockFileSystem file_system;
|
||||
std::string certificate(GenerateRandomData(kCertificateLen));
|
||||
std::string wrapped_private_key(GenerateRandomData(kWrappedKeyLen));
|
||||
std::string device_certificate_path =
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName(params.origin);
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName();
|
||||
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
.WillOnce(Return(params.dir_exists));
|
||||
if (params.dir_exists) {
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
} else {
|
||||
EXPECT_CALL(file, CreateDirectory(StrEq(device_base_path_)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
EXPECT_CALL(file, Open(StrEq(device_certificate_path),
|
||||
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
|
||||
.WillOnce(Return(true));
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system,
|
||||
Open(StrEq(device_certificate_path), IsCreateFileFlagSet()))
|
||||
.WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Write(Contains(certificate, wrapped_private_key, 0),
|
||||
Gt(certificate.size() + wrapped_private_key.size())))
|
||||
.WillOnce(ReturnArg<1>());
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Read(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
EXPECT_TRUE(device_files.StoreCertificate(params.origin, certificate,
|
||||
wrapped_private_key));
|
||||
EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
StoreCertificate, DeviceCertificateStoreTest,
|
||||
::testing::Values(CertStorageVariant(true, EMPTY_ORIGIN),
|
||||
CertStorageVariant(true, kTestOrigin),
|
||||
CertStorageVariant(false, EMPTY_ORIGIN),
|
||||
CertStorageVariant(false, kTestOrigin)));
|
||||
|
||||
TEST_P(DeviceCertificateTest, ReadCertificate) {
|
||||
MockFile file;
|
||||
std::string origin = GetParam();
|
||||
TEST_F(DeviceCertificateTest, ReadCertificate) {
|
||||
MockFileSystem file_system;
|
||||
std::string device_certificate_path =
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName(origin);
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName();
|
||||
std::string data = a2bs_hex(kTestCertificateFileData);
|
||||
|
||||
EXPECT_CALL(file, Exists(StrEq(device_certificate_path)))
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system, Exists(StrEq(device_certificate_path)))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file, FileSize(StrEq(device_certificate_path)))
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(device_certificate_path)))
|
||||
.WillOnce(Return(data.size()));
|
||||
EXPECT_CALL(file, Open(StrEq(device_certificate_path), IsBinaryFileFlagSet()))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, Open(StrEq(device_certificate_path), _))
|
||||
.WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(data.size())))
|
||||
.WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()),
|
||||
Return(data.size())));
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
if (Properties::security_level_path_backward_compatibility_support()) {
|
||||
EXPECT_CALL(file, List(_, NotNull())).WillOnce(Return(false));
|
||||
}
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
std::string certificate, wrapped_private_key;
|
||||
ASSERT_TRUE(device_files.RetrieveCertificate(origin, &certificate,
|
||||
&wrapped_private_key));
|
||||
ASSERT_TRUE(
|
||||
device_files.RetrieveCertificate(&certificate, &wrapped_private_key));
|
||||
EXPECT_EQ(kTestCertificate, b2a_hex(certificate));
|
||||
EXPECT_EQ(kTestWrappedPrivateKey, b2a_hex(wrapped_private_key));
|
||||
}
|
||||
|
||||
TEST_P(DeviceCertificateTest, HasCertificate) {
|
||||
MockFile file;
|
||||
std::string origin = GetParam();
|
||||
TEST_F(DeviceCertificateTest, HasCertificate) {
|
||||
MockFileSystem file_system;
|
||||
std::string device_certificate_path =
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName(origin);
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName();
|
||||
|
||||
EXPECT_CALL(file, Exists(StrEq(device_certificate_path)))
|
||||
EXPECT_CALL(file_system, Exists(StrEq(device_certificate_path)))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file, Open(_, _)).Times(0);
|
||||
EXPECT_CALL(file_system, Open(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
ASSERT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
// MockFile returns false.
|
||||
EXPECT_FALSE(device_files.HasCertificate(origin));
|
||||
EXPECT_FALSE(device_files.HasCertificate());
|
||||
// MockFile returns true.
|
||||
EXPECT_TRUE(device_files.HasCertificate(origin));
|
||||
EXPECT_TRUE(device_files.HasCertificate());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(CertificateUseTests, DeviceCertificateTest,
|
||||
::testing::Values(EMPTY_ORIGIN, kTestOrigin));
|
||||
|
||||
TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) {
|
||||
MockFile file;
|
||||
MockFileSystem file_system;
|
||||
std::string certificate(GenerateRandomData(kCertificateLen));
|
||||
std::string wrapped_private_key(GenerateRandomData(kWrappedKeyLen));
|
||||
|
||||
@@ -1693,55 +1658,39 @@ TEST_P(DeviceFilesSecurityLevelTest, SecurityLevel) {
|
||||
ASSERT_TRUE(
|
||||
Properties::GetDeviceFilesBasePath(security_level, &device_base_path));
|
||||
std::string device_certificate_path =
|
||||
device_base_path + DeviceFiles::GetCertificateFileName(EMPTY_ORIGIN);
|
||||
device_base_path + DeviceFiles::GetCertificateFileName();
|
||||
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path)))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(file, CreateDirectory(StrEq(device_base_path)))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
EXPECT_CALL(file, Open(StrEq(device_certificate_path),
|
||||
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
|
||||
.WillOnce(Return(true));
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system,
|
||||
Open(StrEq(device_certificate_path), IsCreateFileFlagSet()))
|
||||
.WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Write(Contains(certificate, wrapped_private_key, 0),
|
||||
Gt(certificate.size() + wrapped_private_key.size())))
|
||||
.WillOnce(ReturnArg<1>());
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Read(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(security_level));
|
||||
device_files.SetTestFile(&file);
|
||||
EXPECT_TRUE(device_files.StoreCertificate(EMPTY_ORIGIN, certificate,
|
||||
wrapped_private_key));
|
||||
EXPECT_TRUE(device_files.StoreCertificate(certificate, wrapped_private_key));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SecurityLevel, DeviceFilesSecurityLevelTest,
|
||||
::testing::Values(kSecurityLevelL1, kSecurityLevelL3));
|
||||
|
||||
TEST_P(DeviceFilesStoreTest, StoreLicense) {
|
||||
MockFile file;
|
||||
MockFileSystem file_system;
|
||||
size_t license_num = 0;
|
||||
std::string license_path = device_base_path_ +
|
||||
license_test_data[license_num].key_set_id +
|
||||
DeviceFiles::GetLicenseFileNameExtension();
|
||||
|
||||
bool dir_exists = GetParam();
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
.WillOnce(Return(dir_exists));
|
||||
if (dir_exists) {
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
} else {
|
||||
EXPECT_CALL(file, CreateDirectory(StrEq(device_base_path_)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
CdmAppParameterMap app_parameters =
|
||||
GetAppParameters(license_test_data[license_num].app_parameters);
|
||||
|
||||
EXPECT_CALL(file, Open(StrEq(license_path),
|
||||
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
|
||||
.WillOnce(Return(true));
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system, Open(StrEq(license_path), IsCreateFileFlagSet()))
|
||||
.WillOnce(Return(&file));
|
||||
EXPECT_CALL(
|
||||
file, Write(Contains(license_test_data[license_num].pssh_data,
|
||||
license_test_data[license_num].key_request,
|
||||
@@ -1755,9 +1704,8 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) {
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Read(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
EXPECT_TRUE(device_files.StoreLicense(
|
||||
license_test_data[license_num].key_set_id,
|
||||
license_test_data[license_num].license_state,
|
||||
@@ -1774,11 +1722,8 @@ TEST_P(DeviceFilesStoreTest, StoreLicense) {
|
||||
INSTANTIATE_TEST_CASE_P(StoreLicense, DeviceFilesStoreTest, ::testing::Bool());
|
||||
|
||||
TEST_F(DeviceFilesTest, StoreLicenses) {
|
||||
MockFileSystem file_system;
|
||||
MockFile file;
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
.Times(kNumberOfLicenses)
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
|
||||
for (size_t i = 0; i < kNumberOfLicenses; ++i) {
|
||||
std::string license_path = device_base_path_ +
|
||||
@@ -1788,9 +1733,8 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
|
||||
CdmAppParameterMap app_parameters =
|
||||
GetAppParameters(license_test_data[i].app_parameters);
|
||||
|
||||
EXPECT_CALL(file, Open(StrEq(license_path),
|
||||
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, Open(StrEq(license_path), IsCreateFileFlagSet()))
|
||||
.WillOnce(Return(&file));
|
||||
|
||||
EXPECT_CALL(file, Write(Contains(license_test_data[i].pssh_data,
|
||||
license_test_data[i].key_request,
|
||||
@@ -1805,9 +1749,8 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
|
||||
EXPECT_CALL(file, Close()).Times(kNumberOfLicenses);
|
||||
EXPECT_CALL(file, Read(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
for (size_t i = 0; i < kNumberOfLicenses; i++) {
|
||||
CdmAppParameterMap app_parameters =
|
||||
GetAppParameters(license_test_data[i].app_parameters);
|
||||
@@ -1825,6 +1768,7 @@ TEST_F(DeviceFilesTest, StoreLicenses) {
|
||||
}
|
||||
|
||||
TEST_F(DeviceFilesTest, RetrieveLicenses) {
|
||||
MockFileSystem file_system;
|
||||
MockFile file;
|
||||
|
||||
for (size_t i = 0; i < kNumberOfLicenses; ++i) {
|
||||
@@ -1834,10 +1778,12 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) {
|
||||
|
||||
size_t size = license_test_data[i].file_data.size();
|
||||
|
||||
EXPECT_CALL(file, Exists(StrEq(license_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, FileSize(StrEq(license_path))).WillOnce(Return(size));
|
||||
EXPECT_CALL(file, Open(StrEq(license_path), IsBinaryFileFlagSet()))
|
||||
EXPECT_CALL(file_system, Exists(StrEq(license_path)))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(license_path)))
|
||||
.WillOnce(Return(size));
|
||||
EXPECT_CALL(file_system, Open(StrEq(license_path), _))
|
||||
.WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(size)))
|
||||
.WillOnce(
|
||||
DoAll(SetArrayArgument<0>(license_test_data[i].file_data.begin(),
|
||||
@@ -1847,9 +1793,8 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) {
|
||||
EXPECT_CALL(file, Close()).Times(kNumberOfLicenses);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
CdmInitData pssh_data;
|
||||
CdmKeyMessage key_request;
|
||||
CdmKeyResponse key_response;
|
||||
@@ -1886,7 +1831,7 @@ TEST_F(DeviceFilesTest, RetrieveLicenses) {
|
||||
}
|
||||
|
||||
TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) {
|
||||
MockFile file;
|
||||
MockFileSystem file_system;
|
||||
LicenseInfo* test_data =
|
||||
&license_app_parameters_backwards_compatibility_test_data;
|
||||
|
||||
@@ -1895,10 +1840,12 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) {
|
||||
|
||||
size_t size = test_data->file_data.size();
|
||||
|
||||
EXPECT_CALL(file, Exists(StrEq(license_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, FileSize(StrEq(license_path))).WillOnce(Return(size));
|
||||
EXPECT_CALL(file, Open(StrEq(license_path), IsBinaryFileFlagSet()))
|
||||
.WillOnce(Return(true));
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system, Exists(StrEq(license_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(license_path)))
|
||||
.WillOnce(Return(size));
|
||||
EXPECT_CALL(file_system, Open(StrEq(license_path), _))
|
||||
.WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(size)))
|
||||
.WillOnce(DoAll(SetArrayArgument<0>(test_data->file_data.begin(),
|
||||
test_data->file_data.end()),
|
||||
@@ -1907,9 +1854,8 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) {
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
DeviceFiles::LicenseState license_state;
|
||||
CdmInitData pssh_data;
|
||||
CdmKeyMessage key_request;
|
||||
@@ -1936,102 +1882,16 @@ TEST_F(DeviceFilesTest, AppParametersBackwardCompatibility) {
|
||||
EXPECT_EQ(0u, app_parameters.size());
|
||||
}
|
||||
|
||||
TEST_F(DeviceFilesTest, SecurityLevelPathBackwardCompatibility) {
|
||||
if (!Properties::security_level_path_backward_compatibility_support()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MockFile file;
|
||||
std::vector<std::string> security_dirs;
|
||||
EXPECT_TRUE(Properties::GetSecurityLevelDirectories(&security_dirs));
|
||||
|
||||
size_t pos = std::string::npos;
|
||||
for (size_t i = 0; i < security_dirs.size(); ++i) {
|
||||
pos = device_base_path_.rfind(security_dirs[i]);
|
||||
if (std::string::npos != pos) break;
|
||||
}
|
||||
|
||||
EXPECT_NE(std::string::npos, pos);
|
||||
|
||||
std::string base_path(device_base_path_, 0, pos);
|
||||
std::vector<std::string> old_files;
|
||||
std::string new_path;
|
||||
for (size_t i = 0; i < security_dirs.size(); ++i) {
|
||||
old_files.push_back(security_dirs[i]);
|
||||
new_path = base_path + security_dirs[i];
|
||||
EXPECT_CALL(file, IsRegularFile(StrEq(new_path))).WillOnce(Return(false));
|
||||
EXPECT_CALL(file, Exists(StrEq(new_path)))
|
||||
.WillOnce(Return(false))
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, CreateDirectory(StrEq(new_path))).WillOnce(Return(true));
|
||||
}
|
||||
|
||||
std::string old_path =
|
||||
base_path + DeviceFiles::GetCertificateFileName(EMPTY_ORIGIN);
|
||||
old_files.push_back(DeviceFiles::GetCertificateFileName(EMPTY_ORIGIN));
|
||||
EXPECT_CALL(file, IsRegularFile(StrEq(old_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, Remove(StrEq(old_path))).WillOnce(Return(true));
|
||||
for (size_t i = 0; i < security_dirs.size(); ++i) {
|
||||
new_path = base_path + security_dirs[i] +
|
||||
DeviceFiles::GetCertificateFileName(EMPTY_ORIGIN);
|
||||
EXPECT_CALL(file, Copy(StrEq(old_path), StrEq(new_path)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < kNumberOfLicenses; ++j) {
|
||||
std::string file_name = license_test_data[j].key_set_id +
|
||||
DeviceFiles::GetLicenseFileNameExtension();
|
||||
old_path = base_path + file_name;
|
||||
old_files.push_back(file_name);
|
||||
EXPECT_CALL(file, IsRegularFile(StrEq(old_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, Remove(StrEq(old_path))).WillOnce(Return(true));
|
||||
for (size_t i = 0; i < security_dirs.size(); ++i) {
|
||||
new_path = base_path + security_dirs[i] + file_name;
|
||||
EXPECT_CALL(file, Copy(StrEq(old_path), StrEq(new_path)))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_CALL(file, List(StrEq(base_path), NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(old_files), Return(true)));
|
||||
|
||||
std::string data = a2bs_hex(kTestCertificateFileData);
|
||||
|
||||
new_path =
|
||||
device_base_path_ + DeviceFiles::GetCertificateFileName(EMPTY_ORIGIN);
|
||||
EXPECT_CALL(file, Exists(StrEq(new_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, FileSize(_)).WillOnce(Return(data.size()));
|
||||
EXPECT_CALL(file, Open(_, _)).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(data.size())))
|
||||
.WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()),
|
||||
Return(data.size())));
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
Properties::Init();
|
||||
std::string certificate, wrapped_private_key;
|
||||
ASSERT_TRUE(device_files.RetrieveCertificate(EMPTY_ORIGIN, &certificate,
|
||||
&wrapped_private_key));
|
||||
}
|
||||
|
||||
TEST_F(DeviceFilesTest, UpdateLicenseState) {
|
||||
MockFile file;
|
||||
MockFileSystem file_system;
|
||||
std::string license_path = device_base_path_ +
|
||||
license_update_test_data[0].key_set_id +
|
||||
DeviceFiles::GetLicenseFileNameExtension();
|
||||
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system, Open(StrEq(license_path), IsCreateFileFlagSet()))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
EXPECT_CALL(file, Open(StrEq(license_path),
|
||||
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(Return(&file));
|
||||
EXPECT_CALL(file, Write(IsStrEq(license_update_test_data[0].file_data),
|
||||
Eq(license_update_test_data[0].file_data.size())))
|
||||
.WillOnce(ReturnArg<1>());
|
||||
@@ -2041,9 +1901,8 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) {
|
||||
EXPECT_CALL(file, Close()).Times(2);
|
||||
EXPECT_CALL(file, Read(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
EXPECT_TRUE(device_files.StoreLicense(
|
||||
license_update_test_data[0].key_set_id,
|
||||
license_update_test_data[0].license_state,
|
||||
@@ -2072,32 +1931,33 @@ TEST_F(DeviceFilesTest, UpdateLicenseState) {
|
||||
}
|
||||
|
||||
TEST_F(DeviceFilesTest, DeleteLicense) {
|
||||
MockFile file;
|
||||
MockFileSystem file_system;
|
||||
std::string license_path = device_base_path_ +
|
||||
license_test_data[0].key_set_id +
|
||||
DeviceFiles::GetLicenseFileNameExtension();
|
||||
|
||||
size_t size = license_test_data[0].file_data.size();
|
||||
|
||||
EXPECT_CALL(file, Exists(StrEq(license_path)))
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system, Exists(StrEq(license_path)))
|
||||
.Times(2)
|
||||
.WillOnce(Return(true))
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(file, FileSize(StrEq(license_path))).WillOnce(Return(size));
|
||||
EXPECT_CALL(file, Open(StrEq(license_path), IsBinaryFileFlagSet()))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(license_path)))
|
||||
.WillOnce(Return(size));
|
||||
EXPECT_CALL(file_system, Open(StrEq(license_path), _))
|
||||
.WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(size)))
|
||||
.WillOnce(
|
||||
DoAll(SetArrayArgument<0>(license_test_data[0].file_data.begin(),
|
||||
license_test_data[0].file_data.end()),
|
||||
Return(size)));
|
||||
EXPECT_CALL(file, Remove(StrEq(license_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, Remove(StrEq(license_path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
DeviceFiles::LicenseState license_state;
|
||||
CdmInitData pssh_data;
|
||||
CdmKeyMessage key_request;
|
||||
@@ -2135,17 +1995,11 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
|
||||
|
||||
TEST_F(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem) {
|
||||
// Validate that ReserveLicenseIds does not touch the file system.
|
||||
MockFile file;
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))).Times(0);
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
EXPECT_CALL(file, Open(_, _)).Times(0);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
EXPECT_CALL(file, Close()).Times(0);
|
||||
EXPECT_CALL(file, Read(_, _)).Times(0);
|
||||
MockFileSystem file_system;
|
||||
EXPECT_CALL(file_system, Open(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
for (size_t i = 0; i < kNumberOfLicenses; i++) {
|
||||
EXPECT_TRUE(device_files.ReserveLicenseId(license_test_data[i].key_set_id));
|
||||
// Validate that the license IDs are actually reserved.
|
||||
@@ -2156,6 +2010,7 @@ TEST_F(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem) {
|
||||
}
|
||||
|
||||
TEST_P(DeviceFilesUsageInfoTest, Read) {
|
||||
MockFileSystem file_system;
|
||||
MockFile file;
|
||||
std::string app_id; // TODO(fredgc): add tests with multiple app_ids.
|
||||
std::string path =
|
||||
@@ -2167,28 +2022,24 @@ TEST_P(DeviceFilesUsageInfoTest, Read) {
|
||||
data = kUsageInfoTestData[index].file_data;
|
||||
}
|
||||
if (index >= 0) {
|
||||
EXPECT_CALL(file, Exists(StrEq(path))).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, FileSize(StrEq(path)))
|
||||
EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(path)))
|
||||
.WillRepeatedly(Return(data.size()));
|
||||
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(data.size())))
|
||||
.WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()),
|
||||
Return(data.size())));
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
} else {
|
||||
EXPECT_CALL(file, Exists(StrEq(path)))
|
||||
.WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(file, FileSize(_)).Times(0);
|
||||
EXPECT_CALL(file, Open(_, _)).Times(0);
|
||||
EXPECT_CALL(file, Close()).Times(0);
|
||||
EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(false));
|
||||
EXPECT_CALL(file_system, FileSize(_)).Times(0);
|
||||
EXPECT_CALL(file_system, Open(_, _)).Times(0);
|
||||
}
|
||||
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info;
|
||||
ASSERT_TRUE(device_files.RetrieveUsageInfo(app_id, &license_info));
|
||||
@@ -2212,7 +2063,7 @@ TEST_P(DeviceFilesUsageInfoTest, Read) {
|
||||
}
|
||||
|
||||
TEST_P(DeviceFilesUsageInfoTest, Store) {
|
||||
MockFile file;
|
||||
MockFileSystem file_system;
|
||||
std::string app_id; // TODO(fredgc): multiple app ids.
|
||||
std::string pst(GenerateRandomData(kProviderSessionTokenLen));
|
||||
std::string license_request(GenerateRandomData(kLicenseRequestLen));
|
||||
@@ -2226,24 +2077,24 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
|
||||
if (index >= 0) {
|
||||
data = kUsageInfoTestData[index].file_data;
|
||||
}
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
|
||||
EXPECT_CALL(file, Exists(StrEq(path))).WillRepeatedly(Return(index >= 0));
|
||||
MockFile file;
|
||||
EXPECT_CALL(file_system, Exists(StrEq(path)))
|
||||
.WillRepeatedly(Return(index >= 0));
|
||||
if (index >= 0) {
|
||||
EXPECT_CALL(file, FileSize(StrEq(path))).WillOnce(Return(data.size()));
|
||||
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(path)))
|
||||
.WillOnce(Return(data.size()));
|
||||
EXPECT_CALL(file_system, Open(StrEq(path), _))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(Return(&file));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(data.size())))
|
||||
.WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()),
|
||||
Return(data.size())));
|
||||
EXPECT_CALL(file, Close()).Times(2);
|
||||
} else {
|
||||
EXPECT_CALL(file, FileSize(_)).Times(0);
|
||||
EXPECT_CALL(file, Open(_, _)).Times(1).WillOnce(Return(true));
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file_system, FileSize(_)).Times(0);
|
||||
EXPECT_CALL(file_system, Open(_, _)).Times(1).WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Close());
|
||||
}
|
||||
|
||||
EXPECT_CALL(file,
|
||||
@@ -2253,9 +2104,8 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
|
||||
key_set_id.size())))
|
||||
.WillOnce(ReturnArg<1>());
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
ASSERT_TRUE(
|
||||
device_files.StoreUsageInfo(pst, license_request, license, app_id,
|
||||
@@ -2263,6 +2113,7 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
|
||||
}
|
||||
|
||||
TEST_P(DeviceFilesUsageInfoTest, Delete) {
|
||||
MockFileSystem file_system;
|
||||
MockFile file;
|
||||
std::string app_id; // TODO(fredgc): expand tests.
|
||||
std::string path =
|
||||
@@ -2282,24 +2133,19 @@ TEST_P(DeviceFilesUsageInfoTest, Delete) {
|
||||
}
|
||||
}
|
||||
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
EXPECT_CALL(file_system, Exists(StrEq(path))).WillOnce(Return(index >= 0));
|
||||
|
||||
EXPECT_CALL(file, Exists(StrEq(path))).WillOnce(Return(index >= 0));
|
||||
|
||||
EXPECT_CALL(file, FileSize(StrEq(path))).WillOnce(Return(data.size()));
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(path))).WillOnce(Return(data.size()));
|
||||
if (index >= 1) {
|
||||
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
|
||||
EXPECT_CALL(file_system, Open(StrEq(path), _))
|
||||
.Times(2)
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(Return(&file));
|
||||
EXPECT_CALL(file, Write(Contains(prev_pst, prev_license, prev_data.size()),
|
||||
Gt(prev_pst.size() + prev_license.size())))
|
||||
.WillOnce(ReturnArg<1>());
|
||||
EXPECT_CALL(file, Close()).Times(2);
|
||||
} else {
|
||||
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
}
|
||||
@@ -2307,9 +2153,8 @@ TEST_P(DeviceFilesUsageInfoTest, Delete) {
|
||||
.WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()),
|
||||
Return(data.size())));
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
if (index >= 1) {
|
||||
ASSERT_TRUE(device_files.DeleteUsageInfo(app_id, pst));
|
||||
@@ -2319,36 +2164,33 @@ TEST_P(DeviceFilesUsageInfoTest, Delete) {
|
||||
}
|
||||
|
||||
TEST_P(DeviceFilesUsageInfoTest, DeleteAll) {
|
||||
MockFileSystem file_system;
|
||||
MockFile file;
|
||||
std::string app_id; // TODO(fredgc): expand tests.
|
||||
std::string path =
|
||||
device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id);
|
||||
|
||||
int index = GetParam();
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
|
||||
std::string data;
|
||||
if (index < 0) {
|
||||
EXPECT_CALL(file, Exists(StrEq(path))).WillOnce(Return(false));
|
||||
EXPECT_CALL(file_system, Exists(StrEq(path))).WillOnce(Return(false));
|
||||
} else {
|
||||
data = kUsageInfoTestData[index].file_data;
|
||||
EXPECT_CALL(file, Exists(StrEq(path))).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, FileSize(StrEq(path))).WillOnce(Return(data.size()));
|
||||
EXPECT_CALL(file, Open(StrEq(path), IsBinaryFileFlagSet()))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, Exists(StrEq(path))).WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file_system, FileSize(StrEq(path)))
|
||||
.WillOnce(Return(data.size()));
|
||||
EXPECT_CALL(file_system, Open(StrEq(path), _)).WillOnce(Return(&file));
|
||||
EXPECT_CALL(file, Read(NotNull(), Eq(data.size())))
|
||||
.WillOnce(DoAll(SetArrayArgument<0>(data.begin(), data.end()),
|
||||
Return(data.size())));
|
||||
EXPECT_CALL(file, Close()).Times(1);
|
||||
EXPECT_CALL(file, Remove(StrEq(path))).WillOnce(Return(true));
|
||||
EXPECT_CALL(file_system, Remove(StrEq(path))).WillOnce(Return(true));
|
||||
}
|
||||
|
||||
DeviceFiles device_files;
|
||||
DeviceFiles device_files(&file_system);
|
||||
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
|
||||
device_files.SetTestFile(&file);
|
||||
|
||||
std::vector<std::string> psts;
|
||||
ASSERT_TRUE(device_files.DeleteAllUsageInfoForApp(app_id, &psts));
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "device_files.h"
|
||||
|
||||
#include "file_store.h"
|
||||
#include "properties.h"
|
||||
#include "test_vectors.h"
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -18,20 +17,12 @@ const std::string kWildcard = "*";
|
||||
|
||||
class FileTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() { CreateTestDir(); }
|
||||
FileTest() {}
|
||||
|
||||
virtual void TearDown() { RemoveTestDir(); }
|
||||
|
||||
void CreateTestDir() {
|
||||
File file;
|
||||
if (!file.Exists(test_vectors::kTestDir)) {
|
||||
EXPECT_TRUE(file.CreateDirectory(test_vectors::kTestDir));
|
||||
}
|
||||
EXPECT_TRUE(file.Exists(test_vectors::kTestDir));
|
||||
}
|
||||
|
||||
void RemoveTestDir() {
|
||||
File file;
|
||||
EXPECT_TRUE(file.Remove(test_vectors::kTestDir));
|
||||
EXPECT_TRUE(file_system.Remove(test_vectors::kTestDir));
|
||||
}
|
||||
|
||||
std::string GenerateRandomData(uint32_t len) {
|
||||
@@ -41,64 +32,52 @@ class FileTest : public testing::Test {
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
FileSystem file_system;
|
||||
};
|
||||
|
||||
TEST_F(FileTest, FileExists) {
|
||||
File file;
|
||||
EXPECT_TRUE(file.Exists(test_vectors::kExistentFile));
|
||||
EXPECT_TRUE(file.Exists(test_vectors::kExistentDir));
|
||||
EXPECT_FALSE(file.Exists(test_vectors::kNonExistentFile));
|
||||
EXPECT_FALSE(file.Exists(test_vectors::kNonExistentDir));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, CreateDirectory) {
|
||||
File file;
|
||||
std::string dir_wo_delimiter =
|
||||
test_vectors::kTestDir.substr(0, test_vectors::kTestDir.size() - 1);
|
||||
if (file.Exists(dir_wo_delimiter)) EXPECT_TRUE(file.Remove(dir_wo_delimiter));
|
||||
EXPECT_FALSE(file.Exists(dir_wo_delimiter));
|
||||
EXPECT_TRUE(file.CreateDirectory(dir_wo_delimiter));
|
||||
EXPECT_TRUE(file.Exists(dir_wo_delimiter));
|
||||
EXPECT_TRUE(file.Remove(dir_wo_delimiter));
|
||||
EXPECT_TRUE(file.CreateDirectory(test_vectors::kTestDir));
|
||||
EXPECT_TRUE(file.Exists(test_vectors::kTestDir));
|
||||
EXPECT_TRUE(file.Remove(test_vectors::kTestDir));
|
||||
EXPECT_TRUE(file_system.Exists(test_vectors::kExistentFile));
|
||||
EXPECT_TRUE(file_system.Exists(test_vectors::kExistentDir));
|
||||
EXPECT_FALSE(file_system.Exists(test_vectors::kNonExistentFile));
|
||||
EXPECT_FALSE(file_system.Exists(test_vectors::kNonExistentDir));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, RemoveDir) {
|
||||
File file;
|
||||
EXPECT_TRUE(file.Remove(test_vectors::kTestDir));
|
||||
EXPECT_FALSE(file.Exists(test_vectors::kTestDir));
|
||||
EXPECT_TRUE(file_system.Remove(test_vectors::kTestDir));
|
||||
EXPECT_FALSE(file_system.Exists(test_vectors::kTestDir));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, OpenFile) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
File handle;
|
||||
EXPECT_TRUE(handle.Remove(path));
|
||||
EXPECT_TRUE(file_system.Remove(path));
|
||||
|
||||
File file;
|
||||
EXPECT_TRUE(file.Open(path, File::kCreate));
|
||||
file.Close();
|
||||
File* file = file_system.Open(path, FileSystem::kCreate);
|
||||
ASSERT_TRUE(file);
|
||||
file->Close();
|
||||
|
||||
EXPECT_TRUE(handle.Exists(path));
|
||||
EXPECT_TRUE(file_system.Exists(path));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, RemoveDirAndFile) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
|
||||
File file;
|
||||
EXPECT_TRUE(file.Open(path, File::kCreate));
|
||||
file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
EXPECT_TRUE(file.Remove(path));
|
||||
EXPECT_FALSE(file.Exists(path));
|
||||
File* file = file_system.Open(path, FileSystem::kCreate);
|
||||
ASSERT_TRUE(file);
|
||||
file->Close();
|
||||
|
||||
EXPECT_TRUE(file.Open(path, File::kCreate));
|
||||
file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
EXPECT_TRUE(file_system.Exists(path));
|
||||
EXPECT_TRUE(file_system.Remove(path));
|
||||
EXPECT_FALSE(file_system.Exists(path));
|
||||
|
||||
file = file_system.Open(path, FileSystem::kCreate);
|
||||
ASSERT_TRUE(file);
|
||||
file->Close();
|
||||
|
||||
EXPECT_TRUE(file_system.Exists(path));
|
||||
RemoveTestDir();
|
||||
EXPECT_FALSE(file.Exists(test_vectors::kTestDir));
|
||||
EXPECT_FALSE(file.Exists(path));
|
||||
EXPECT_FALSE(file_system.Exists(test_vectors::kTestDir));
|
||||
EXPECT_FALSE(file_system.Exists(path));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, RemoveWildcardFiles) {
|
||||
@@ -107,159 +86,53 @@ TEST_F(FileTest, RemoveWildcardFiles) {
|
||||
std::string wildcard_path =
|
||||
test_vectors::kTestDir + kWildcard + kTestFileNameExt;
|
||||
|
||||
File file;
|
||||
EXPECT_TRUE(file.Open(path1, File::kCreate));
|
||||
file.Close();
|
||||
EXPECT_TRUE(file.Open(path2, File::kCreate));
|
||||
file.Close();
|
||||
EXPECT_TRUE(file.Exists(path1));
|
||||
EXPECT_TRUE(file.Exists(path2));
|
||||
EXPECT_TRUE(file.Remove(wildcard_path));
|
||||
EXPECT_FALSE(file.Exists(path1));
|
||||
EXPECT_FALSE(file.Exists(path2));
|
||||
}
|
||||
File* file = file_system.Open(path1, FileSystem::kCreate);
|
||||
ASSERT_TRUE(file);
|
||||
file->Close();
|
||||
file = file_system.Open(path2, FileSystem::kCreate);
|
||||
ASSERT_TRUE(file);
|
||||
file->Close();
|
||||
|
||||
TEST_F(FileTest, IsDir) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
File file;
|
||||
EXPECT_TRUE(file.Open(path, File::kCreate));
|
||||
file.Close();
|
||||
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
EXPECT_TRUE(file.Exists(test_vectors::kTestDir));
|
||||
EXPECT_FALSE(file.IsDirectory(path));
|
||||
EXPECT_TRUE(file.IsDirectory(test_vectors::kTestDir));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, IsRegularFile) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
File file;
|
||||
EXPECT_TRUE(file.Open(path, File::kCreate));
|
||||
file.Close();
|
||||
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
EXPECT_TRUE(file.Exists(test_vectors::kTestDir));
|
||||
EXPECT_TRUE(file.IsRegularFile(path));
|
||||
EXPECT_FALSE(file.IsRegularFile(test_vectors::kTestDir));
|
||||
EXPECT_TRUE(file_system.Exists(path1));
|
||||
EXPECT_TRUE(file_system.Exists(path2));
|
||||
EXPECT_TRUE(file_system.Remove(wildcard_path));
|
||||
EXPECT_FALSE(file_system.Exists(path1));
|
||||
EXPECT_FALSE(file_system.Exists(path2));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, FileSize) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
File file;
|
||||
file.Remove(path);
|
||||
file_system.Remove(path);
|
||||
|
||||
std::string write_data = GenerateRandomData(600);
|
||||
File wr_file;
|
||||
EXPECT_TRUE(wr_file.Open(path, File::kCreate | File::kBinary));
|
||||
EXPECT_TRUE(wr_file.Write(write_data.data(), write_data.size()));
|
||||
wr_file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
File* file = file_system.Open(path, FileSystem::kCreate);
|
||||
ASSERT_TRUE(file);
|
||||
EXPECT_TRUE(file->Write(write_data.data(), write_data.size()));
|
||||
file->Close();
|
||||
EXPECT_TRUE(file_system.Exists(path));
|
||||
|
||||
EXPECT_EQ(static_cast<ssize_t>(write_data.size()), file.FileSize(path));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, WriteReadTextFile) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
File file;
|
||||
file.Remove(path);
|
||||
|
||||
std::string write_data = "This is a test";
|
||||
File wr_file;
|
||||
EXPECT_TRUE(wr_file.Open(path, File::kCreate));
|
||||
EXPECT_TRUE(wr_file.Write(write_data.data(), write_data.size()));
|
||||
wr_file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
|
||||
std::string read_data;
|
||||
read_data.resize(file.FileSize(path));
|
||||
File rd_file;
|
||||
EXPECT_TRUE(rd_file.Open(path, File::kReadOnly));
|
||||
EXPECT_TRUE(rd_file.Read(&read_data[0], read_data.size()));
|
||||
rd_file.Close();
|
||||
EXPECT_EQ(write_data, read_data);
|
||||
EXPECT_EQ(static_cast<ssize_t>(write_data.size()),
|
||||
file_system.FileSize(path));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, WriteReadBinaryFile) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
File file;
|
||||
file.Remove(path);
|
||||
file_system.Remove(path);
|
||||
|
||||
std::string write_data = GenerateRandomData(600);
|
||||
File wr_file;
|
||||
EXPECT_TRUE(wr_file.Open(path, File::kCreate | File::kBinary));
|
||||
EXPECT_TRUE(wr_file.Write(write_data.data(), write_data.size()));
|
||||
wr_file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
File* file = file_system.Open(path, FileSystem::kCreate);
|
||||
ASSERT_TRUE(file);
|
||||
EXPECT_TRUE(file->Write(write_data.data(), write_data.size()));
|
||||
file->Close();
|
||||
EXPECT_TRUE(file_system.Exists(path));
|
||||
|
||||
std::string read_data;
|
||||
read_data.resize(file.FileSize(path));
|
||||
File rd_file;
|
||||
EXPECT_TRUE(rd_file.Open(path, File::kReadOnly));
|
||||
EXPECT_TRUE(rd_file.Read(&read_data[0], read_data.size()));
|
||||
rd_file.Close();
|
||||
read_data.resize(file_system.FileSize(path));
|
||||
file = file_system.Open(path, FileSystem::kReadOnly);
|
||||
ASSERT_TRUE(file);
|
||||
EXPECT_TRUE(file->Read(&read_data[0], read_data.size()));
|
||||
file->Close();
|
||||
EXPECT_EQ(write_data, read_data);
|
||||
}
|
||||
|
||||
TEST_F(FileTest, CopyFile) {
|
||||
std::string path = test_vectors::kTestDir + kTestFileName;
|
||||
File file;
|
||||
file.Remove(path);
|
||||
|
||||
std::string write_data = GenerateRandomData(600);
|
||||
File wr_file;
|
||||
EXPECT_TRUE(wr_file.Open(path, File::kCreate | File::kBinary));
|
||||
EXPECT_TRUE(wr_file.Write(write_data.data(), write_data.size()));
|
||||
wr_file.Close();
|
||||
ASSERT_TRUE(file.Exists(path));
|
||||
|
||||
std::string path_copy = test_vectors::kTestDir + kTestFileName2;
|
||||
EXPECT_FALSE(file.Exists(path_copy));
|
||||
EXPECT_TRUE(file.Copy(path, path_copy));
|
||||
|
||||
std::string read_data;
|
||||
read_data.resize(file.FileSize(path_copy));
|
||||
File rd_file;
|
||||
EXPECT_TRUE(rd_file.Open(path_copy, File::kReadOnly));
|
||||
EXPECT_TRUE(rd_file.Read(&read_data[0], read_data.size()));
|
||||
rd_file.Close();
|
||||
EXPECT_EQ(write_data, read_data);
|
||||
EXPECT_EQ(file.FileSize(path), file.FileSize(path_copy));
|
||||
}
|
||||
|
||||
TEST_F(FileTest, ListEmptyDirectory) {
|
||||
std::vector<std::string> files;
|
||||
File file;
|
||||
EXPECT_TRUE(file.List(test_vectors::kTestDir, &files));
|
||||
EXPECT_EQ(0u, files.size());
|
||||
}
|
||||
|
||||
TEST_F(FileTest, ListFiles) {
|
||||
File file;
|
||||
std::string path = test_vectors::kTestDir + kTestDirName;
|
||||
EXPECT_TRUE(file.CreateDirectory(path));
|
||||
|
||||
path = test_vectors::kTestDir + kTestFileName;
|
||||
std::string write_data = GenerateRandomData(600);
|
||||
EXPECT_TRUE(file.Open(path, File::kCreate | File::kBinary));
|
||||
EXPECT_TRUE(file.Write(write_data.data(), write_data.size()));
|
||||
file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
|
||||
path = test_vectors::kTestDir + kTestFileName2;
|
||||
write_data = GenerateRandomData(600);
|
||||
EXPECT_TRUE(file.Open(path, File::kCreate | File::kBinary));
|
||||
EXPECT_TRUE(file.Write(write_data.data(), write_data.size()));
|
||||
file.Close();
|
||||
EXPECT_TRUE(file.Exists(path));
|
||||
|
||||
std::vector<std::string> files;
|
||||
EXPECT_TRUE(file.List(test_vectors::kTestDir, &files));
|
||||
EXPECT_EQ(3u, files.size());
|
||||
|
||||
for (size_t i = 0; i < files.size(); ++i) {
|
||||
EXPECT_TRUE(files[i] == kTestDirName || files[i] == kTestFileName ||
|
||||
files[i] == kTestFileName2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
416
libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp
Normal file
416
libwvdrmengine/cdm/core/test/generic_crypto_unittest.cpp
Normal file
@@ -0,0 +1,416 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
// These tests are for the generic crypto operations. They call on the
|
||||
// CdmEngine class and exercise the classes below it as well. In
|
||||
// particular, we assume that the OEMCrypo layer works, and has a valid keybox.
|
||||
// This is because we need a valid RSA certificate, and will attempt to connect
|
||||
// to the provisioning server to request one if we don't.
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
|
||||
#include "cdm_engine.h"
|
||||
|
||||
#include "license_request.h"
|
||||
#include "log.h"
|
||||
#include "oec_session_util.h"
|
||||
#include "../../oemcrypto/mock/src/oemcrypto_key_mock.h"
|
||||
#include "string_conversions.h"
|
||||
#include "url_request.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace {
|
||||
|
||||
const std::string kKeySystem = "com.widevine.alpha";
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class WvGenericOperationsTest : public testing::Test {
|
||||
public:
|
||||
virtual void SetUp() {
|
||||
::testing::Test::SetUp();
|
||||
|
||||
// Load test keybox. This keybox will be used by any CryptoSession
|
||||
// created by the CDM under test.
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadTestKeybox());
|
||||
|
||||
// Perform CdmEngine setup
|
||||
cdm_engine_ = new CdmEngine(&file_system_);
|
||||
|
||||
CdmResponseType status =
|
||||
cdm_engine_->OpenSession(kKeySystem, NULL, NULL, &session_id_);
|
||||
if (status == NEED_PROVISIONING) {
|
||||
Provision();
|
||||
status = cdm_engine_->OpenSession(kKeySystem, NULL, NULL, &session_id_);
|
||||
}
|
||||
ASSERT_EQ(NO_ERROR, status);
|
||||
ASSERT_NE("", session_id_) << "Could not open CDM session.";
|
||||
ASSERT_TRUE(cdm_engine_->IsOpenSession(session_id_));
|
||||
|
||||
// Get OEMCrypto session ID from the CDM
|
||||
CdmQueryMap query;
|
||||
cdm_engine_->QueryOemCryptoSessionId(session_id_, &query);
|
||||
std::istringstream parse_int;
|
||||
parse_int.str(query[QUERY_KEY_OEMCRYPTO_SESSION_ID]);
|
||||
parse_int >> oec_session_id_;
|
||||
|
||||
// Construct and install keys into the CDM's OEMCrypto session.
|
||||
OecSessionSetup(oec_session_id_);
|
||||
EncryptAndLoadKeys();
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
oec_util_session_.close();
|
||||
cdm_engine_->CloseSession(session_id_);
|
||||
// OEMCrypto_Terminate() will be performed during the test class's
|
||||
// destruction (specifically by the CryptoSession destructor)
|
||||
}
|
||||
|
||||
void OecSessionSetup(uint32_t oec_session_id) {
|
||||
buffer_size_ = 160;
|
||||
oec_util_session_.SetSessionId(oec_session_id);
|
||||
oec_util_session_.GenerateTestSessionKeys();
|
||||
MakeFourKeys();
|
||||
}
|
||||
|
||||
enum GenericKeyType {
|
||||
kGenericEncrypt = 0,
|
||||
kGenericDecrypt = 1,
|
||||
kGenericSign = 2,
|
||||
kGenericVerify = 3
|
||||
};
|
||||
|
||||
virtual void MakeFourKeys(
|
||||
uint32_t duration = wvoec::kDuration, uint32_t control = 0,
|
||||
uint32_t nonce = 0, const std::string& pst = "") {
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
oec_util_session_.FillSimpleMessage(duration, control, nonce, pst));
|
||||
oec_util_session_.license().keys[kGenericEncrypt].control.control_bits |=
|
||||
htonl(wvoec_mock::kControlAllowEncrypt);
|
||||
oec_util_session_.license().keys[kGenericDecrypt].control.control_bits |=
|
||||
htonl(wvoec_mock::kControlAllowDecrypt);
|
||||
oec_util_session_.license().keys[kGenericSign].control.control_bits |=
|
||||
htonl(wvoec_mock::kControlAllowSign);
|
||||
oec_util_session_.license().keys[kGenericVerify].control.control_bits |=
|
||||
htonl(wvoec_mock::kControlAllowVerify);
|
||||
|
||||
oec_util_session_.license().keys[kGenericSign].key_data_length =
|
||||
wvcdm::MAC_KEY_SIZE;
|
||||
oec_util_session_.license().keys[kGenericVerify].key_data_length =
|
||||
wvcdm::MAC_KEY_SIZE;
|
||||
|
||||
clear_buffer_.assign(buffer_size_, 0);
|
||||
for (size_t i = 0; i < clear_buffer_.size(); i++) {
|
||||
clear_buffer_[i] = 1 + i % 250;
|
||||
}
|
||||
for (size_t i = 0; i < wvcdm::KEY_IV_SIZE; i++) {
|
||||
iv_[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GetKeyId(GenericKeyType type) {
|
||||
std::string key_id;
|
||||
size_t key_id_length = oec_util_session_.license().keys[0].key_id_length;
|
||||
key_id.assign(
|
||||
&(oec_util_session_.license().keys[type].key_id[0]),
|
||||
&(oec_util_session_.license().keys[type].key_id[key_id_length]));
|
||||
return key_id;
|
||||
}
|
||||
|
||||
std::string GetClearBuffer() {
|
||||
std::string buffer;
|
||||
size_t buffer_length = clear_buffer_.size();
|
||||
buffer.assign(&clear_buffer_[0], &clear_buffer_[buffer_length]);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string GetEncryptedBuffer() {
|
||||
std::string buffer;
|
||||
size_t buffer_length = encrypted_buffer_.size();
|
||||
buffer.assign(&encrypted_buffer_[0], &encrypted_buffer_[buffer_length]);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string GetIvBlock() {
|
||||
std::string buffer;
|
||||
size_t buffer_length = wvcdm::KEY_IV_SIZE;
|
||||
buffer.assign(&iv_[0], &iv_[buffer_length]);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string GetSignatureBuffer() {
|
||||
std::string buffer;
|
||||
buffer.resize(SHA256_DIGEST_LENGTH);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void EncryptAndLoadKeys() {
|
||||
ASSERT_NO_FATAL_FAILURE(oec_util_session_.EncryptAndSign());
|
||||
oec_util_session_.LoadTestKeys();
|
||||
}
|
||||
|
||||
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_->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));
|
||||
}
|
||||
|
||||
// This CryptoSession object handles Initialization and Termination
|
||||
// calls on OEMCrypto for the duration of the test. CryptoSessions
|
||||
// created by the CDM will share the OEMCrypto state of this CryptoSession,
|
||||
// including, for example, a test keybox.
|
||||
CryptoSession crypto_session_;
|
||||
|
||||
FileSystem file_system_;
|
||||
CdmEngine* cdm_engine_;
|
||||
std::string key_msg_;
|
||||
std::string session_id_;
|
||||
std::string server_url_;
|
||||
uint32_t oec_session_id_;
|
||||
wvoec::Session oec_util_session_;
|
||||
size_t buffer_size_;
|
||||
vector<uint8_t> clear_buffer_;
|
||||
vector<uint8_t> encrypted_buffer_;
|
||||
uint8_t iv_[wvcdm::KEY_IV_SIZE];
|
||||
};
|
||||
|
||||
TEST_F(WvGenericOperationsTest, NormalSessionOpenClose) {
|
||||
wvoec::Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenerateSessionKeys) {
|
||||
wvoec::Session s;
|
||||
ASSERT_NO_FATAL_FAILURE(s.open());
|
||||
ASSERT_NO_FATAL_FAILURE(s.GenerateTestSessionKeys());
|
||||
ASSERT_NO_FATAL_FAILURE(s.close());
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericEncryptNoKey) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string out_buffer = GetEncryptedBuffer();
|
||||
std::string iv = GetIvBlock();
|
||||
|
||||
// No key
|
||||
KeyId key_id("xyz");
|
||||
cdm_sts = cdm_engine_->GenericEncrypt(session_id_, in_buffer, key_id, iv,
|
||||
wvcdm::kEncryptionAlgorithmAesCbc128,
|
||||
&out_buffer);
|
||||
EXPECT_EQ(KEY_ERROR_1, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericEncryptKeyNotAllowed) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string out_buffer = GetEncryptedBuffer();
|
||||
std::string iv = GetIvBlock();
|
||||
|
||||
// Wrong key
|
||||
std::string key_id = GetKeyId(kGenericDecrypt);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericEncrypt(session_id_, in_buffer, key_id, iv,
|
||||
wvcdm::kEncryptionAlgorithmAesCbc128,
|
||||
&out_buffer);
|
||||
EXPECT_EQ(UNKNOWN_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericEncryptGood) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string out_buffer = GetEncryptedBuffer();
|
||||
std::string iv = GetIvBlock();
|
||||
|
||||
// Good key
|
||||
std::string key_id = GetKeyId(kGenericEncrypt);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericEncrypt(session_id_, in_buffer, key_id, iv,
|
||||
wvcdm::kEncryptionAlgorithmAesCbc128,
|
||||
&out_buffer);
|
||||
EXPECT_EQ(NO_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericDecryptKeyNotAllowed) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string out_buffer = GetEncryptedBuffer();
|
||||
std::string iv = GetIvBlock();
|
||||
|
||||
// Wrong key
|
||||
std::string key_id = GetKeyId(kGenericEncrypt);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericDecrypt(session_id_, in_buffer, key_id, iv,
|
||||
wvcdm::kEncryptionAlgorithmAesCbc128,
|
||||
&out_buffer);
|
||||
EXPECT_EQ(UNKNOWN_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericDecryptGood) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string out_buffer = GetEncryptedBuffer();
|
||||
std::string iv = GetIvBlock();
|
||||
|
||||
// Good key
|
||||
std::string key_id = GetKeyId(kGenericDecrypt);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericDecrypt(session_id_, in_buffer, key_id, iv,
|
||||
wvcdm::kEncryptionAlgorithmAesCbc128,
|
||||
&out_buffer);
|
||||
EXPECT_EQ(NO_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericSignKeyNotAllowed) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string signature_buffer;
|
||||
|
||||
// Wrong key
|
||||
std::string key_id = GetKeyId(kGenericVerify);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericSign(session_id_, in_buffer, key_id,
|
||||
wvcdm::kSigningAlgorithmHmacSha256,
|
||||
&signature_buffer);
|
||||
EXPECT_EQ(UNKNOWN_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericSignGood) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string signature_buffer;
|
||||
|
||||
// Good key
|
||||
std::string key_id = GetKeyId(kGenericSign);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericSign(session_id_, in_buffer, key_id,
|
||||
wvcdm::kSigningAlgorithmHmacSha256,
|
||||
&signature_buffer);
|
||||
EXPECT_EQ(NO_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericVerifyKeyNotAllowed) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string signature_buffer = GetSignatureBuffer();
|
||||
|
||||
// Wrong key
|
||||
std::string key_id = GetKeyId(kGenericSign);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericVerify(session_id_, in_buffer, key_id,
|
||||
wvcdm::kSigningAlgorithmHmacSha256,
|
||||
signature_buffer);
|
||||
EXPECT_EQ(UNKNOWN_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsTest, GenericVerifyGood) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string signature_buffer = GetSignatureBuffer();
|
||||
|
||||
// Good key - signature not set.
|
||||
std::string key_id = GetKeyId(kGenericVerify);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericVerify(session_id_, in_buffer, key_id,
|
||||
wvcdm::kSigningAlgorithmHmacSha256,
|
||||
signature_buffer);
|
||||
// OEMCrypto error is OEMCrypto_ERROR_SIGNATURE_FAILURE
|
||||
EXPECT_EQ(UNKNOWN_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
class WvGenericOperationsDataTest : public WvGenericOperationsTest {
|
||||
public:
|
||||
// Construct keys for encrypt/decrypt and for sign/verify
|
||||
virtual void MakeFourKeys(
|
||||
uint32_t duration = wvoec::kDuration, uint32_t control = 0,
|
||||
uint32_t nonce = 0, const std::string& pst = "") {
|
||||
ASSERT_NO_FATAL_FAILURE(
|
||||
oec_util_session_.FillSimpleMessage(duration, control, nonce, pst));
|
||||
oec_util_session_.license().keys[kGenericEncrypt].control.control_bits |=
|
||||
htonl(wvoec_mock::kControlAllowEncrypt |
|
||||
wvoec_mock::kControlAllowDecrypt);
|
||||
oec_util_session_.license().keys[kGenericSign].control.control_bits |=
|
||||
htonl(wvoec_mock::kControlAllowSign | wvoec_mock::kControlAllowVerify);
|
||||
|
||||
oec_util_session_.license().keys[kGenericSign].key_data_length =
|
||||
wvcdm::MAC_KEY_SIZE;
|
||||
|
||||
clear_buffer_.assign(buffer_size_, 0);
|
||||
for (size_t i = 0; i < clear_buffer_.size(); i++) {
|
||||
clear_buffer_[i] = 1 + i % 250;
|
||||
}
|
||||
for (size_t i = 0; i < wvcdm::KEY_IV_SIZE; i++) {
|
||||
iv_[i] = i;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(WvGenericOperationsDataTest, GenericEncryptDecrypt) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string encrypted_buffer = GetEncryptedBuffer();
|
||||
std::string iv = GetIvBlock();
|
||||
|
||||
// Encrypt
|
||||
std::string key_id = GetKeyId(kGenericEncrypt);
|
||||
|
||||
cdm_sts = cdm_engine_->GenericEncrypt(
|
||||
session_id_, in_buffer, key_id, iv, wvcdm::kEncryptionAlgorithmAesCbc128,
|
||||
&encrypted_buffer);
|
||||
|
||||
EXPECT_EQ(NO_ERROR, cdm_sts);
|
||||
|
||||
// Decrypt, use same key as encrypt.
|
||||
key_id = GetKeyId(kGenericEncrypt);
|
||||
|
||||
std::string final_buffer;
|
||||
final_buffer.resize(in_buffer.size());
|
||||
|
||||
cdm_sts = cdm_engine_->GenericDecrypt(
|
||||
session_id_, encrypted_buffer, key_id, iv,
|
||||
wvcdm::kEncryptionAlgorithmAesCbc128, &final_buffer);
|
||||
|
||||
EXPECT_EQ(NO_ERROR, cdm_sts);
|
||||
EXPECT_EQ(0, in_buffer.compare(final_buffer));
|
||||
}
|
||||
|
||||
TEST_F(WvGenericOperationsDataTest, GenericSignVerify) {
|
||||
CdmResponseType cdm_sts;
|
||||
std::string in_buffer = GetClearBuffer();
|
||||
std::string signature_buffer = GetSignatureBuffer();
|
||||
|
||||
// Signing key
|
||||
std::string key_id = GetKeyId(kGenericSign);
|
||||
cdm_sts = cdm_engine_->GenericSign(session_id_, in_buffer, key_id,
|
||||
wvcdm::kSigningAlgorithmHmacSha256,
|
||||
&signature_buffer);
|
||||
EXPECT_EQ(NO_ERROR, cdm_sts);
|
||||
|
||||
// Verify signature, use same key as sign.
|
||||
key_id = GetKeyId(kGenericSign);
|
||||
cdm_sts = cdm_engine_->GenericVerify(session_id_, in_buffer, key_id,
|
||||
wvcdm::kSigningAlgorithmHmacSha256,
|
||||
signature_buffer);
|
||||
EXPECT_EQ(NO_ERROR, cdm_sts);
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
888
libwvdrmengine/cdm/core/test/license_keys_unittest.cpp
Normal file
888
libwvdrmengine/cdm/core/test/license_keys_unittest.cpp
Normal file
@@ -0,0 +1,888 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <vector>
|
||||
#include "license.h"
|
||||
#include "license_key_status.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
namespace {
|
||||
|
||||
static const uint32_t dev_lo_res = 200;
|
||||
static const uint32_t dev_hi_res = 400;
|
||||
static const uint32_t dev_top_res = 800;
|
||||
|
||||
static const uint32_t key_lo_res_min = 151;
|
||||
static const uint32_t key_lo_res_max = 300;
|
||||
static const uint32_t key_hi_res_min = 301;
|
||||
static const uint32_t key_hi_res_max = 450;
|
||||
static const uint32_t key_top_res_min = 451;
|
||||
static const uint32_t key_top_res_max = 650;
|
||||
|
||||
// Content Keys
|
||||
static const KeyId ck_sw_crypto = "c_key_SW_SECURE_CRYPTO";
|
||||
static const KeyId ck_sw_decode = "c_key_SW_SECURE_DECODE";
|
||||
static const KeyId ck_hw_crypto = "c_key_HW_SECURE_CRYPTO";
|
||||
static const KeyId ck_hw_decode = "c_key_HW_SECURE_DECODE";
|
||||
static const KeyId ck_hw_secure = "c_key_HW_SECURE_ALL";
|
||||
|
||||
// Operator Session Keys
|
||||
static const KeyId osk_decrypt = "os_key_generic_decrypt";
|
||||
static const KeyId osk_encrypt = "os_key_generic_encrypt";
|
||||
static const KeyId osk_sign = "os_key_generic_sign";
|
||||
static const KeyId osk_verify = "os_key_generic_verify";
|
||||
static const KeyId osk_encrypt_decrypt = "os_key_generic_encrypt_decrypt";
|
||||
static const KeyId osk_sign_verify = "os_key_generic_sign_verify";
|
||||
static const KeyId osk_all = "os_key_generic_all";
|
||||
|
||||
// HDCP test keys
|
||||
static const KeyId ck_sw_crypto_NO_HDCP = "ck_sw_crypto_NO_HDCP";
|
||||
static const KeyId ck_hw_secure_NO_HDCP = "ck_hw_secure_NO_HDCP";
|
||||
static const KeyId ck_sw_crypto_HDCP_V2_1 = "ck_sw_crypto_HDCP_V2_1";
|
||||
static const KeyId ck_hw_secure_HDCP_V2_1 = "ck_hw_secure_HDCP_V2_1";
|
||||
static const KeyId ck_sw_crypto_HDCP_NO_OUTPUT = "ck_sw_crypto_HDCP_NO_OUT";
|
||||
static const KeyId ck_hw_secure_HDCP_NO_OUTPUT = "ck_hw_secure_HDCP_NO_OUT";
|
||||
|
||||
// Constraint test keys
|
||||
static const KeyId ck_NO_HDCP_lo_res = "ck_NO_HDCP_lo_res";
|
||||
static const KeyId ck_HDCP_NO_OUTPUT_hi_res = "ck_HDCP_NO_OUTPUT_hi_res";
|
||||
static const KeyId ck_HDCP_V2_1_max_res = "ck_HDCP_V2_1_max_res";
|
||||
static const KeyId ck_NO_HDCP_dual_res = "ck_NO_HDCP_dual_res";
|
||||
|
||||
} // namespace
|
||||
|
||||
// protobuf generated classes.
|
||||
using video_widevine_server::sdk::License;
|
||||
using video_widevine_server::sdk::LicenseIdentification;
|
||||
using video_widevine_server::sdk::STREAMING;
|
||||
using video_widevine_server::sdk::OFFLINE;
|
||||
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer;
|
||||
typedef KeyContainer::VideoResolutionConstraint VideoResolutionConstraint;
|
||||
|
||||
class LicenseKeysTest : public ::testing::Test {
|
||||
protected:
|
||||
|
||||
enum KeyFlag {
|
||||
kKeyFlagNull,
|
||||
kKeyFlagFalse,
|
||||
kKeyFlagTrue
|
||||
};
|
||||
|
||||
static const KeyFlag kEncryptNull = kKeyFlagNull;
|
||||
static const KeyFlag kEncryptFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kEncryptTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kDecryptNull = kKeyFlagNull;
|
||||
static const KeyFlag kDecryptFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kDecryptTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kSignNull = kKeyFlagNull;
|
||||
static const KeyFlag kSignFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kSignTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kVerifyNull = kKeyFlagNull;
|
||||
static const KeyFlag kVerifyFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kVerifyTrue = kKeyFlagTrue;
|
||||
|
||||
static const KeyFlag kContentSecureFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kContentSecureTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kContentClearFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kContentClearTrue = kKeyFlagTrue;
|
||||
|
||||
virtual void SetUp() {
|
||||
LicenseIdentification* id = license_.mutable_id();
|
||||
id->set_version(1);
|
||||
id->set_type(STREAMING);
|
||||
}
|
||||
|
||||
virtual void AddContentKey(
|
||||
const KeyId& key_id, bool set_level = false,
|
||||
KeyContainer::SecurityLevel level = KeyContainer::SW_SECURE_CRYPTO,
|
||||
bool set_hdcp = false, KeyContainer::OutputProtection::HDCP hdcp_value =
|
||||
KeyContainer::OutputProtection::HDCP_NONE,
|
||||
bool set_constraints = false,
|
||||
std::vector<VideoResolutionConstraint>* constraints = NULL) {
|
||||
KeyContainer* key = license_.add_key();
|
||||
key->set_type(KeyContainer::CONTENT);
|
||||
if (set_level) {
|
||||
key->set_level(level);
|
||||
}
|
||||
if (set_hdcp) {
|
||||
KeyContainer::OutputProtection* pro = key->mutable_required_protection();
|
||||
pro->set_hdcp(hdcp_value);
|
||||
}
|
||||
if (set_constraints) {
|
||||
for (std::vector<VideoResolutionConstraint>::iterator
|
||||
it = constraints->begin(); it != constraints->end(); ++it) {
|
||||
VideoResolutionConstraint* constraint =
|
||||
key->add_video_resolution_constraints();
|
||||
constraint->set_min_resolution_pixels(it->min_resolution_pixels());
|
||||
constraint->set_max_resolution_pixels(it->max_resolution_pixels());
|
||||
constraint->mutable_required_protection()->
|
||||
set_hdcp(it->required_protection().hdcp());
|
||||
}
|
||||
}
|
||||
key->set_id(key_id);
|
||||
}
|
||||
|
||||
virtual void AddOperatorSessionKey(
|
||||
const KeyId& key_id, bool set_perms = false,
|
||||
KeyFlag encrypt = kKeyFlagNull, KeyFlag decrypt = kKeyFlagNull,
|
||||
KeyFlag sign = kKeyFlagNull, KeyFlag verify = kKeyFlagNull) {
|
||||
KeyContainer* non_content_key = license_.add_key();
|
||||
non_content_key->set_type(KeyContainer::OPERATOR_SESSION);
|
||||
non_content_key->set_id(key_id);
|
||||
if (set_perms) {
|
||||
KeyContainer::OperatorSessionKeyPermissions* permissions =
|
||||
non_content_key->mutable_operator_session_key_permissions();
|
||||
if (encrypt != kKeyFlagNull) {
|
||||
permissions->set_allow_encrypt(encrypt == kKeyFlagTrue);
|
||||
}
|
||||
if (decrypt != kKeyFlagNull) {
|
||||
permissions->set_allow_decrypt(decrypt == kKeyFlagTrue);
|
||||
}
|
||||
if (sign != kKeyFlagNull) {
|
||||
permissions->set_allow_sign(sign == kKeyFlagTrue);
|
||||
}
|
||||
if (verify != kKeyFlagNull) {
|
||||
permissions->set_allow_signature_verify(verify == kKeyFlagTrue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void AddSigningKey(const KeyId& key_id) {
|
||||
KeyContainer* key = license_.add_key();
|
||||
key->set_type(KeyContainer::SIGNING);
|
||||
key->set_id(key_id);
|
||||
}
|
||||
|
||||
virtual void ExpectAllowedUsageContent(
|
||||
const CdmKeyAllowedUsage& key_usage, KeyFlag secure, KeyFlag clear) {
|
||||
EXPECT_EQ(key_usage.decrypt_to_secure_buffer, secure == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.decrypt_to_clear_buffer, clear == kKeyFlagTrue);
|
||||
EXPECT_FALSE(key_usage.generic_encrypt);
|
||||
EXPECT_FALSE(key_usage.generic_decrypt);
|
||||
EXPECT_FALSE(key_usage.generic_sign);
|
||||
EXPECT_FALSE(key_usage.generic_verify);
|
||||
}
|
||||
|
||||
virtual void ExpectAllowedUsageOperator(
|
||||
const CdmKeyAllowedUsage& key_usage, KeyFlag encrypt, KeyFlag decrypt,
|
||||
KeyFlag sign, KeyFlag verify) {
|
||||
EXPECT_FALSE(key_usage.decrypt_to_secure_buffer);
|
||||
EXPECT_FALSE(key_usage.decrypt_to_clear_buffer);
|
||||
EXPECT_EQ(key_usage.generic_encrypt, encrypt == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.generic_decrypt, decrypt == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.generic_sign, sign == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.generic_verify, verify == kKeyFlagTrue);
|
||||
}
|
||||
|
||||
virtual int NumContentKeys() {
|
||||
return content_key_count_;
|
||||
}
|
||||
|
||||
virtual void StageContentKeys() {
|
||||
content_key_count_ = 0;
|
||||
AddContentKey(ck_sw_crypto, true, KeyContainer::SW_SECURE_CRYPTO);
|
||||
content_key_count_++;
|
||||
AddContentKey(ck_sw_decode, true, KeyContainer::SW_SECURE_DECODE);
|
||||
content_key_count_++;
|
||||
AddContentKey(ck_hw_crypto, true, KeyContainer::HW_SECURE_CRYPTO);
|
||||
content_key_count_++;
|
||||
AddContentKey(ck_hw_decode, true, KeyContainer::HW_SECURE_DECODE);
|
||||
content_key_count_++;
|
||||
AddContentKey(ck_hw_secure, true, KeyContainer::HW_SECURE_ALL);
|
||||
content_key_count_++;
|
||||
license_keys_.SetFromLicense(license_);
|
||||
}
|
||||
|
||||
virtual void StageOperatorSessionKeys() {
|
||||
AddOperatorSessionKey(osk_decrypt, true,
|
||||
kEncryptNull, kDecryptTrue, kSignNull, kVerifyNull);
|
||||
AddOperatorSessionKey(osk_encrypt, true,
|
||||
kEncryptTrue, kDecryptNull, kSignNull, kVerifyNull);
|
||||
AddOperatorSessionKey(osk_sign, true,
|
||||
kEncryptNull, kDecryptNull, kSignTrue, kVerifyNull);
|
||||
AddOperatorSessionKey(osk_verify, true,
|
||||
kEncryptNull, kDecryptNull, kSignNull, kVerifyTrue);
|
||||
AddOperatorSessionKey(osk_encrypt_decrypt, true,
|
||||
kEncryptTrue, kDecryptTrue, kSignNull, kVerifyNull);
|
||||
AddOperatorSessionKey(osk_sign_verify, true,
|
||||
kEncryptNull, kDecryptNull, kSignTrue, kVerifyTrue);
|
||||
AddOperatorSessionKey(osk_all, true,
|
||||
kEncryptTrue, kDecryptTrue, kSignTrue, kVerifyTrue);
|
||||
license_keys_.SetFromLicense(license_);
|
||||
}
|
||||
|
||||
virtual void StageHdcpKeys() {
|
||||
content_key_count_ = 0;
|
||||
AddContentKey(ck_sw_crypto_NO_HDCP, true, KeyContainer::SW_SECURE_CRYPTO,
|
||||
true, KeyContainer::OutputProtection::HDCP_NONE);
|
||||
content_key_count_++;
|
||||
AddContentKey(ck_hw_secure_NO_HDCP, true, KeyContainer::HW_SECURE_ALL, true,
|
||||
KeyContainer::OutputProtection::HDCP_NONE);
|
||||
content_key_count_++;
|
||||
|
||||
AddContentKey(ck_sw_crypto_HDCP_V2_1, true, KeyContainer::SW_SECURE_CRYPTO,
|
||||
true, KeyContainer::OutputProtection::HDCP_V2_1);
|
||||
content_key_count_++;
|
||||
AddContentKey(ck_hw_secure_HDCP_V2_1, true, KeyContainer::HW_SECURE_ALL,
|
||||
true, KeyContainer::OutputProtection::HDCP_V2_1);
|
||||
content_key_count_++;
|
||||
|
||||
AddContentKey(ck_sw_crypto_HDCP_NO_OUTPUT, true,
|
||||
KeyContainer::SW_SECURE_CRYPTO, true,
|
||||
KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
|
||||
content_key_count_++;
|
||||
AddContentKey(ck_hw_secure_HDCP_NO_OUTPUT, true,
|
||||
KeyContainer::HW_SECURE_ALL, true,
|
||||
KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
|
||||
content_key_count_++;
|
||||
license_keys_.SetFromLicense(license_);
|
||||
}
|
||||
|
||||
virtual void AddConstraint(
|
||||
std::vector<VideoResolutionConstraint>& constraints, uint32_t min_res,
|
||||
uint32_t max_res, bool set_hdcp = false,
|
||||
KeyContainer::OutputProtection::HDCP hdcp =
|
||||
KeyContainer::OutputProtection::HDCP_NONE) {
|
||||
VideoResolutionConstraint constraint;
|
||||
constraint.set_min_resolution_pixels(min_res);
|
||||
constraint.set_max_resolution_pixels(max_res);
|
||||
if (set_hdcp) {
|
||||
constraint.mutable_required_protection()->set_hdcp(hdcp);
|
||||
}
|
||||
constraints.push_back(constraint);
|
||||
}
|
||||
|
||||
virtual void StageConstraintKeys() {
|
||||
content_key_count_ = 0;
|
||||
|
||||
std::vector<VideoResolutionConstraint> constraints;
|
||||
|
||||
AddConstraint(constraints, key_lo_res_min, key_lo_res_max);
|
||||
|
||||
AddContentKey(ck_NO_HDCP_lo_res, true, KeyContainer::SW_SECURE_CRYPTO, true,
|
||||
KeyContainer::OutputProtection::HDCP_NONE, true,
|
||||
&constraints);
|
||||
content_key_count_++;
|
||||
|
||||
constraints.clear();
|
||||
AddConstraint(constraints, key_hi_res_min, key_hi_res_max);
|
||||
|
||||
AddContentKey(
|
||||
ck_HDCP_NO_OUTPUT_hi_res, true, KeyContainer::SW_SECURE_CRYPTO, true,
|
||||
KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT, true,
|
||||
&constraints);
|
||||
content_key_count_++;
|
||||
|
||||
constraints.clear();
|
||||
AddConstraint(constraints, key_top_res_min, key_top_res_max);
|
||||
|
||||
AddContentKey(ck_HDCP_V2_1_max_res, true, KeyContainer::SW_SECURE_CRYPTO,
|
||||
true, KeyContainer::OutputProtection::HDCP_V2_1, true,
|
||||
&constraints);
|
||||
content_key_count_++;
|
||||
|
||||
constraints.clear();
|
||||
AddConstraint(constraints, key_lo_res_min, key_lo_res_max);
|
||||
AddConstraint(constraints, key_hi_res_min, key_hi_res_max,
|
||||
KeyContainer::OutputProtection::HDCP_NO_DIGITAL_OUTPUT);
|
||||
|
||||
AddContentKey(ck_NO_HDCP_dual_res, true, KeyContainer::HW_SECURE_ALL, true,
|
||||
KeyContainer::OutputProtection::HDCP_NONE, true,
|
||||
&constraints);
|
||||
content_key_count_++;
|
||||
|
||||
license_keys_.SetFromLicense(license_);
|
||||
}
|
||||
|
||||
virtual void ExpectKeyStatusesEqual(CdmKeyStatusMap& key_status_map,
|
||||
CdmKeyStatus expected_status) {
|
||||
for (CdmKeyStatusMap::iterator it = key_status_map.begin();
|
||||
it != key_status_map.end(); ++it) {
|
||||
EXPECT_TRUE(it->second == expected_status);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ExpectKeyStatusEqual(CdmKeyStatusMap& key_status_map,
|
||||
const KeyId& key_id,
|
||||
CdmKeyStatus expected_status) {
|
||||
for (CdmKeyStatusMap::iterator it = key_status_map.begin();
|
||||
it != key_status_map.end(); ++it) {
|
||||
if (key_id == it->first) {
|
||||
EXPECT_TRUE(it->second == expected_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int content_key_count_;
|
||||
LicenseKeys license_keys_;
|
||||
License license_;
|
||||
};
|
||||
|
||||
TEST_F(LicenseKeysTest, Empty) {
|
||||
EXPECT_TRUE(license_keys_.Empty());
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, NotEmpty) {
|
||||
const KeyId c_key = "content_key";
|
||||
AddContentKey(c_key);
|
||||
license_keys_.SetFromLicense(license_);
|
||||
EXPECT_FALSE(license_keys_.Empty());
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, BadKeyId) {
|
||||
const KeyId c_key = "content_key";
|
||||
const KeyId os_key = "op_sess_key";
|
||||
const KeyId unk_key = "unknown_key";
|
||||
CdmKeyAllowedUsage allowed_usage;
|
||||
AddContentKey(c_key);
|
||||
AddOperatorSessionKey(os_key);
|
||||
license_keys_.SetFromLicense(license_);
|
||||
EXPECT_FALSE(license_keys_.IsContentKey(unk_key));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(unk_key));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(unk_key));
|
||||
EXPECT_FALSE(license_keys_.GetAllowedUsage(unk_key, &allowed_usage));
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, SigningKey) {
|
||||
const KeyId c_key = "content_key";
|
||||
const KeyId os_key = "op_sess_key";
|
||||
const KeyId sign_key = "signing_key";
|
||||
CdmKeyAllowedUsage allowed_usage;
|
||||
AddSigningKey(sign_key);
|
||||
AddContentKey(c_key);
|
||||
AddOperatorSessionKey(os_key);
|
||||
license_keys_.SetFromLicense(license_);
|
||||
EXPECT_FALSE(license_keys_.IsContentKey(sign_key));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(sign_key));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(sign_key));
|
||||
EXPECT_FALSE(license_keys_.GetAllowedUsage(sign_key, &allowed_usage));
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, ContentKey) {
|
||||
const KeyId c_key = "content_key";
|
||||
AddContentKey(c_key);
|
||||
EXPECT_FALSE(license_keys_.IsContentKey(c_key));
|
||||
|
||||
license_keys_.SetFromLicense(license_);
|
||||
EXPECT_TRUE(license_keys_.IsContentKey(c_key));
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, OperatorSessionKey) {
|
||||
const KeyId os_key = "op_sess_key";
|
||||
EXPECT_FALSE(license_keys_.IsContentKey(os_key));
|
||||
AddOperatorSessionKey(os_key);
|
||||
|
||||
license_keys_.SetFromLicense(license_);
|
||||
EXPECT_FALSE(license_keys_.IsContentKey(os_key));
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, CanDecrypt) {
|
||||
const KeyId os_key = "op_sess_key";
|
||||
const KeyId c_key = "content_key";
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(c_key));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(os_key));
|
||||
AddOperatorSessionKey(os_key);
|
||||
AddContentKey(c_key);
|
||||
license_keys_.SetFromLicense(license_);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(c_key));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(os_key));
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(c_key));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(os_key));
|
||||
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusExpired,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(c_key));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(os_key));
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, AllowedUsageNull) {
|
||||
const KeyId os_key = "op_sess_key";
|
||||
const KeyId c_key = "content_key";
|
||||
const KeyId sign_key = "signing_key";
|
||||
AddOperatorSessionKey(os_key);
|
||||
AddContentKey(c_key);
|
||||
AddSigningKey(sign_key);
|
||||
license_keys_.SetFromLicense(license_);
|
||||
CdmKeyAllowedUsage usage_1;
|
||||
EXPECT_FALSE(license_keys_.GetAllowedUsage(sign_key, &usage_1));
|
||||
|
||||
CdmKeyAllowedUsage usage_2;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(c_key, &usage_2));
|
||||
ExpectAllowedUsageContent(usage_2, kContentClearTrue, kContentSecureTrue);
|
||||
|
||||
CdmKeyAllowedUsage usage_3;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(os_key, &usage_3));
|
||||
ExpectAllowedUsageContent(usage_3, kContentClearFalse, kContentSecureFalse);
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, AllowedUsageContent) {
|
||||
StageContentKeys();
|
||||
CdmKeyAllowedUsage u_sw_crypto;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(ck_sw_crypto, &u_sw_crypto));
|
||||
ExpectAllowedUsageContent(u_sw_crypto, kContentSecureTrue, kContentClearTrue);
|
||||
|
||||
CdmKeyAllowedUsage u_sw_decode;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(ck_sw_decode, &u_sw_decode));
|
||||
ExpectAllowedUsageContent(u_sw_decode, kContentSecureTrue, kContentClearTrue);
|
||||
|
||||
CdmKeyAllowedUsage u_hw_crypto;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(ck_hw_crypto, &u_hw_crypto));
|
||||
ExpectAllowedUsageContent(u_hw_crypto, kContentSecureTrue, kContentClearTrue);
|
||||
|
||||
CdmKeyAllowedUsage u_hw_decode;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(ck_hw_decode, &u_hw_decode));
|
||||
ExpectAllowedUsageContent(u_hw_decode, kContentSecureTrue,
|
||||
kContentClearFalse);
|
||||
|
||||
CdmKeyAllowedUsage u_hw_secure;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(ck_hw_secure, &u_hw_secure));
|
||||
ExpectAllowedUsageContent(u_hw_secure, kContentSecureTrue,
|
||||
kContentClearFalse);
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, AllowedUsageOperatorSession) {
|
||||
StageOperatorSessionKeys();
|
||||
CdmKeyAllowedUsage u_encrypt;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(osk_encrypt, &u_encrypt));
|
||||
ExpectAllowedUsageOperator(u_encrypt, kEncryptTrue, kDecryptFalse, kSignFalse,
|
||||
kVerifyFalse);
|
||||
|
||||
CdmKeyAllowedUsage u_decrypt;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(osk_decrypt, &u_decrypt));
|
||||
ExpectAllowedUsageOperator(u_decrypt, kEncryptFalse, kDecryptTrue, kSignFalse,
|
||||
kVerifyFalse);
|
||||
|
||||
CdmKeyAllowedUsage u_sign;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(osk_sign, &u_sign));
|
||||
ExpectAllowedUsageOperator(u_sign, kEncryptFalse, kDecryptFalse, kSignTrue,
|
||||
kVerifyFalse);
|
||||
|
||||
CdmKeyAllowedUsage u_verify;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(osk_verify, &u_verify));
|
||||
ExpectAllowedUsageOperator(u_verify, kEncryptFalse, kDecryptFalse, kSignFalse,
|
||||
kVerifyTrue);
|
||||
|
||||
CdmKeyAllowedUsage u_encrypt_decrypt;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(osk_encrypt_decrypt,
|
||||
&u_encrypt_decrypt));
|
||||
ExpectAllowedUsageOperator(u_encrypt_decrypt, kEncryptTrue, kDecryptTrue,
|
||||
kSignFalse, kVerifyFalse);
|
||||
|
||||
CdmKeyAllowedUsage u_sign_verify;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(osk_sign_verify, &u_sign_verify));
|
||||
ExpectAllowedUsageOperator(u_sign_verify, kEncryptFalse, kDecryptFalse,
|
||||
kSignTrue, kVerifyTrue);
|
||||
|
||||
CdmKeyAllowedUsage u_all;
|
||||
EXPECT_TRUE(license_keys_.GetAllowedUsage(osk_all, &u_all));
|
||||
ExpectAllowedUsageOperator(u_all, kEncryptTrue, kDecryptTrue, kSignTrue,
|
||||
kVerifyTrue);
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, ExtractKeyStatuses) {
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageOperatorSessionKeys();
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(0, key_status_map.size());
|
||||
StageContentKeys();
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusInternalError);
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, KeyStatusChanges) {
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageOperatorSessionKeys();
|
||||
StageContentKeys();
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusInternalError);
|
||||
|
||||
// change to pending
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusPending,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusPending);
|
||||
|
||||
// change to pending (again)
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusPending,
|
||||
&new_usable_keys);
|
||||
EXPECT_FALSE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusPending);
|
||||
|
||||
// change to usable
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusUsable);
|
||||
|
||||
// change to usable (again)
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
EXPECT_FALSE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusUsable);
|
||||
|
||||
// change to expired
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusExpired,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
EXPECT_EQ(content_key_count_, key_status_map.size());
|
||||
ExpectKeyStatusesEqual(key_status_map, kKeyStatusExpired);
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, HdcpChanges) {
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageHdcpKeys();
|
||||
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_NO_HDCP, kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_V2_1,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_V1);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_FALSE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_NO_HDCP, kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_V2_1,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_V2_2);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_V2_1,
|
||||
kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_NO_OUTPUT,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_NO_DIGITAL_OUTPUT);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_V2_1,
|
||||
kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_NO_OUTPUT,
|
||||
kKeyStatusUsable);
|
||||
|
||||
license_keys_.ApplyConstraints(100, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_sw_crypto_NO_HDCP));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_hw_secure_NO_HDCP));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_V2_1));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_sw_crypto_HDCP_NO_OUTPUT));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_hw_secure_HDCP_NO_OUTPUT));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_NO_HDCP,
|
||||
kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_NO_OUTPUT,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
}
|
||||
|
||||
TEST_F(LicenseKeysTest, ConstraintChanges) {
|
||||
bool new_usable_keys = false;
|
||||
bool any_change = false;
|
||||
CdmKeyStatusMap key_status_map;
|
||||
StageConstraintKeys();
|
||||
|
||||
// No constraints set by device
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_lo_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_dual_res));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_lo_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
// Low-res device, no HDCP support
|
||||
license_keys_.ApplyConstraints(dev_lo_res, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_dual_res));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_NO_HDCP, kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_V2_1,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Hi-res device, HDCP_V1 support
|
||||
license_keys_.ApplyConstraints(dev_hi_res, HDCP_V1);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_NO_HDCP_lo_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_dual_res));
|
||||
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_NO_HDCP_lo_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_NO_HDCP, kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_V2_1,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Lo-res device, HDCP V2.2 support
|
||||
license_keys_.ApplyConstraints(dev_lo_res, HDCP_V2_2);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_dual_res));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_V2_1,
|
||||
kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_sw_crypto_HDCP_NO_OUTPUT,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Hi-res device, Maximal HDCP support
|
||||
license_keys_.ApplyConstraints(dev_hi_res, HDCP_NO_DIGITAL_OUTPUT);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_NO_HDCP_lo_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_dual_res));
|
||||
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_NO_HDCP_lo_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_V2_1,
|
||||
kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_NO_OUTPUT,
|
||||
kKeyStatusUsable);
|
||||
|
||||
// Lo-res device, no HDCP support
|
||||
license_keys_.ApplyConstraints(dev_lo_res, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_TRUE(new_usable_keys);
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.CanDecryptContent(ck_NO_HDCP_dual_res));
|
||||
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_TRUE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_NO_HDCP,
|
||||
kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_NO_OUTPUT,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
|
||||
// Too-high-res -- all keys rejected
|
||||
license_keys_.ApplyConstraints(dev_top_res, HDCP_NONE);
|
||||
any_change = license_keys_.ApplyStatusChange(kKeyStatusUsable,
|
||||
&new_usable_keys);
|
||||
|
||||
EXPECT_TRUE(any_change);
|
||||
EXPECT_FALSE(new_usable_keys);
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_FALSE(license_keys_.CanDecryptContent(ck_NO_HDCP_dual_res));
|
||||
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_NO_HDCP_lo_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_NO_OUTPUT_hi_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_HDCP_V2_1_max_res));
|
||||
EXPECT_FALSE(license_keys_.MeetsConstraints(ck_NO_HDCP_dual_res));
|
||||
|
||||
license_keys_.ExtractKeyStatuses(&key_status_map);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_NO_HDCP,
|
||||
kKeyStatusUsable);
|
||||
ExpectKeyStatusEqual(key_status_map, ck_hw_secure_HDCP_NO_OUTPUT,
|
||||
kKeyStatusOutputNotAllowed);
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
@@ -1,323 +0,0 @@
|
||||
// Copyright 2012 Google Inc. All Rights Reserved.
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include "crypto_session.h"
|
||||
#include "license.h"
|
||||
#include "max_res_engine.h"
|
||||
#include "mock_clock.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
typedef ::video_widevine_server::sdk::License License;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer::OutputProtection
|
||||
OutputProtection;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer::
|
||||
VideoResolutionConstraint VideoResolutionConstraint;
|
||||
typedef ::google::protobuf::RepeatedPtrField<KeyContainer> KeyList;
|
||||
typedef ::google::protobuf::RepeatedPtrField<VideoResolutionConstraint>
|
||||
ConstraintList;
|
||||
|
||||
using namespace testing;
|
||||
|
||||
namespace {
|
||||
|
||||
const KeyId kKeyId1 = "357adc89f1673433c36c621f1b5c41ee";
|
||||
const KeyId kKeyId2 = "3d25f819250789ecfc9ed48cc99af164";
|
||||
const KeyId kKeyId3 = "fe3cf6b69e76c9a1c877922e1a661707";
|
||||
const KeyId kKeyId4 = "29a321b9886658078f916fdd41d6f570";
|
||||
const KeyId kKeyId5 = "cc5b031bcde371031c06822d935b9a63";
|
||||
const KeyId kKeyId6 = "90ac1332e4efc8acbaf929c8d321f50c";
|
||||
|
||||
const uint32_t kMinRes1 = 0;
|
||||
const uint32_t kMaxRes1 = 2000;
|
||||
const uint32_t kTargetRes1 = (kMinRes1 + kMaxRes1) / 2;
|
||||
const uint32_t kMinRes2 = kMaxRes1;
|
||||
const uint32_t kMaxRes2 = 4000;
|
||||
const uint32_t kTargetRes2 = (kMinRes2 + kMaxRes2) / 2;
|
||||
const uint32_t kTargetRes3 = kMaxRes2 + 1000;
|
||||
|
||||
const OutputProtection::HDCP kHdcpDefault = OutputProtection::HDCP_V2;
|
||||
const OutputProtection::HDCP kHdcpConstraint = OutputProtection::HDCP_V2_1;
|
||||
|
||||
const int64_t kHdcpInterval = 10;
|
||||
|
||||
class HdcpOnlyMockCryptoSession : public CryptoSession {
|
||||
public:
|
||||
MOCK_METHOD2(GetHdcpCapabilities, bool(HdcpCapability*, HdcpCapability*));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ACTION_P2(IncrementAndReturnPointee, p, a) {
|
||||
*p += a;
|
||||
return *p;
|
||||
}
|
||||
|
||||
class MaxResEngineTest : public Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
mock_clock_ = new NiceMock<MockClock>();
|
||||
current_time_ = 0;
|
||||
|
||||
ON_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillByDefault(
|
||||
IncrementAndReturnPointee(¤t_time_, kHdcpInterval));
|
||||
|
||||
max_res_engine_.reset(new MaxResEngine(&crypto_session_, mock_clock_));
|
||||
|
||||
KeyList* keys = license_.mutable_key();
|
||||
|
||||
// Key 1 - Content key w/ ID, no HDCP, no constraints
|
||||
{
|
||||
KeyContainer* key1 = keys->Add();
|
||||
key1->set_type(KeyContainer::CONTENT);
|
||||
key1->set_id(kKeyId1);
|
||||
}
|
||||
|
||||
// Key 2 - Content key w/ ID, HDCP, no constraints
|
||||
{
|
||||
KeyContainer* key2 = keys->Add();
|
||||
key2->set_type(KeyContainer::CONTENT);
|
||||
key2->set_id(kKeyId2);
|
||||
key2->mutable_required_protection()->set_hdcp(kHdcpDefault);
|
||||
}
|
||||
|
||||
// Key 3 - Content key w/ ID, no HDCP, constraints
|
||||
{
|
||||
KeyContainer* key3 = keys->Add();
|
||||
key3->set_type(KeyContainer::CONTENT);
|
||||
key3->set_id(kKeyId3);
|
||||
AddConstraints(key3->mutable_video_resolution_constraints());
|
||||
}
|
||||
|
||||
// Key 4 - Content key w/ ID, HDCP, constraints
|
||||
{
|
||||
KeyContainer* key4 = keys->Add();
|
||||
key4->set_type(KeyContainer::CONTENT);
|
||||
key4->set_id(kKeyId4);
|
||||
key4->mutable_required_protection()->set_hdcp(kHdcpDefault);
|
||||
AddConstraints(key4->mutable_video_resolution_constraints());
|
||||
}
|
||||
|
||||
// Key 5 - Content key w/o ID, HDCP, constraints
|
||||
{
|
||||
KeyContainer* key5 = keys->Add();
|
||||
key5->set_type(KeyContainer::CONTENT);
|
||||
key5->mutable_required_protection()->set_hdcp(kHdcpDefault);
|
||||
AddConstraints(key5->mutable_video_resolution_constraints());
|
||||
}
|
||||
|
||||
// Key 6 - Non-content key
|
||||
{
|
||||
KeyContainer* key6 = keys->Add();
|
||||
key6->set_type(KeyContainer::OPERATOR_SESSION);
|
||||
}
|
||||
}
|
||||
|
||||
void AddConstraints(ConstraintList* constraints) {
|
||||
// Constraint 1 - Low-res and no HDCP
|
||||
{
|
||||
VideoResolutionConstraint* constraint1 = constraints->Add();
|
||||
constraint1->set_min_resolution_pixels(kMinRes1);
|
||||
constraint1->set_max_resolution_pixels(kMaxRes1);
|
||||
}
|
||||
|
||||
// Constraint 2 - High-res and stricter HDCP
|
||||
{
|
||||
VideoResolutionConstraint* constraint2 = constraints->Add();
|
||||
constraint2->set_min_resolution_pixels(kMinRes2);
|
||||
constraint2->set_max_resolution_pixels(kMaxRes2);
|
||||
constraint2->mutable_required_protection()->set_hdcp(kHdcpConstraint);
|
||||
}
|
||||
}
|
||||
|
||||
MockClock* mock_clock_;
|
||||
int64_t current_time_;
|
||||
StrictMock<HdcpOnlyMockCryptoSession> crypto_session_;
|
||||
scoped_ptr<MaxResEngine> max_res_engine_;
|
||||
License license_;
|
||||
};
|
||||
|
||||
TEST_F(MaxResEngineTest, IsPermissiveByDefault) {
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
max_res_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, IsPermissiveWithoutALicense) {
|
||||
max_res_engine_->SetResolution(1, kTargetRes1);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, IsPermissiveWithoutAResolution) {
|
||||
max_res_engine_->SetLicense(license_);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, HandlesResolutionsBasedOnConstraints) {
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(true)));
|
||||
|
||||
max_res_engine_->SetLicense(license_);
|
||||
|
||||
max_res_engine_->SetResolution(1, kTargetRes1);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
max_res_engine_->SetResolution(1, kTargetRes2);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
max_res_engine_->SetResolution(1, kTargetRes3);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_FALSE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, RequestsHdcpImmediatelyAndOnlyAfterInterval) {
|
||||
int64_t start_time = current_time_;
|
||||
|
||||
{
|
||||
InSequence calls;
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).WillOnce(Return(start_time));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2_2),
|
||||
Return(true)));
|
||||
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(true)));
|
||||
}
|
||||
|
||||
max_res_engine_->SetLicense(license_);
|
||||
max_res_engine_->SetResolution(1, kTargetRes1);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
max_res_engine_->OnTimerEvent();
|
||||
max_res_engine_->OnTimerEvent();
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, DoesNotRequestHdcpWithoutALicense) {
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _)).Times(0);
|
||||
|
||||
max_res_engine_->OnTimerEvent();
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, HandlesConstraintOverridingHdcp) {
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2),
|
||||
Return(true)));
|
||||
|
||||
max_res_engine_->SetLicense(license_);
|
||||
|
||||
max_res_engine_->SetResolution(1, kTargetRes1);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
max_res_engine_->SetResolution(1, kTargetRes2);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_FALSE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, HandlesNoHdcp) {
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NONE),
|
||||
Return(true)));
|
||||
|
||||
max_res_engine_->SetLicense(license_);
|
||||
|
||||
max_res_engine_->SetResolution(1, kTargetRes1);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
max_res_engine_->SetResolution(1, kTargetRes2);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_FALSE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(MaxResEngineTest, IgnoresHdcpWithoutAResolution) {
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _)).Times(0);
|
||||
|
||||
max_res_engine_->SetLicense(license_);
|
||||
max_res_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_TRUE(max_res_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
} // wvcdm
|
||||
@@ -0,0 +1,430 @@
|
||||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include "crypto_session.h"
|
||||
#include "license.h"
|
||||
#include "policy_engine.h"
|
||||
#include "mock_clock.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "wv_cdm_event_listener.h"
|
||||
#include "wv_cdm_types.h"
|
||||
|
||||
// protobuf generated classes.
|
||||
using video_widevine_server::sdk::License;
|
||||
using video_widevine_server::sdk::License_Policy;
|
||||
using video_widevine_server::sdk::STREAMING;
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
typedef ::video_widevine_server::sdk::License License;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer KeyContainer;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer::OutputProtection
|
||||
OutputProtection;
|
||||
typedef ::video_widevine_server::sdk::License::KeyContainer::
|
||||
VideoResolutionConstraint VideoResolutionConstraint;
|
||||
typedef ::google::protobuf::RepeatedPtrField<KeyContainer> KeyList;
|
||||
typedef ::google::protobuf::RepeatedPtrField<VideoResolutionConstraint>
|
||||
ConstraintList;
|
||||
|
||||
using namespace testing;
|
||||
|
||||
namespace {
|
||||
|
||||
const CdmSessionId kSessionId = "mock_session_id";
|
||||
|
||||
const KeyId kKeyId1 = "1111kKeyId1";
|
||||
const KeyId kKeyId2 = "2222kKeyId2";
|
||||
const KeyId kKeyId3 = "3333kKeyId3";
|
||||
const KeyId kKeyId4 = "4444kKeyId4";
|
||||
const KeyId kKeyId5 = "5555kKeyId5";
|
||||
const KeyId kKeyId6 = "6666kKeyId6";
|
||||
|
||||
const uint32_t kMinRes1 = 0;
|
||||
const uint32_t kMaxRes1 = 2000;
|
||||
const uint32_t kMinRes2 = kMaxRes1;
|
||||
const uint32_t kMaxRes2 = 4000;
|
||||
const uint32_t kTargetRes1 = (kMinRes1 + kMaxRes1) / 2;
|
||||
const uint32_t kTargetRes2 = (kMinRes2 + kMaxRes2) / 2;
|
||||
const uint32_t kTargetRes3 = kMaxRes2 + 1000;
|
||||
|
||||
const int64_t kRentalDuration = 604800; // 7 days
|
||||
const int64_t kPlaybackDuration = 172800; // 48 hours
|
||||
const int64_t kStreamingLicenseDuration = 300;
|
||||
|
||||
const OutputProtection::HDCP kHdcpV2 = OutputProtection::HDCP_V2;
|
||||
const OutputProtection::HDCP kHdcpV2_1 = OutputProtection::HDCP_V2_1;
|
||||
|
||||
// should match kHdcpCheckInterval in policy_engine.cpp
|
||||
const int64_t kHdcpInterval = 10;
|
||||
|
||||
class HdcpOnlyMockCryptoSession : public CryptoSession {
|
||||
public:
|
||||
MOCK_METHOD2(GetHdcpCapabilities, bool(HdcpCapability*, HdcpCapability*));
|
||||
};
|
||||
|
||||
class MockCdmEventListener : public WvCdmEventListener {
|
||||
public:
|
||||
MOCK_METHOD1(OnSessionRenewalNeeded, void(const CdmSessionId& session_id));
|
||||
MOCK_METHOD3(OnSessionKeysChange, void(const CdmSessionId& session_id,
|
||||
const CdmKeyStatusMap& keys_status,
|
||||
bool has_new_usable_key));
|
||||
MOCK_METHOD2(OnExpirationUpdate, void(const CdmSessionId& session_id,
|
||||
int64_t new_expiry_time_seconds));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class PolicyEngineConstraintsTest : public Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
mock_clock_ = new NiceMock<MockClock>();
|
||||
current_time_ = 0;
|
||||
|
||||
policy_engine_.reset(new PolicyEngine(kSessionId, &mock_event_listener_,
|
||||
&crypto_session_));
|
||||
InjectMockClock();
|
||||
|
||||
SetupLicense();
|
||||
}
|
||||
|
||||
void AddConstraints(ConstraintList* constraints) {
|
||||
// Constraint 1 - Low-res and no HDCP
|
||||
{
|
||||
VideoResolutionConstraint* c_lo_res_no_hdcp = constraints->Add();
|
||||
c_lo_res_no_hdcp->set_min_resolution_pixels(kMinRes1);
|
||||
c_lo_res_no_hdcp->set_max_resolution_pixels(kMaxRes1);
|
||||
}
|
||||
|
||||
// Constraint 2 - High-res and stricter HDCP
|
||||
{
|
||||
VideoResolutionConstraint* c_hi_res_hdcp_v2 = constraints->Add();
|
||||
c_hi_res_hdcp_v2->set_min_resolution_pixels(kMinRes2);
|
||||
c_hi_res_hdcp_v2->set_max_resolution_pixels(kMaxRes2);
|
||||
c_hi_res_hdcp_v2->mutable_required_protection()->set_hdcp(kHdcpV2_1);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupLicense() {
|
||||
license_.set_license_start_time(current_time_);
|
||||
|
||||
LicenseIdentification* id = license_.mutable_id();
|
||||
id->set_version(1);
|
||||
id->set_type(STREAMING);
|
||||
|
||||
License_Policy* policy = license_.mutable_policy();
|
||||
policy = license_.mutable_policy();
|
||||
policy->set_can_play(true);
|
||||
policy->set_can_persist(false);
|
||||
policy->set_rental_duration_seconds(kRentalDuration);
|
||||
policy->set_playback_duration_seconds(kPlaybackDuration);
|
||||
policy->set_license_duration_seconds(kStreamingLicenseDuration);
|
||||
|
||||
KeyList* keys = license_.mutable_key();
|
||||
|
||||
// Key 1 - Content key w/ ID, no HDCP, no constraints
|
||||
{
|
||||
KeyContainer* key1 = keys->Add();
|
||||
key1->set_type(KeyContainer::CONTENT);
|
||||
key1->set_id(kKeyId1);
|
||||
}
|
||||
|
||||
// Key 2 - Content key w/ ID, HDCP, no constraints
|
||||
{
|
||||
KeyContainer* key2 = keys->Add();
|
||||
key2->set_type(KeyContainer::CONTENT);
|
||||
key2->set_id(kKeyId2);
|
||||
key2->mutable_required_protection()->set_hdcp(kHdcpV2);
|
||||
}
|
||||
|
||||
// Key 3 - Content key w/ ID, no HDCP, constraints
|
||||
{
|
||||
KeyContainer* key3 = keys->Add();
|
||||
key3->set_type(KeyContainer::CONTENT);
|
||||
key3->set_id(kKeyId3);
|
||||
AddConstraints(key3->mutable_video_resolution_constraints());
|
||||
}
|
||||
|
||||
// Key 4 - Content key w/ ID, HDCP, constraints
|
||||
{
|
||||
KeyContainer* key4 = keys->Add();
|
||||
key4->set_type(KeyContainer::CONTENT);
|
||||
key4->set_id(kKeyId4);
|
||||
key4->mutable_required_protection()->set_hdcp(kHdcpV2);
|
||||
AddConstraints(key4->mutable_video_resolution_constraints());
|
||||
}
|
||||
|
||||
// Key 5 - Content key w/o ID, HDCP, constraints
|
||||
{
|
||||
KeyContainer* key5 = keys->Add();
|
||||
key5->set_type(KeyContainer::CONTENT);
|
||||
key5->mutable_required_protection()->set_hdcp(kHdcpV2);
|
||||
AddConstraints(key5->mutable_video_resolution_constraints());
|
||||
}
|
||||
|
||||
// Key 6 - Non-content key
|
||||
{
|
||||
KeyContainer* key6 = keys->Add();
|
||||
key6->set_type(KeyContainer::OPERATOR_SESSION);
|
||||
}
|
||||
}
|
||||
|
||||
void InjectMockClock() {
|
||||
mock_clock_ = new MockClock();
|
||||
policy_engine_->set_clock(mock_clock_);
|
||||
}
|
||||
|
||||
void ExpectSessionKeysChange(CdmKeyStatus expected_key_status,
|
||||
bool expected_has_new_usable_key) {
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
OnSessionKeysChange(
|
||||
kSessionId, UnorderedElementsAre(
|
||||
Pair(kKeyId1, expected_key_status),
|
||||
Pair(kKeyId2, expected_key_status),
|
||||
Pair(kKeyId3, expected_key_status),
|
||||
Pair(kKeyId4, expected_key_status)),
|
||||
expected_has_new_usable_key));
|
||||
}
|
||||
|
||||
void ExpectSessionKeysChanges(const KeyId& k1, CdmKeyStatus expected_1,
|
||||
const KeyId& k2, CdmKeyStatus expected_2,
|
||||
const KeyId& k3, CdmKeyStatus expected_3,
|
||||
const KeyId& k4, CdmKeyStatus expected_4,
|
||||
bool expected_has_new_usable_key) {
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
OnSessionKeysChange(
|
||||
kSessionId, UnorderedElementsAre(
|
||||
Pair(k1, expected_1),
|
||||
Pair(k2, expected_2),
|
||||
Pair(k3, expected_3),
|
||||
Pair(k4, expected_4)),
|
||||
expected_has_new_usable_key));
|
||||
}
|
||||
|
||||
scoped_ptr<PolicyEngine> policy_engine_;
|
||||
MockClock* mock_clock_;
|
||||
int64_t current_time_;
|
||||
StrictMock<HdcpOnlyMockCryptoSession> crypto_session_;
|
||||
StrictMock<MockCdmEventListener> mock_event_listener_;
|
||||
License license_;
|
||||
};
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, IsPermissiveWithoutAResolution) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).Times(2);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->OnTimerEvent();
|
||||
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, HandlesResolutionsBasedOnConstraints) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<4; ++i) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).InSequence(time)
|
||||
.WillOnce(Return(i * 10));
|
||||
}
|
||||
}
|
||||
{
|
||||
Sequence key_change;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusUsable,
|
||||
kKeyId3, kKeyStatusOutputNotAllowed,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, false);
|
||||
}
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_NO_DIGITAL_OUTPUT),
|
||||
Return(true)));
|
||||
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
policy_engine_->NotifyResolution(1, kTargetRes2);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
policy_engine_->NotifyResolution(1, kTargetRes3);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest,
|
||||
RequestsHdcpImmediatelyAndOnlyAfterInterval) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(0))
|
||||
.WillOnce(Return(5));
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
|
||||
int64_t start_time = current_time_ + 5;
|
||||
{
|
||||
InSequence calls;
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillOnce(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2_2),
|
||||
Return(true)));
|
||||
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(true)));
|
||||
}
|
||||
|
||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->OnTimerEvent();
|
||||
policy_engine_->OnTimerEvent();
|
||||
policy_engine_->OnTimerEvent();
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, DoesNotRequestHdcpWithoutALicense) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(0));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _)).Times(0);
|
||||
|
||||
policy_engine_->OnTimerEvent();
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, HandlesConstraintOverridingHdcp) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<3; ++i) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).InSequence(time)
|
||||
.WillOnce(Return(i * 10));
|
||||
}
|
||||
}
|
||||
{
|
||||
Sequence key_change;
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusUsable,
|
||||
kKeyId3, kKeyStatusOutputNotAllowed,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, false);
|
||||
}
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _))
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(HDCP_V2),
|
||||
Return(true)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
policy_engine_->NotifyResolution(1, kTargetRes2);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, HandlesNoHdcp) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<3; ++i) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).InSequence(time)
|
||||
.WillOnce(Return(i * 10));
|
||||
}
|
||||
}
|
||||
{
|
||||
Sequence key_change;
|
||||
ExpectSessionKeysChanges(kKeyId1, kKeyStatusUsable,
|
||||
kKeyId2, kKeyStatusOutputNotAllowed,
|
||||
kKeyId3, kKeyStatusUsable,
|
||||
kKeyId4, kKeyStatusOutputNotAllowed, false);
|
||||
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),
|
||||
Return(true)));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
policy_engine_->NotifyResolution(1, kTargetRes1);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
|
||||
policy_engine_->NotifyResolution(1, kTargetRes2);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineConstraintsTest, IgnoresHdcpWithoutAResolution) {
|
||||
{
|
||||
Sequence time;
|
||||
for (int i=0; i<2; ++i) {
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime()).InSequence(time)
|
||||
.WillOnce(Return(i * 10));
|
||||
}
|
||||
}
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(kSessionId, _));
|
||||
EXPECT_CALL(crypto_session_, GetHdcpCapabilities(_, _)).Times(0);
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId1));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId2));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId3));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId4));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId5));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId6));
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
@@ -42,6 +42,7 @@ const char* kRenewalServerUrl =
|
||||
const KeyId kKeyId = "357adc89f1673433c36c621f1b5c41ee";
|
||||
const KeyId kAnotherKeyId = "another_key_id";
|
||||
const KeyId kSomeRandomKeyId = "some_random_key_id";
|
||||
const KeyId kUnknownKeyId = "some_random_unknown_key_id";
|
||||
const CdmSessionId kSessionId = "mock_session_id";
|
||||
|
||||
int64_t GetLicenseRenewalDelay(int64_t license_duration) {
|
||||
@@ -60,13 +61,6 @@ class MockCdmEventListener : public WvCdmEventListener {
|
||||
int64_t new_expiry_time_seconds));
|
||||
};
|
||||
|
||||
class MockMaxResEngine : public MaxResEngine {
|
||||
public:
|
||||
MockMaxResEngine() : MaxResEngine(NULL) {}
|
||||
|
||||
MOCK_METHOD1(CanDecrypt, bool(const KeyId& key_id));
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// protobuf generated classes.
|
||||
@@ -138,11 +132,6 @@ class PolicyEngineTest : public ::testing::Test {
|
||||
policy_engine_->set_clock(mock_clock_);
|
||||
}
|
||||
|
||||
void InjectMockMaxResEngine() {
|
||||
mock_max_res_engine_ = new MockMaxResEngine();
|
||||
policy_engine_->set_max_res_engine(mock_max_res_engine_);
|
||||
}
|
||||
|
||||
void ExpectSessionKeysChange(CdmKeyStatus expected_key_status,
|
||||
bool expected_has_new_usable_key) {
|
||||
EXPECT_CALL(mock_event_listener_,
|
||||
@@ -165,7 +154,6 @@ class PolicyEngineTest : public ::testing::Test {
|
||||
|
||||
StrictMock<MockCdmEventListener> mock_event_listener_;
|
||||
MockClock* mock_clock_;
|
||||
MockMaxResEngine* mock_max_res_engine_;
|
||||
scoped_ptr<PolicyEngine> policy_engine_;
|
||||
License license_;
|
||||
MockFunction<void(int i)> check_;
|
||||
@@ -1036,56 +1024,204 @@ TEST_F(PolicyEngineTest, MultipleKeysInLicense) {
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kSomeRandomKeyId));
|
||||
}
|
||||
|
||||
TEST_F(PolicyEngineTest, KeysOutputNotAllowedByMaxResEngine) {
|
||||
class PolicyEngineKeyAllowedUsageTest : public PolicyEngineTest {
|
||||
protected:
|
||||
enum KeyFlag {
|
||||
kKeyFlagNull,
|
||||
kKeyFlagFalse,
|
||||
kKeyFlagTrue
|
||||
};
|
||||
|
||||
static const KeyFlag kEncryptNull = kKeyFlagNull;
|
||||
static const KeyFlag kEncryptFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kEncryptTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kDecryptNull = kKeyFlagNull;
|
||||
static const KeyFlag kDecryptFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kDecryptTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kSignNull = kKeyFlagNull;
|
||||
static const KeyFlag kSignFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kSignTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kVerifyNull = kKeyFlagNull;
|
||||
static const KeyFlag kVerifyFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kVerifyTrue = kKeyFlagTrue;
|
||||
|
||||
static const KeyFlag kContentSecureFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kContentSecureTrue = kKeyFlagTrue;
|
||||
static const KeyFlag kContentClearFalse = kKeyFlagFalse;
|
||||
static const KeyFlag kContentClearTrue = kKeyFlagTrue;
|
||||
|
||||
|
||||
void ExpectAllowedContentKeySettings(const CdmKeyAllowedUsage& key_usage,
|
||||
KeyFlag secure, KeyFlag clear) {
|
||||
EXPECT_EQ(key_usage.decrypt_to_secure_buffer, secure == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.decrypt_to_clear_buffer, clear == kKeyFlagTrue);
|
||||
EXPECT_FALSE(key_usage.generic_encrypt);
|
||||
EXPECT_FALSE(key_usage.generic_decrypt);
|
||||
EXPECT_FALSE(key_usage.generic_sign);
|
||||
EXPECT_FALSE(key_usage.generic_verify);
|
||||
}
|
||||
|
||||
void ExpectAllowedOperatorKeySettings(const CdmKeyAllowedUsage& key_usage,
|
||||
KeyFlag encrypt, KeyFlag decrypt,
|
||||
KeyFlag sign, KeyFlag verify) {
|
||||
EXPECT_FALSE(key_usage.decrypt_to_secure_buffer);
|
||||
EXPECT_FALSE(key_usage.decrypt_to_clear_buffer);
|
||||
EXPECT_EQ(key_usage.generic_encrypt, encrypt == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.generic_decrypt, decrypt == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.generic_sign, sign == kKeyFlagTrue);
|
||||
EXPECT_EQ(key_usage.generic_verify, verify == kKeyFlagTrue);
|
||||
}
|
||||
|
||||
void ExpectSecureContentKey(const KeyId& key_id) {
|
||||
CdmKeyAllowedUsage key_usage;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
policy_engine_->QueryKeyAllowedUsage(key_id, &key_usage));
|
||||
|
||||
ExpectAllowedContentKeySettings(key_usage, kContentSecureTrue,
|
||||
kContentSecureFalse);
|
||||
}
|
||||
|
||||
void ExpectLessSecureContentKey(const KeyId& key_id) {
|
||||
CdmKeyAllowedUsage key_usage;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
policy_engine_->QueryKeyAllowedUsage(key_id, &key_usage));
|
||||
|
||||
ExpectAllowedContentKeySettings(key_usage, kContentSecureTrue,
|
||||
kContentSecureTrue);
|
||||
}
|
||||
|
||||
void ExpectOperatorSessionKey(const KeyId& key_id, KeyFlag encrypt,
|
||||
KeyFlag decrypt, KeyFlag sign, KeyFlag verify) {
|
||||
CdmKeyAllowedUsage key_usage;
|
||||
EXPECT_EQ(NO_ERROR,
|
||||
policy_engine_->QueryKeyAllowedUsage(key_id, &key_usage));
|
||||
|
||||
ExpectAllowedOperatorKeySettings(key_usage, encrypt, decrypt, sign, verify);
|
||||
}
|
||||
|
||||
void AddOperatorSessionKey(const KeyId& key_id, KeyFlag encrypt,
|
||||
KeyFlag decrypt, KeyFlag sign, KeyFlag verify) {
|
||||
License::KeyContainer* non_content_key = license_.add_key();
|
||||
non_content_key->set_type(License::KeyContainer::OPERATOR_SESSION);
|
||||
non_content_key->set_id(key_id);
|
||||
License::KeyContainer::OperatorSessionKeyPermissions* permissions =
|
||||
non_content_key->mutable_operator_session_key_permissions();
|
||||
if (encrypt != kKeyFlagNull) {
|
||||
permissions->set_allow_encrypt(encrypt == kKeyFlagTrue);
|
||||
}
|
||||
if (decrypt != kKeyFlagNull) {
|
||||
permissions->set_allow_decrypt(decrypt == kKeyFlagTrue);
|
||||
}
|
||||
if (sign != kKeyFlagNull) {
|
||||
permissions->set_allow_sign(sign == kKeyFlagTrue);
|
||||
}
|
||||
if (verify != kKeyFlagNull) {
|
||||
permissions->set_allow_signature_verify(verify == kKeyFlagTrue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(PolicyEngineKeyAllowedUsageTest, AllowedUsageBasic) {
|
||||
|
||||
const KeyId kGenericKeyId = "oper_session_key";
|
||||
|
||||
license_.clear_key();
|
||||
|
||||
// most secure
|
||||
License::KeyContainer* content_key = license_.add_key();
|
||||
content_key->set_type(License::KeyContainer::CONTENT);
|
||||
content_key->set_id(kKeyId);
|
||||
content_key->set_level(License::KeyContainer::HW_SECURE_ALL);
|
||||
|
||||
// generic operator session key (sign)
|
||||
AddOperatorSessionKey(kGenericKeyId, kEncryptNull, kDecryptNull, kSignTrue,
|
||||
kVerifyNull);
|
||||
|
||||
License::KeyContainer* content_key_without_id = license_.add_key();
|
||||
content_key_without_id->set_type(License::KeyContainer::CONTENT);
|
||||
|
||||
// default level - less secure
|
||||
License::KeyContainer* another_content_key = license_.add_key();
|
||||
another_content_key->set_type(License::KeyContainer::CONTENT);
|
||||
another_content_key->set_id(kAnotherKeyId);
|
||||
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(kLicenseStartTime + 1))
|
||||
.WillOnce(Return(kLicenseStartTime + 5))
|
||||
.WillOnce(Return(kLicenseStartTime + 8))
|
||||
.WillOnce(Return(kLicenseStartTime + 10));
|
||||
.WillOnce(Return(kLicenseStartTime + 1));
|
||||
|
||||
InjectMockMaxResEngine();
|
||||
EXPECT_CALL(*mock_max_res_engine_, CanDecrypt(kKeyId))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(true))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*mock_max_res_engine_, CanDecrypt(kAnotherKeyId))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(true))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
InSequence s;
|
||||
ExpectSessionKeysChange(kKeyStatusOutputNotAllowed,
|
||||
kKeyStatusOutputNotAllowed, false);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusOutputNotAllowed, true);
|
||||
ExpectSessionKeysChange(kKeyStatusOutputNotAllowed, kKeyStatusUsable, true);
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||
ExpectSecureContentKey(kKeyId);
|
||||
ExpectLessSecureContentKey(kAnotherKeyId);
|
||||
ExpectOperatorSessionKey(kGenericKeyId, kEncryptNull, kDecryptNull,
|
||||
kSignTrue, kVerifyNull);
|
||||
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_FALSE(policy_engine_->CanDecrypt(kKeyId));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||
CdmKeyAllowedUsage key_usage;
|
||||
EXPECT_EQ(KEY_NOT_FOUND_1,
|
||||
policy_engine_->QueryKeyAllowedUsage(kUnknownKeyId, &key_usage));
|
||||
}
|
||||
|
||||
policy_engine_->OnTimerEvent();
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kKeyId));
|
||||
EXPECT_TRUE(policy_engine_->CanDecrypt(kAnotherKeyId));
|
||||
TEST_F(PolicyEngineKeyAllowedUsageTest, AllowedUsageGeneric) {
|
||||
|
||||
const KeyId kGenericEncryptKeyId = "oper_session_key_1";
|
||||
const KeyId kGenericDecryptKeyId = "oper_session_key_2";
|
||||
const KeyId kGenericSignKeyId = "oper_session_key_3";
|
||||
const KeyId kGenericVerifyKeyId = "oper_session_key_4";
|
||||
const KeyId kGenericFullKeyId = "oper_session_key_5";
|
||||
const KeyId kGenericExplicitKeyId = "oper_session_key_6";
|
||||
|
||||
license_.clear_key();
|
||||
|
||||
// more secure
|
||||
License::KeyContainer* content_key = license_.add_key();
|
||||
content_key->set_type(License::KeyContainer::CONTENT);
|
||||
content_key->set_id(kKeyId);
|
||||
content_key->set_level(License::KeyContainer::HW_SECURE_DECODE);
|
||||
|
||||
// less secure
|
||||
License::KeyContainer* another_content_key = license_.add_key();
|
||||
another_content_key->set_type(License::KeyContainer::CONTENT);
|
||||
another_content_key->set_id(kAnotherKeyId);
|
||||
another_content_key->set_level(License::KeyContainer::HW_SECURE_CRYPTO);
|
||||
|
||||
// generic operator session keys
|
||||
AddOperatorSessionKey(kGenericSignKeyId, kEncryptNull, kDecryptNull,
|
||||
kSignTrue, kVerifyNull);
|
||||
AddOperatorSessionKey(kGenericEncryptKeyId, kEncryptTrue, kDecryptNull,
|
||||
kSignNull, kVerifyNull);
|
||||
AddOperatorSessionKey(kGenericDecryptKeyId, kEncryptNull, kDecryptTrue,
|
||||
kSignNull, kVerifyNull);
|
||||
AddOperatorSessionKey(kGenericVerifyKeyId, kEncryptNull, kDecryptNull,
|
||||
kSignNull, kVerifyTrue);
|
||||
AddOperatorSessionKey(kGenericFullKeyId, kEncryptTrue, kDecryptTrue,
|
||||
kSignTrue, kVerifyTrue);
|
||||
AddOperatorSessionKey(kGenericExplicitKeyId, kEncryptFalse, kDecryptTrue,
|
||||
kSignFalse, kVerifyTrue);
|
||||
|
||||
EXPECT_CALL(*mock_clock_, GetCurrentTime())
|
||||
.WillOnce(Return(kLicenseStartTime + 1));
|
||||
|
||||
ExpectSessionKeysChange(kKeyStatusUsable, kKeyStatusUsable, true);
|
||||
EXPECT_CALL(mock_event_listener_, OnExpirationUpdate(_, _));
|
||||
|
||||
policy_engine_->SetLicense(license_);
|
||||
|
||||
ExpectSecureContentKey(kKeyId);
|
||||
ExpectLessSecureContentKey(kAnotherKeyId);
|
||||
ExpectOperatorSessionKey(kGenericEncryptKeyId, kEncryptTrue, kDecryptFalse,
|
||||
kSignFalse, kVerifyFalse);
|
||||
ExpectOperatorSessionKey(kGenericDecryptKeyId, kEncryptFalse, kDecryptTrue,
|
||||
kSignFalse, kVerifyFalse);
|
||||
ExpectOperatorSessionKey(kGenericSignKeyId, kEncryptFalse, kDecryptFalse,
|
||||
kSignTrue, kVerifyFalse);
|
||||
ExpectOperatorSessionKey(kGenericVerifyKeyId, kEncryptFalse, kDecryptFalse,
|
||||
kSignFalse, kVerifyTrue);
|
||||
ExpectOperatorSessionKey(kGenericFullKeyId, kEncryptTrue, kDecryptTrue,
|
||||
kSignTrue, kVerifyTrue);
|
||||
ExpectOperatorSessionKey(kGenericExplicitKeyId, kEncryptFalse, kDecryptTrue,
|
||||
kSignFalse, kVerifyTrue);
|
||||
}
|
||||
|
||||
class PolicyEngineQueryTest : public PolicyEngineTest {
|
||||
|
||||
@@ -26,59 +26,74 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case DEVICE_REVOKED: *os << "DEVICE_REVOKED";
|
||||
break;
|
||||
case INSUFFICIENT_CRYPTO_RESOURCES: *os << "INSUFFICIENT_CRYPTO_RESOURCES";
|
||||
case INSUFFICIENT_CRYPTO_RESOURCES: *os << "INSUFFICIENT_CRYPTO_RESOURCES";
|
||||
break;
|
||||
case ADD_KEY_ERROR: *os << "ADD_KEY_ERROR";
|
||||
break;
|
||||
case CERT_PROVISIONING_GET_KEYBOX_ERROR_1: *os << "CERT_PROVISIONING_GET_KEYBOX_ERROR_1";
|
||||
case CERT_PROVISIONING_GET_KEYBOX_ERROR_1:
|
||||
*os << "CERT_PROVISIONING_GET_KEYBOX_ERROR_1";
|
||||
break;
|
||||
case CERT_PROVISIONING_GET_KEYBOX_ERROR_2: *os << "CERT_PROVISIONING_GET_KEYBOX_ERROR_2";
|
||||
case CERT_PROVISIONING_GET_KEYBOX_ERROR_2:
|
||||
*os << "CERT_PROVISIONING_GET_KEYBOX_ERROR_2";
|
||||
break;
|
||||
case CERT_PROVISIONING_INVALID_CERT_TYPE: *os << "CERT_PROVISIONING_INVALID_CERT_TYPE";
|
||||
case CERT_PROVISIONING_INVALID_CERT_TYPE:
|
||||
*os << "CERT_PROVISIONING_INVALID_CERT_TYPE";
|
||||
break;
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_1: *os << "CERT_PROVISIONING_REQUEST_ERROR_1";
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_1:
|
||||
*os << "CERT_PROVISIONING_REQUEST_ERROR_1";
|
||||
break;
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_2: *os << "CERT_PROVISIONING_REQUEST_ERROR_2";
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_2:
|
||||
*os << "CERT_PROVISIONING_REQUEST_ERROR_2";
|
||||
break;
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_3: *os << "CERT_PROVISIONING_REQUEST_ERROR_3";
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_3:
|
||||
*os << "CERT_PROVISIONING_REQUEST_ERROR_3";
|
||||
break;
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_4: *os << "CERT_PROVISIONING_REQUEST_ERROR_4";
|
||||
case CERT_PROVISIONING_REQUEST_ERROR_4:
|
||||
*os << "CERT_PROVISIONING_REQUEST_ERROR_4";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_1: *os << "CERT_PROVISIONING_RESPONSE_ERROR_1";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_1:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_1";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_2: *os << "CERT_PROVISIONING_RESPONSE_ERROR_2";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_2:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_2";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_3: *os << "CERT_PROVISIONING_RESPONSE_ERROR_3";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_3:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_3";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_4: *os << "CERT_PROVISIONING_RESPONSE_ERROR_4";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_4:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_4";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_5: *os << "CERT_PROVISIONING_RESPONSE_ERROR_5";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_5:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_5";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_6: *os << "CERT_PROVISIONING_RESPONSE_ERROR_6";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_6:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_6";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_7: *os << "CERT_PROVISIONING_RESPONSE_ERROR_7";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_7:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_7";
|
||||
break;
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_8: *os << "CERT_PROVISIONING_RESPONSE_ERROR_8";
|
||||
case CERT_PROVISIONING_RESPONSE_ERROR_8:
|
||||
*os << "CERT_PROVISIONING_RESPONSE_ERROR_8";
|
||||
break;
|
||||
case CRYPTO_SESSION_OPEN_ERROR_1: *os << "CRYPTO_SESSION_OPEN_ERROR_1";
|
||||
case CRYPTO_SESSION_OPEN_ERROR_1: *os << "CRYPTO_SESSION_OPEN_ERROR_1";
|
||||
break;
|
||||
case CRYPTO_SESSION_OPEN_ERROR_2: *os << "CRYPTO_SESSION_OPEN_ERROR_2";
|
||||
case CRYPTO_SESSION_OPEN_ERROR_2: *os << "CRYPTO_SESSION_OPEN_ERROR_2";
|
||||
break;
|
||||
case CRYPTO_SESSION_OPEN_ERROR_3: *os << "CRYPTO_SESSION_OPEN_ERROR_3";
|
||||
case CRYPTO_SESSION_OPEN_ERROR_3: *os << "CRYPTO_SESSION_OPEN_ERROR_3";
|
||||
break;
|
||||
case CRYPTO_SESSION_OPEN_ERROR_4: *os << "CRYPTO_SESSION_OPEN_ERROR_4";
|
||||
case CRYPTO_SESSION_OPEN_ERROR_4: *os << "CRYPTO_SESSION_OPEN_ERROR_4";
|
||||
break;
|
||||
case CRYPTO_SESSION_OPEN_ERROR_5: *os << "CRYPTO_SESSION_OPEN_ERROR_5";
|
||||
case CRYPTO_SESSION_OPEN_ERROR_5: *os << "CRYPTO_SESSION_OPEN_ERROR_5";
|
||||
break;
|
||||
case DECRYPT_NOT_READY: *os << "DECRYPT_NOT_READY";
|
||||
break;
|
||||
case DEVICE_CERTIFICATE_ERROR_1: *os << "DEVICE_CERTIFICATE_ERROR_1";
|
||||
case DEVICE_CERTIFICATE_ERROR_1: *os << "DEVICE_CERTIFICATE_ERROR_1";
|
||||
break;
|
||||
case DEVICE_CERTIFICATE_ERROR_2: *os << "DEVICE_CERTIFICATE_ERROR_2";
|
||||
case DEVICE_CERTIFICATE_ERROR_2: *os << "DEVICE_CERTIFICATE_ERROR_2";
|
||||
break;
|
||||
case DEVICE_CERTIFICATE_ERROR_3: *os << "DEVICE_CERTIFICATE_ERROR_3";
|
||||
case DEVICE_CERTIFICATE_ERROR_3: *os << "DEVICE_CERTIFICATE_ERROR_3";
|
||||
break;
|
||||
case DEVICE_CERTIFICATE_ERROR_4: *os << "DEVICE_CERTIFICATE_ERROR_4";
|
||||
case DEVICE_CERTIFICATE_ERROR_4: *os << "DEVICE_CERTIFICATE_ERROR_4";
|
||||
break;
|
||||
case EMPTY_KEY_DATA_1: *os << "EMPTY_KEY_DATA_1";
|
||||
break;
|
||||
@@ -96,25 +111,27 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case EMPTY_LICENSE_RENEWAL: *os << "EMPTY_LICENSE_RENEWAL";
|
||||
break;
|
||||
case EMPTY_LICENSE_RESPONSE_1: *os << "EMPTY_LICENSE_RESPONSE_1";
|
||||
case EMPTY_LICENSE_RESPONSE_1: *os << "EMPTY_LICENSE_RESPONSE_1";
|
||||
break;
|
||||
case EMPTY_LICENSE_RESPONSE_2: *os << "EMPTY_LICENSE_RESPONSE_2";
|
||||
case EMPTY_LICENSE_RESPONSE_2: *os << "EMPTY_LICENSE_RESPONSE_2";
|
||||
break;
|
||||
case EMPTY_PROVISIONING_CERTIFICATE_1: *os << "EMPTY_PROVISIONING_CERTIFICATE_1";
|
||||
case EMPTY_PROVISIONING_CERTIFICATE_1:
|
||||
*os << "EMPTY_PROVISIONING_CERTIFICATE_1";
|
||||
break;
|
||||
case EMPTY_PROVISIONING_RESPONSE: *os << "EMPTY_PROVISIONING_RESPONSE";
|
||||
case EMPTY_PROVISIONING_RESPONSE: *os << "EMPTY_PROVISIONING_RESPONSE";
|
||||
break;
|
||||
case EMPTY_SESSION_ID: *os << "EMPTY_SESSION_ID";
|
||||
break;
|
||||
case GENERATE_DERIVED_KEYS_ERROR: *os << "GENERATE_DERIVED_KEYS_ERROR";
|
||||
case GENERATE_DERIVED_KEYS_ERROR: *os << "GENERATE_DERIVED_KEYS_ERROR";
|
||||
break;
|
||||
case LICENSE_RENEWAL_NONCE_GENERATION_ERROR: *os << "LICENSE_RENEWAL_NONCE_GENERATION_ERROR";
|
||||
case LICENSE_RENEWAL_NONCE_GENERATION_ERROR:
|
||||
*os << "LICENSE_RENEWAL_NONCE_GENERATION_ERROR";
|
||||
break;
|
||||
case GENERATE_USAGE_REPORT_ERROR: *os << "GENERATE_USAGE_REPORT_ERROR";
|
||||
case GENERATE_USAGE_REPORT_ERROR: *os << "GENERATE_USAGE_REPORT_ERROR";
|
||||
break;
|
||||
case GET_LICENSE_ERROR: *os << "GET_LICENSE_ERROR";
|
||||
break;
|
||||
case GET_RELEASED_LICENSE_ERROR: *os << "GET_RELEASED_LICENSE_ERROR";
|
||||
case GET_RELEASED_LICENSE_ERROR: *os << "GET_RELEASED_LICENSE_ERROR";
|
||||
break;
|
||||
case GET_USAGE_INFO_ERROR_1: *os << "GET_USAGE_INFO_ERROR_1";
|
||||
break;
|
||||
@@ -126,51 +143,60 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case INIT_DATA_NOT_FOUND: *os << "INIT_DATA_NOT_FOUND";
|
||||
break;
|
||||
case INVALID_CRYPTO_SESSION_1: *os << "INVALID_CRYPTO_SESSION_1";
|
||||
case INVALID_CRYPTO_SESSION_1: *os << "INVALID_CRYPTO_SESSION_1";
|
||||
break;
|
||||
case INVALID_CRYPTO_SESSION_2: *os << "INVALID_CRYPTO_SESSION_2";
|
||||
case INVALID_CRYPTO_SESSION_2: *os << "INVALID_CRYPTO_SESSION_2";
|
||||
break;
|
||||
case INVALID_CRYPTO_SESSION_3: *os << "INVALID_CRYPTO_SESSION_3";
|
||||
case INVALID_CRYPTO_SESSION_3: *os << "INVALID_CRYPTO_SESSION_3";
|
||||
break;
|
||||
case INVALID_CRYPTO_SESSION_4: *os << "INVALID_CRYPTO_SESSION_4";
|
||||
case INVALID_CRYPTO_SESSION_4: *os << "INVALID_CRYPTO_SESSION_4";
|
||||
break;
|
||||
case INVALID_CRYPTO_SESSION_5: *os << "INVALID_CRYPTO_SESSION_5";
|
||||
case INVALID_CRYPTO_SESSION_5: *os << "INVALID_CRYPTO_SESSION_5";
|
||||
break;
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_1: *os << "INVALID_DECRYPT_PARAMETERS_ENG_1";
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_1:
|
||||
*os << "INVALID_DECRYPT_PARAMETERS_ENG_1";
|
||||
break;
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_2: *os << "INVALID_DECRYPT_PARAMETERS_ENG_2";
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_2:
|
||||
*os << "INVALID_DECRYPT_PARAMETERS_ENG_2";
|
||||
break;
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_3: *os << "INVALID_DECRYPT_PARAMETERS_ENG_3";
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_3:
|
||||
*os << "INVALID_DECRYPT_PARAMETERS_ENG_3";
|
||||
break;
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_4: *os << "INVALID_DECRYPT_PARAMETERS_ENG_4";
|
||||
case INVALID_DECRYPT_PARAMETERS_ENG_4:
|
||||
*os << "INVALID_DECRYPT_PARAMETERS_ENG_4";
|
||||
break;
|
||||
case INVALID_DEVICE_CERTIFICATE_TYPE: *os << "INVALID_DEVICE_CERTIFICATE_TYPE";
|
||||
case INVALID_DEVICE_CERTIFICATE_TYPE:
|
||||
*os << "INVALID_DEVICE_CERTIFICATE_TYPE";
|
||||
break;
|
||||
case INVALID_KEY_SYSTEM: *os << "INVALID_KEY_SYSTEM";
|
||||
break;
|
||||
case INVALID_LICENSE_RESPONSE: *os << "INVALID_LICENSE_RESPONSE";
|
||||
case INVALID_LICENSE_RESPONSE: *os << "INVALID_LICENSE_RESPONSE";
|
||||
break;
|
||||
case INVALID_LICENSE_TYPE: *os << "INVALID_LICENSE_TYPE";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_1: *os << "INVALID_PARAMETERS_ENG_1";
|
||||
case INVALID_PARAMETERS_ENG_1: *os << "INVALID_PARAMETERS_ENG_1";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_2: *os << "INVALID_PARAMETERS_ENG_2";
|
||||
case INVALID_PARAMETERS_ENG_2: *os << "INVALID_PARAMETERS_ENG_2";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_3: *os << "INVALID_PARAMETERS_ENG_3";
|
||||
case INVALID_PARAMETERS_ENG_3: *os << "INVALID_PARAMETERS_ENG_3";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_4: *os << "INVALID_PARAMETERS_ENG_4";
|
||||
case INVALID_PARAMETERS_ENG_4: *os << "INVALID_PARAMETERS_ENG_4";
|
||||
break;
|
||||
case INVALID_PARAMETERS_LIC_1: *os << "INVALID_PARAMETERS_LIC_1";
|
||||
case INVALID_PARAMETERS_LIC_1: *os << "INVALID_PARAMETERS_LIC_1";
|
||||
break;
|
||||
case INVALID_PARAMETERS_LIC_2: *os << "INVALID_PARAMETERS_LIC_2";
|
||||
case INVALID_PARAMETERS_LIC_2: *os << "INVALID_PARAMETERS_LIC_2";
|
||||
break;
|
||||
case INVALID_PROVISIONING_PARAMETERS_1: *os << "INVALID_PROVISIONING_PARAMETERS_1";
|
||||
case INVALID_PROVISIONING_PARAMETERS_1:
|
||||
*os << "INVALID_PROVISIONING_PARAMETERS_1";
|
||||
break;
|
||||
case INVALID_PROVISIONING_PARAMETERS_2: *os << "INVALID_PROVISIONING_PARAMETERS_2";
|
||||
case INVALID_PROVISIONING_PARAMETERS_2:
|
||||
*os << "INVALID_PROVISIONING_PARAMETERS_2";
|
||||
break;
|
||||
case INVALID_PROVISIONING_REQUEST_PARAM_1: *os << "INVALID_PROVISIONING_REQUEST_PARAM_1";
|
||||
case INVALID_PROVISIONING_REQUEST_PARAM_1:
|
||||
*os << "INVALID_PROVISIONING_REQUEST_PARAM_1";
|
||||
break;
|
||||
case INVALID_PROVISIONING_REQUEST_PARAM_2: *os << "INVALID_PROVISIONING_REQUEST_PARAM_2";
|
||||
case INVALID_PROVISIONING_REQUEST_PARAM_2:
|
||||
*os << "INVALID_PROVISIONING_REQUEST_PARAM_2";
|
||||
break;
|
||||
case INVALID_QUERY_KEY: *os << "INVALID_QUERY_KEY";
|
||||
break;
|
||||
@@ -188,22 +214,28 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case LICENSE_ID_NOT_FOUND: *os << "LICENSE_ID_NOT_FOUND";
|
||||
break;
|
||||
case LICENSE_PARSER_INIT_ERROR: *os << "LICENSE_PARSER_INIT_ERROR";
|
||||
case LICENSE_PARSER_INIT_ERROR: *os << "LICENSE_PARSER_INIT_ERROR";
|
||||
break;
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_1: *os << "LICENSE_PARSER_NOT_INITIALIZED_1";
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_1:
|
||||
*os << "LICENSE_PARSER_NOT_INITIALIZED_1";
|
||||
break;
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_2: *os << "LICENSE_PARSER_NOT_INITIALIZED_2";
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_2:
|
||||
*os << "LICENSE_PARSER_NOT_INITIALIZED_2";
|
||||
break;
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_3: *os << "LICENSE_PARSER_NOT_INITIALIZED_3";
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_3:
|
||||
*os << "LICENSE_PARSER_NOT_INITIALIZED_3";
|
||||
break;
|
||||
case LICENSE_RESPONSE_NOT_SIGNED: *os << "LICENSE_RESPONSE_NOT_SIGNED";
|
||||
case LICENSE_RESPONSE_NOT_SIGNED: *os << "LICENSE_RESPONSE_NOT_SIGNED";
|
||||
break;
|
||||
break;
|
||||
case LICENSE_RESPONSE_PARSE_ERROR_1: *os << "LICENSE_RESPONSE_PARSE_ERROR_1";
|
||||
case LICENSE_RESPONSE_PARSE_ERROR_1:
|
||||
*os << "LICENSE_RESPONSE_PARSE_ERROR_1";
|
||||
break;
|
||||
case LICENSE_RESPONSE_PARSE_ERROR_2: *os << "LICENSE_RESPONSE_PARSE_ERROR_2";
|
||||
case LICENSE_RESPONSE_PARSE_ERROR_2:
|
||||
*os << "LICENSE_RESPONSE_PARSE_ERROR_2";
|
||||
break;
|
||||
case LICENSE_RESPONSE_PARSE_ERROR_3: *os << "LICENSE_RESPONSE_PARSE_ERROR_3";
|
||||
case LICENSE_RESPONSE_PARSE_ERROR_3:
|
||||
*os << "LICENSE_RESPONSE_PARSE_ERROR_3";
|
||||
break;
|
||||
case LOAD_KEY_ERROR: *os << "LOAD_KEY_ERROR";
|
||||
break;
|
||||
@@ -211,31 +243,34 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case REFRESH_KEYS_ERROR: *os << "REFRESH_KEYS_ERROR";
|
||||
break;
|
||||
case RELEASE_ALL_USAGE_INFO_ERROR_1: *os << "RELEASE_ALL_USAGE_INFO_ERROR_1";
|
||||
case RELEASE_ALL_USAGE_INFO_ERROR_1:
|
||||
*os << "RELEASE_ALL_USAGE_INFO_ERROR_1";
|
||||
break;
|
||||
case RELEASE_ALL_USAGE_INFO_ERROR_2: *os << "RELEASE_ALL_USAGE_INFO_ERROR_2";
|
||||
case RELEASE_ALL_USAGE_INFO_ERROR_2:
|
||||
*os << "RELEASE_ALL_USAGE_INFO_ERROR_2";
|
||||
break;
|
||||
case RELEASE_KEY_ERROR: *os << "RELEASE_KEY_ERROR";
|
||||
break;
|
||||
case RELEASE_KEY_REQUEST_ERROR: *os << "RELEASE_KEY_REQUEST_ERROR";
|
||||
case RELEASE_KEY_REQUEST_ERROR: *os << "RELEASE_KEY_REQUEST_ERROR";
|
||||
break;
|
||||
case RELEASE_LICENSE_ERROR_1: *os << "RELEASE_LICENSE_ERROR_1";
|
||||
break;
|
||||
case RELEASE_LICENSE_ERROR_2: *os << "RELEASE_LICENSE_ERROR_2";
|
||||
break;
|
||||
case RELEASE_USAGE_INFO_ERROR: *os << "RELEASE_USAGE_INFO_ERROR";
|
||||
case RELEASE_USAGE_INFO_ERROR: *os << "RELEASE_USAGE_INFO_ERROR";
|
||||
break;
|
||||
case RENEW_KEY_ERROR_1: *os << "RENEW_KEY_ERROR_1";
|
||||
break;
|
||||
case RENEW_KEY_ERROR_2: *os << "RENEW_KEY_ERROR_2";
|
||||
break;
|
||||
case LICENSE_RENEWAL_SIGNING_ERROR: *os << "LICENSE_RENEWAL_SIGNING_ERROR";
|
||||
case LICENSE_RENEWAL_SIGNING_ERROR: *os << "LICENSE_RENEWAL_SIGNING_ERROR";
|
||||
break;
|
||||
case RESTORE_OFFLINE_LICENSE_ERROR_2: *os << "RESTORE_OFFLINE_LICENSE_ERROR_2";
|
||||
case RESTORE_OFFLINE_LICENSE_ERROR_2:
|
||||
*os << "RESTORE_OFFLINE_LICENSE_ERROR_2";
|
||||
break;
|
||||
case SESSION_INIT_ERROR_2: *os << "SESSION_INIT_ERROR_2";
|
||||
break;
|
||||
case SESSION_INIT_GET_KEYBOX_ERROR: *os << "SESSION_INIT_GET_KEYBOX_ERROR";
|
||||
case SESSION_INIT_GET_KEYBOX_ERROR: *os << "SESSION_INIT_GET_KEYBOX_ERROR";
|
||||
break;
|
||||
case SESSION_NOT_FOUND_1: *os << "SESSION_NOT_FOUND_1";
|
||||
break;
|
||||
@@ -257,7 +292,7 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
break;
|
||||
case SESSION_NOT_FOUND_10: *os << "SESSION_NOT_FOUND_10";
|
||||
break;
|
||||
case SESSION_NOT_FOUND_FOR_DECRYPT: *os << "SESSION_NOT_FOUND_FOR_DECRYPT";
|
||||
case SESSION_NOT_FOUND_FOR_DECRYPT: *os << "SESSION_NOT_FOUND_FOR_DECRYPT";
|
||||
break;
|
||||
case SESSION_KEYS_NOT_FOUND: *os << "SESSION_KEYS_NOT_FOUND";
|
||||
break;
|
||||
@@ -284,68 +319,134 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
|
||||
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";
|
||||
case EMPTY_PROVISIONING_CERTIFICATE_2:
|
||||
*os << "EMPTY_PROVISIONING_CERTIFICATE_2";
|
||||
break;
|
||||
case PARSE_SERVICE_CERTIFICATE_ERROR: *os << "PARSE_SERVICE_CERTIFICATE_ERROR";
|
||||
case PARSE_SERVICE_CERTIFICATE_ERROR:
|
||||
*os << "PARSE_SERVICE_CERTIFICATE_ERROR";
|
||||
break;
|
||||
case SERVICE_CERTIFICATE_TYPE_ERROR: *os << "SERVICE_CERTIFICATE_TYPE_ERROR";
|
||||
case SERVICE_CERTIFICATE_TYPE_ERROR:
|
||||
*os << "SERVICE_CERTIFICATE_TYPE_ERROR";
|
||||
break;
|
||||
case CLIENT_ID_GENERATE_RANDOM_ERROR: *os << "CLIENT_ID_GENERATE_RANDOM_ERROR";
|
||||
case CLIENT_ID_GENERATE_RANDOM_ERROR:
|
||||
*os << "CLIENT_ID_GENERATE_RANDOM_ERROR";
|
||||
break;
|
||||
case CLIENT_ID_AES_INIT_ERROR: *os << "CLIENT_ID_AES_INIT_ERROR";
|
||||
case CLIENT_ID_AES_INIT_ERROR: *os << "CLIENT_ID_AES_INIT_ERROR";
|
||||
break;
|
||||
case CLIENT_ID_AES_ENCRYPT_ERROR: *os << "CLIENT_ID_AES_ENCRYPT_ERROR";
|
||||
case CLIENT_ID_AES_ENCRYPT_ERROR: *os << "CLIENT_ID_AES_ENCRYPT_ERROR";
|
||||
break;
|
||||
case CLIENT_ID_RSA_INIT_ERROR: *os << "CLIENT_ID_RSA_INIT_ERROR";
|
||||
case CLIENT_ID_RSA_INIT_ERROR: *os << "CLIENT_ID_RSA_INIT_ERROR";
|
||||
break;
|
||||
case CLIENT_ID_RSA_ENCRYPT_ERROR: *os << "CLIENT_ID_RSA_ENCRYPT_ERROR";
|
||||
case CLIENT_ID_RSA_ENCRYPT_ERROR: *os << "CLIENT_ID_RSA_ENCRYPT_ERROR";
|
||||
break;
|
||||
case INVALID_QUERY_STATUS: *os << "INVALID_QUERY_STATUS";
|
||||
break;
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_4: *os << "LICENSE_PARSER_NOT_INITIALIZED_4";
|
||||
case LICENSE_PARSER_NOT_INITIALIZED_4:
|
||||
*os << "LICENSE_PARSER_NOT_INITIALIZED_4";
|
||||
break;
|
||||
case INVALID_PARAMETERS_LIC_3: *os << "INVALID_PARAMETERS_LIC_3";
|
||||
case INVALID_PARAMETERS_LIC_3: *os << "INVALID_PARAMETERS_LIC_3";
|
||||
break;
|
||||
case INVALID_PARAMETERS_LIC_4: *os << "INVALID_PARAMETERS_LIC_4";
|
||||
case INVALID_PARAMETERS_LIC_4: *os << "INVALID_PARAMETERS_LIC_4";
|
||||
break;
|
||||
case INVALID_PARAMETERS_LIC_6: *os << "INVALID_PARAMETERS_LIC_6";
|
||||
case INVALID_PARAMETERS_LIC_6: *os << "INVALID_PARAMETERS_LIC_6";
|
||||
break;
|
||||
case INVALID_PARAMETERS_LIC_7: *os << "INVALID_PARAMETERS_LIC_7";
|
||||
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";
|
||||
case CENC_INIT_DATA_UNAVAILABLE: *os << "CENC_INIT_DATA_UNAVAILABLE";
|
||||
break;
|
||||
case PREPARE_CENC_CONTENT_ID_FAILED: *os << "PREPARE_CENC_CONTENT_ID_FAILED";
|
||||
case PREPARE_CENC_CONTENT_ID_FAILED:
|
||||
*os << "PREPARE_CENC_CONTENT_ID_FAILED";
|
||||
break;
|
||||
case WEBM_INIT_DATA_UNAVAILABLE: *os << "WEBM_INIT_DATA_UNAVAILABLE";
|
||||
case WEBM_INIT_DATA_UNAVAILABLE: *os << "WEBM_INIT_DATA_UNAVAILABLE";
|
||||
break;
|
||||
case PREPARE_WEBM_CONTENT_ID_FAILED: *os << "PREPARE_WEBM_CONTENT_ID_FAILED";
|
||||
case PREPARE_WEBM_CONTENT_ID_FAILED:
|
||||
*os << "PREPARE_WEBM_CONTENT_ID_FAILED";
|
||||
break;
|
||||
case UNSUPPORTED_INIT_DATA_FORMAT: *os << "UNSUPPORTED_INIT_DATA_FORMAT";
|
||||
case UNSUPPORTED_INIT_DATA_FORMAT: *os << "UNSUPPORTED_INIT_DATA_FORMAT";
|
||||
break;
|
||||
case LICENSE_REQUEST_NONCE_GENERATION_ERROR: *os << "LICENSE_REQUEST_NONCE_GENERATION_ERROR";
|
||||
case LICENSE_REQUEST_NONCE_GENERATION_ERROR:
|
||||
*os << "LICENSE_REQUEST_NONCE_GENERATION_ERROR";
|
||||
break;
|
||||
case LICENSE_REQUEST_SIGNING_ERROR: *os << "LICENSE_REQUEST_SIGNING_ERROR";
|
||||
case LICENSE_REQUEST_SIGNING_ERROR: *os << "LICENSE_REQUEST_SIGNING_ERROR";
|
||||
break;
|
||||
case EMPTY_LICENSE_REQUEST: *os << "EMPTY_LICENSE_REQUEST";
|
||||
break;
|
||||
case DUPLICATE_SESSION_ID_SPECIFIED: *os << "DUPLICATE_SESSION_ID_SPECIFIED";
|
||||
case DUPLICATE_SESSION_ID_SPECIFIED:
|
||||
*os << "DUPLICATE_SESSION_ID_SPECIFIED";
|
||||
break;
|
||||
case LICENSE_RENEWAL_PROHIBITED: *os << "LICENSE_RENEWAL_PROHIBITED";
|
||||
case LICENSE_RENEWAL_PROHIBITED: *os << "LICENSE_RENEWAL_PROHIBITED";
|
||||
break;
|
||||
case SESSION_FILE_HANDLE_INIT_ERROR: *os << "SESSION_FILE_HANDLE_INIT_ERROR";
|
||||
case SESSION_FILE_HANDLE_INIT_ERROR:
|
||||
*os << "SESSION_FILE_HANDLE_INIT_ERROR";
|
||||
break;
|
||||
case INCORRECT_CRYPTO_MODE: *os << "INCORRECT_CRYPTO_MODE";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_5: *os << "INVALID_PARAMETERS_ENG_5";
|
||||
break;
|
||||
case DECRYPT_ERROR: *os << "DECRYPT_ERROR";
|
||||
break;
|
||||
case INSUFFICIENT_OUTPUT_PROTECTION:
|
||||
*os << "INSUFFICIENT_OUTPUT_PROTECTION";
|
||||
break;
|
||||
case SESSION_NOT_FOUND_12: *os << "SESSION_NOT_FOUND_12";
|
||||
break;
|
||||
case KEY_NOT_FOUND_1: *os << "KEY_NOT_FOUND_1";
|
||||
break;
|
||||
case KEY_NOT_FOUND_2: *os << "KEY_NOT_FOUND_2";
|
||||
break;
|
||||
case KEY_CONFLICT_1: *os << "KEY_CONFLICT_1";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_6: *os << "INVALID_PARAMETERS_ENG_6";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_7: *os << "INVALID_PARAMETERS_ENG_7";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_8: *os << "INVALID_PARAMETERS_ENG_8";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_9: *os << "INVALID_PARAMETERS_ENG_9";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_10: *os << "INVALID_PARAMETERS_ENG_10";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_11: *os << "INVALID_PARAMETERS_ENG_11";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_12: *os << "INVALID_PARAMETERS_ENG_12";
|
||||
break;
|
||||
case SESSION_NOT_FOUND_13: *os << "SESSION_NOT_FOUND_13";
|
||||
break;
|
||||
case SESSION_NOT_FOUND_14: *os << "SESSION_NOT_FOUND_14";
|
||||
break;
|
||||
case SESSION_NOT_FOUND_15: *os << "SESSION_NOT_FOUND_15";
|
||||
break;
|
||||
case SESSION_NOT_FOUND_16: *os << "SESSION_NOT_FOUND_16";
|
||||
break;
|
||||
case KEY_NOT_FOUND_3: *os << "KEY_NOT_FOUND_3";
|
||||
break;
|
||||
case KEY_NOT_FOUND_4: *os << "KEY_NOT_FOUND_4";
|
||||
break;
|
||||
case KEY_NOT_FOUND_5: *os << "KEY_NOT_FOUND_5";
|
||||
break;
|
||||
case KEY_NOT_FOUND_6: *os << "KEY_NOT_FOUND_6";
|
||||
break;
|
||||
case KEY_ERROR_1: *os << "KEY_ERROR_1";
|
||||
break;
|
||||
case KEY_ERROR_2: *os << "KEY_ERROR_2";
|
||||
break;
|
||||
case KEY_ERROR_3: *os << "KEY_ERROR_3";
|
||||
break;
|
||||
case KEY_ERROR_4: *os << "KEY_ERROR_4";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_13: *os << "INVALID_PARAMETERS_ENG_13";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_14: *os << "INVALID_PARAMETERS_ENG_14";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_15: *os << "INVALID_PARAMETERS_ENG_15";
|
||||
break;
|
||||
case INVALID_PARAMETERS_ENG_16: *os << "INVALID_PARAMETERS_ENG_16";
|
||||
break;
|
||||
default:
|
||||
*os << "Unknown CdmResponseType";
|
||||
*os << "Unknown CdmResponseType";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -368,7 +469,7 @@ void PrintTo(const enum CdmLicenseType& value, ::std::ostream* os) {
|
||||
|
||||
void PrintTo(const enum CdmSecurityLevel& value, ::std::ostream* os) {
|
||||
switch (value) {
|
||||
case kSecurityLevelUninitialized: *os << "kSecurityLevelUninitialized";
|
||||
case kSecurityLevelUninitialized: *os << "kSecurityLevelUninitialized";
|
||||
break;
|
||||
case kSecurityLevelL1: *os << "kSecurityLevelL1";
|
||||
break;
|
||||
@@ -391,7 +492,7 @@ void PrintTo(const enum CdmCertificateType& value, ::std::ostream* os) {
|
||||
case kCertificateX509: *os << "kCertificateX509";
|
||||
break;
|
||||
default:
|
||||
*os << "Unknown CdmCertificateType";
|
||||
*os << "Unknown CdmCertificateType";
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user