Add initial support for key rotation through ce cdm interface.

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

Bug: 72168544
Test: tested as part of http://go/ag/4674759
Change-Id: I1a2d0f49371e5b3edf1d9dff85b85593f981d1f5
This commit is contained in:
Fred Gylys-Colwell
2018-07-01 17:56:23 -07:00
parent d17199fb83
commit fc4186e4fd
12 changed files with 480 additions and 332 deletions

View File

@@ -27,6 +27,10 @@ class PolicyEngine;
class CdmSession;
class CryptoKey;
using ::google::protobuf::RepeatedPtrField;
using video_widevine::License_KeyContainer;
using video_widevine::WidevinePsshData_EntitledKey;
class CdmLicense {
public:
CdmLicense(const CdmSessionId& session_id);
@@ -50,7 +54,8 @@ class CdmLicense {
const CdmKeyResponse& license_response);
virtual CdmResponseType HandleKeyUpdateResponse(
bool is_renewal, const CdmKeyResponse& license_response);
virtual CdmResponseType HandleSubLicense(const InitializationData& init_data);
virtual CdmResponseType HandleEmbeddedKeyData(
const InitializationData& init_data);
virtual bool RestoreOfflineLicense(
const CdmKeyMessage& license_request,
@@ -101,6 +106,10 @@ class CdmLicense {
const std::vector<CryptoKey>& key_array,
const video_widevine::License& license);
CdmResponseType HandleNewEntitledKeys(
const std::vector<WidevinePsshData_EntitledKey>& wrapped_keys);
CdmResponseType HandleSubLicense(const InitializationData& init_data);
template <typename T>
bool SetTypeAndId(CdmLicenseType license_type, const std::string& request_id,
T* content_id);
@@ -132,16 +141,19 @@ class CdmLicense {
// CdmLicense takes ownership of the clock.
CdmLicense(const CdmSessionId& session_id, Clock* clock);
// For sublicense key embedding. This key array will be initilized with any
// sub session keys we may have received in a license response. These keys
// may be used to support key rotation.
std::vector<CryptoKey> sub_session_key_array_;
// For entitlement key licensing. This holds the keys from the init_data.
// These keys are extracted from the pssh when we generate a license request.
// It is used to load content keys after we have received a license and
// entitelement keys. It is also used in updating the key status info.
std::vector<video_widevine::WrappedKey> wrapped_keys_;
std::vector<WidevinePsshData_EntitledKey> wrapped_keys_;
// For sublicense key embedding. This key array will be initialized with any
// sub session keys we may have received in a license response. These keys
// may be used to support key rotation.
std::vector<CryptoKey> entitlement_key_array_;
CdmLicenseKeyType license_key_type_;
RepeatedPtrField<License_KeyContainer> entitlement_keys_;
#if defined(UNIT_TEST)
friend class CdmLicenseTest;
#endif

View File

@@ -16,6 +16,8 @@ namespace wvcdm {
class LicenseKeyStatus;
using video_widevine::WidevinePsshData_EntitledKey;
// Holds all content and operator session keys for a session.
class LicenseKeys {
public:
@@ -59,8 +61,11 @@ class LicenseKeys {
// Extracts the keys from a license and makes them available for
// querying usage and constraint settings.
virtual void SetFromLicense(
const video_widevine::License& license);
virtual void SetFromLicense(const video_widevine::License& license);
// Sets the keys from the input entitled key data.
virtual void SetEntitledKeys(
const std::vector<WidevinePsshData_EntitledKey>& keys);
private:
typedef ::video_widevine::License::KeyContainer KeyContainer;
@@ -70,7 +75,12 @@ class LicenseKeys {
void Clear();
bool is_initialized_;
// |keys_| can hold either content key statuses, or entitlement key statuses.
std::map<KeyId, LicenseKeyStatus*> keys_;
// |content_keyid_to_entitlement_key_id_| maps a content key id to an
// entitlement_key_id. The resulting key id can be used to obtain the current
// key status from |keys_| when using entitlement key licensing.
std::map<KeyId, KeyId> content_keyid_to_entitlement_key_id_;
CORE_DISALLOW_COPY_AND_ASSIGN(LicenseKeys);
};
@@ -104,8 +114,8 @@ class LicenseKeyStatus {
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);
virtual void ApplyConstraints(uint32_t new_resolution,
CryptoSession::HdcpCapability new_hdcp_level);
protected:
typedef ::video_widevine::License::KeyContainer KeyContainer;
@@ -121,13 +131,10 @@ class LicenseKeyStatus {
virtual ~LicenseKeyStatus() {}
private:
void ParseContentKey(const KeyContainer& key);
void ParseOperatorSessionKey(const KeyContainer& key);
bool HasConstraints() {
return is_content_key_ && constraints_.size() != 0;
}
bool HasConstraints() { return is_content_key_ && constraints_.size() != 0; }
void SetConstraints(const ConstraintList& constraints);

View File

@@ -17,6 +17,7 @@
namespace wvcdm {
using video_widevine::LicenseIdentification;
using video_widevine::WidevinePsshData_EntitledKey;
class Clock;
class CryptoSession;
@@ -57,12 +58,18 @@ class PolicyEngine {
// permits playback.
virtual void SetLicense(const video_widevine::License& license);
// TODO(jfore): Sublicense uses this to update the keys when they are
// changed during key rotation. Drop this method and use SetLicenseKeys
// instead.
virtual void UpdateLicenseKeys(const video_widevine::License& license);
// Used to update the currently loaded entitled content keys.
virtual void SetEntitledLicenseKeys(
const std::vector<WidevinePsshData_EntitledKey>& entitled_keys);
// SetLicenseForRelease is used when releasing a license. The keys in this
// license will be ignored, and any old keys will be expired.
virtual void SetLicenseForRelease(
const video_widevine::License& license);
virtual void SetLicenseForRelease(const video_widevine::License& license);
// Call this on first decrypt to set the start of playback.
virtual void BeginDecryption(void);
@@ -73,8 +80,7 @@ class PolicyEngine {
// case an exact copy is not what we want to happen. We also will receive an
// updated license_start_time from the server. The license will transition to
// kLicenseStateCanPlay if the license permits playback.
virtual void UpdateLicense(
const video_widevine::License& license);
virtual void UpdateLicense(const video_widevine::License& license);
// Used for notifying the Policy Engine of resolution changes
virtual void NotifyResolution(uint32_t width, uint32_t height);
@@ -101,8 +107,7 @@ class PolicyEngine {
bool IsLicenseForFuture() { return license_state_ == kLicenseStatePending; }
bool HasPlaybackStarted(int64_t current_time) {
if (playback_start_time_ == 0)
return false;
if (playback_start_time_ == 0) return false;
const int64_t playback_time = current_time - playback_start_time_;
return playback_time >= policy_.play_start_grace_period_seconds();
@@ -218,6 +223,6 @@ class PolicyEngine {
CORE_DISALLOW_COPY_AND_ASSIGN(PolicyEngine);
};
} // wvcdm
} // namespace wvcdm
#endif // WVCDM_CORE_POLICY_ENGINE_H_

View File

@@ -355,18 +355,19 @@ enum CdmLicenseType {
// Like Streaming, but stricter. Does not permit storage of any kind.
// Named after the 'temporary' session type in EME, which has this behavior.
kLicenseTypeTemporary,
kLicenseTypeSubSession
// TODO(jfore): The kLicenseTypeEmbeddedKeyData currently is to differentiate
// between call types made to GenerateKeyRequest. This type is used to
// differentiate between calls to generate a license renewal and a new pssh
// with embedded keys. Please refer to CdmSession::GenerateKeyRequest. Based
// on code review comments from go/wvgerrit/41860 this license type should not
// be added. This type can be removed once it is no longer needed by
// GenerateKeyRequest.
kLicenseTypeEmbeddedKeyData
};
enum CdmLicenseKeyType {
kLicenseKeyTypeContent,
kLicenseKeyTypeEntitlement
};
enum CdmLicenseKeyType { kLicenseKeyTypeContent, kLicenseKeyTypeEntitlement };
enum SecurityLevel {
kLevelDefault,
kLevel3
};
enum SecurityLevel { kLevelDefault, kLevel3 };
enum CdmSecurityLevel {
kSecurityLevelUninitialized,
@@ -435,10 +436,10 @@ struct CdmUsageEntryInfo {
CdmKeySetId key_set_id;
std::string usage_info_file_name;
bool operator==(const CdmUsageEntryInfo& other) const {
return storage_type == other.storage_type &&
key_set_id == other.key_set_id &&
(storage_type != kStorageUsageInfo ||
usage_info_file_name == other.usage_info_file_name);
return storage_type == other.storage_type &&
key_set_id == other.key_set_id &&
(storage_type != kStorageUsageInfo ||
usage_info_file_name == other.usage_info_file_name);
}
};
@@ -454,9 +455,7 @@ enum CdmKeySecurityLevel {
class CdmKeyAllowedUsage {
public:
CdmKeyAllowedUsage() {
Clear();
}
CdmKeyAllowedUsage() { Clear(); }
bool Valid() const { return valid_; }
void SetValid() { valid_ = true; }
@@ -506,9 +505,7 @@ class CdmKeyAllowedUsage {
struct CdmCencPatternEncryptionDescriptor {
size_t encrypt_blocks; // number of 16 byte blocks to decrypt
size_t skip_blocks; // number of 16 byte blocks to leave in clear
CdmCencPatternEncryptionDescriptor()
: encrypt_blocks(0),
skip_blocks(0) {}
CdmCencPatternEncryptionDescriptor() : encrypt_blocks(0), skip_blocks(0) {}
};
struct CdmDecryptionParameters {