Add basic handling for entitlement keys in a license.
Merge from Widevine repo of http://go/wvgerrit/41834 Key rotation is not yet supported. The key statuses are updated from a license. The mechanism expects content keys tro come in a license. For entitlement licenses, the content keys come in the init_data. This code does not yet support the key rotation event. (A new pssh with wrapped keys is a passed to the cdm) The policy engine/key status mechanism needs to be updated to handle updated from the init_data. For now, the cdm builds a license with a key container with the content keys and used that to call PolicyEngine::SetLicense to setup the policy engine and key statuses. Bug: 64003606 Bug: 70334840 Test: In child CL Change-Id: Ibf46a18f5321cab4ff6f1778ba30527942c8021f
This commit is contained in:
committed by
Rahul Frias
parent
8251aab9f6
commit
9ae7489938
@@ -6,23 +6,23 @@
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class DefaultKeySession : public KeySession {
|
||||
class ContentKeySession : public KeySession {
|
||||
public:
|
||||
DefaultKeySession(CryptoSessionId oec_session_id,
|
||||
ContentKeySession(CryptoSessionId oec_session_id,
|
||||
metrics::CryptoMetrics* metrics)
|
||||
: KeySession(metrics), oec_session_id_(oec_session_id) {}
|
||||
virtual ~DefaultKeySession() {}
|
||||
virtual ~ContentKeySession() {}
|
||||
|
||||
KeySessionType Type() { return kDefault; }
|
||||
|
||||
// Generate Derived Keys for DefaultKeySession
|
||||
// Generate Derived Keys for ContentKeySession
|
||||
bool GenerateDerivedKeys(const std::string& message);
|
||||
|
||||
// Generate Derived Keys (from session key) for DefaultKeySession
|
||||
// Generate Derived Keys (from session key) for ContentKeySession
|
||||
bool GenerateDerivedKeys(const std::string& message,
|
||||
const std::string& session_key);
|
||||
|
||||
// Load Keys for DefaultKeySession
|
||||
// Load Keys for ContentKeySession
|
||||
OEMCryptoResult LoadKeys(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& mac_key_iv,
|
||||
@@ -32,17 +32,29 @@ class DefaultKeySession : public KeySession {
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement);
|
||||
|
||||
// Select Key for DefaultKeySession
|
||||
OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& keys) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// Select Key for ContentKeySession
|
||||
OEMCryptoResult SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode);
|
||||
|
||||
// Decrypt for DefaultKeySession
|
||||
// Decrypt for ContentKeySession
|
||||
OEMCryptoResult Decrypt(const CdmDecryptionParameters& params,
|
||||
OEMCrypto_DestBufferDesc& buffer_descriptor,
|
||||
OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor);
|
||||
|
||||
private:
|
||||
protected:
|
||||
OEMCryptoResult LoadKeys(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement, OEMCrypto_LicenseType license_type);
|
||||
CryptoSessionId oec_session_id_;
|
||||
|
||||
private:
|
||||
KeyId cached_key_id_;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ class CryptoKey {
|
||||
const std::string& key_control_iv() const { return key_control_iv_; }
|
||||
const std::string& sub_session_key_id() const {return sub_session_key_id_;}
|
||||
const std::string& sub_session_key() const {return sub_session_key_;}
|
||||
const std::string& entitlement_key_id() const {return entitlement_key_id_;}
|
||||
const std::string& track_label() const { return track_label_; }
|
||||
CdmCipherMode cipher_mode() const { return cipher_mode_; }
|
||||
void set_key_id(const std::string& key_id) { key_id_ = key_id; }
|
||||
@@ -40,6 +41,9 @@ class CryptoKey {
|
||||
void set_track_label(const std::string& track_label) {
|
||||
track_label_ = track_label;
|
||||
}
|
||||
void set_entitlement_key_id(const std::string& entitlement_key_id) {
|
||||
entitlement_key_id_ = entitlement_key_id;
|
||||
}
|
||||
|
||||
bool HasKeyControl() const { return key_control_.size() >= 16; }
|
||||
|
||||
@@ -52,6 +56,7 @@ class CryptoKey {
|
||||
std::string sub_session_key_id_;
|
||||
std::string track_label_;
|
||||
std::string sub_session_key_;
|
||||
std::string entitlement_key_id_;
|
||||
CdmCipherMode cipher_mode_;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "lock.h"
|
||||
#include "metrics_collections.h"
|
||||
#include "oemcrypto_adapter.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "scoped_ptr.h"
|
||||
#include "timer_metric.h"
|
||||
#include "wv_cdm_types.h"
|
||||
@@ -77,13 +76,15 @@ class CryptoSession {
|
||||
bool is_provisioning, std::string* signature);
|
||||
virtual bool PrepareRenewalRequest(const std::string& message,
|
||||
std::string* signature);
|
||||
virtual CdmResponseType LoadKeys(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& mac_key_iv,
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const std::string& provider_session_token,
|
||||
const std::string& srm_requirement);
|
||||
virtual CdmResponseType LoadKeys(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const std::string& provider_session_token,
|
||||
const std::string& srm_requirement,
|
||||
CdmLicenseKeyType key_type);
|
||||
virtual CdmResponseType LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& key_array);
|
||||
virtual bool LoadCertificatePrivateKey(std::string& wrapped_key);
|
||||
virtual bool RefreshKeys(const std::string& message,
|
||||
const std::string& signature, int num_keys,
|
||||
@@ -169,19 +170,17 @@ class CryptoSession {
|
||||
virtual CdmResponseType LoadUsageEntry(uint32_t entry_number,
|
||||
const CdmUsageEntry& usage_entry);
|
||||
virtual CdmResponseType UpdateUsageEntry(
|
||||
CdmUsageTableHeader* usage_table_header,
|
||||
CdmUsageEntry* usage_entry);
|
||||
CdmUsageTableHeader* usage_table_header, CdmUsageEntry* usage_entry);
|
||||
virtual CdmResponseType ShrinkUsageTableHeader(
|
||||
uint32_t new_entry_count, CdmUsageTableHeader* usage_table_header);
|
||||
virtual CdmResponseType MoveUsageEntry(uint32_t new_entry_number);
|
||||
virtual bool CreateOldUsageEntry(
|
||||
uint64_t time_since_license_received,
|
||||
uint64_t time_since_first_decrypt,
|
||||
uint64_t time_since_last_decrypt,
|
||||
UsageDurationStatus status,
|
||||
const std::string& server_mac_key,
|
||||
const std::string& client_mac_key,
|
||||
const std::string& provider_session_token);
|
||||
virtual bool CreateOldUsageEntry(uint64_t time_since_license_received,
|
||||
uint64_t time_since_first_decrypt,
|
||||
uint64_t time_since_last_decrypt,
|
||||
UsageDurationStatus status,
|
||||
const std::string& server_mac_key,
|
||||
const std::string& client_mac_key,
|
||||
const std::string& provider_session_token);
|
||||
virtual CdmResponseType CopyOldUsageEntry(
|
||||
const std::string& provider_session_token);
|
||||
virtual metrics::CryptoMetrics* GetCryptoMetrics() { return metrics_; }
|
||||
@@ -209,15 +208,19 @@ class CryptoSession {
|
||||
|
||||
bool SetDestinationBufferType();
|
||||
|
||||
bool RewrapDeviceRSAKey(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& nonce, const std::string& enc_rsa_key,
|
||||
const std::string& rsa_key_iv, std::string* wrapped_rsa_key);
|
||||
bool RewrapDeviceRSAKey(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& nonce,
|
||||
const std::string& enc_rsa_key,
|
||||
const std::string& rsa_key_iv,
|
||||
std::string* wrapped_rsa_key);
|
||||
|
||||
bool RewrapDeviceRSAKey30(
|
||||
const std::string& message, const std::string& nonce,
|
||||
const std::string& private_key, const std::string& iv,
|
||||
const std::string& wrapping_key, std::string* wrapped_private_key);
|
||||
bool RewrapDeviceRSAKey30(const std::string& message,
|
||||
const std::string& nonce,
|
||||
const std::string& private_key,
|
||||
const std::string& iv,
|
||||
const std::string& wrapping_key,
|
||||
std::string* wrapped_private_key);
|
||||
|
||||
CdmResponseType SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode);
|
||||
|
||||
34
libwvdrmengine/cdm/core/include/entitlement_key_session.h
Normal file
34
libwvdrmengine/cdm/core/include/entitlement_key_session.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_
|
||||
#define WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_
|
||||
|
||||
#include "content_key_session.h"
|
||||
#include "key_session.h"
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class EntitlementKeySession : public ContentKeySession {
|
||||
public:
|
||||
EntitlementKeySession(CryptoSessionId oec_session_id,
|
||||
metrics::CryptoMetrics* metrics);
|
||||
virtual ~EntitlementKeySession() {}
|
||||
|
||||
KeySessionType Type() { return kEntitlement; }
|
||||
|
||||
// Load Keys for ContentKeySession
|
||||
OEMCryptoResult LoadKeys(const std::string& message,
|
||||
const std::string& signature,
|
||||
const std::string& mac_key_iv,
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement);
|
||||
OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& keys);
|
||||
|
||||
private:
|
||||
std::vector<CryptoKey> keys_;
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WVCDM_CORE_ENTITLEMENT_KEY_SESSSION_H_
|
||||
@@ -28,8 +28,10 @@ class InitializationData {
|
||||
const CdmInitData& data() const { return data_; }
|
||||
std::vector<uint8_t> hls_iv() const { return hls_iv_; }
|
||||
CdmHlsMethod hls_method() const { return hls_method_; }
|
||||
std::vector<video_widevine::SubLicense> ExtractEmbeddedKeys() const;
|
||||
const std::string ExtractGroupMasterKeyId() const;
|
||||
// TODO(jfore): Perhaps this should be a generic structure with the ids for
|
||||
// any type of licensing?
|
||||
std::vector<video_widevine::SubLicense> ExtractSublicenseKeys() const;
|
||||
std::vector<video_widevine::WrappedKey> ExtractWrappedKeys() const;
|
||||
|
||||
private:
|
||||
// Parse a blob of multiple concatenated PSSH atoms to extract the first
|
||||
|
||||
@@ -12,7 +12,7 @@ class KeySession {
|
||||
KeySession(metrics::CryptoMetrics* metrics) : metrics_(metrics) {}
|
||||
|
||||
public:
|
||||
typedef enum { kDefault, kSubLicense } KeySessionType;
|
||||
typedef enum { kDefault, kSubLicense, kEntitlement } KeySessionType;
|
||||
virtual ~KeySession() {}
|
||||
virtual KeySessionType Type() = 0;
|
||||
virtual bool GenerateDerivedKeys(const std::string& message) = 0;
|
||||
@@ -26,6 +26,8 @@ class KeySession {
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement) = 0;
|
||||
virtual OEMCryptoResult LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& keys) = 0;
|
||||
virtual OEMCryptoResult SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) = 0;
|
||||
virtual OEMCryptoResult Decrypt(
|
||||
|
||||
@@ -29,11 +29,11 @@ class CdmLicense {
|
||||
CdmLicense(const CdmSessionId& session_id);
|
||||
virtual ~CdmLicense();
|
||||
|
||||
virtual bool Init(
|
||||
const std::string& client_token, CdmClientTokenType client_token_type,
|
||||
const std::string& device_id, bool use_privacy_mode,
|
||||
const std::string& signed_service_certificate, CryptoSession* session,
|
||||
PolicyEngine* policy_engine);
|
||||
virtual bool Init(const std::string& client_token,
|
||||
CdmClientTokenType client_token_type,
|
||||
const std::string& device_id, bool use_privacy_mode,
|
||||
const std::string& signed_service_certificate,
|
||||
CryptoSession* session, PolicyEngine* policy_engine);
|
||||
|
||||
virtual CdmResponseType PrepareKeyRequest(
|
||||
const InitializationData& init_data, CdmLicenseType license_type,
|
||||
@@ -64,16 +64,13 @@ class CdmLicense {
|
||||
return provider_session_token_;
|
||||
}
|
||||
|
||||
virtual bool is_offline() {
|
||||
return is_offline_;
|
||||
}
|
||||
virtual bool is_offline() { return is_offline_; }
|
||||
|
||||
static bool ExtractProviderSessionToken(
|
||||
const CdmKeyResponse& license_response,
|
||||
std::string* provider_session_token);
|
||||
|
||||
private:
|
||||
|
||||
CdmResponseType HandleKeyErrorResponse(
|
||||
const video_widevine::SignedMessage& signed_message);
|
||||
|
||||
@@ -86,9 +83,24 @@ class CdmLicense {
|
||||
const std::string& request_id,
|
||||
video_widevine::LicenseRequest* license_request);
|
||||
|
||||
CdmResponseType HandleContentKeyResponse(
|
||||
const std::string& msg, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const video_widevine::License& license);
|
||||
|
||||
// HandleEntitlementKeyResponse loads the entitlement keys in |key_array| into
|
||||
// the crypto session. In addition, it also extracts content keys from
|
||||
// |wrapped_keys_| and loads them for use.
|
||||
CdmResponseType HandleEntitlementKeyResponse(
|
||||
const std::string& msg, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& key_array,
|
||||
const video_widevine::License& license);
|
||||
|
||||
template <typename T>
|
||||
bool SetTypeAndId(CdmLicenseType license_type,
|
||||
const std::string& request_id, T* content_id);
|
||||
bool SetTypeAndId(CdmLicenseType license_type, const std::string& request_id,
|
||||
T* content_id);
|
||||
|
||||
CryptoSession* crypto_session_;
|
||||
PolicyEngine* policy_engine_;
|
||||
@@ -121,6 +133,12 @@ class CdmLicense {
|
||||
// sub session keys we may have received in a license response. These keys
|
||||
// may be used to support key rotation.
|
||||
std::vector<CryptoKey> sub_session_key_array_;
|
||||
|
||||
// For entitlement key licensing. This holds the keys from the init_data.
|
||||
// These keys are extracted from the pssh when we generate a license request.
|
||||
// It is used to load content keys after we have received a license and
|
||||
// entitelement keys. It is also used in updating the key status info.
|
||||
std::vector<video_widevine::WrappedKey> wrapped_keys_;
|
||||
#if defined(UNIT_TEST)
|
||||
friend class CdmLicenseTest;
|
||||
#endif
|
||||
|
||||
@@ -18,7 +18,7 @@ class SubLicenseKeySession : public KeySession {
|
||||
metrics::CryptoMetrics* metrics,
|
||||
const std::string& wrapped_private_device_key,
|
||||
SecurityLevel requested_security_level,
|
||||
const std::string& group_master_key_id);
|
||||
const std::string& group_id);
|
||||
|
||||
virtual ~SubLicenseKeySession();
|
||||
|
||||
@@ -43,6 +43,10 @@ class SubLicenseKeySession : public KeySession {
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement);
|
||||
|
||||
OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& keys) {
|
||||
return OEMCrypto_ERROR_INVALID_CONTEXT;
|
||||
}
|
||||
|
||||
// Each oemcrypto session contains a single key. Find the right sub session
|
||||
// and save it's id as the selected oemcrypto session.
|
||||
OEMCryptoResult SelectKey(const std::string& key_id,
|
||||
@@ -83,7 +87,7 @@ class SubLicenseKeySession : public KeySession {
|
||||
std::vector<CryptoKey> keys_;
|
||||
SubLicenseSessionMap& sub_license_oec_sessions_;
|
||||
SecurityLevel requested_security_level_;
|
||||
KeyId group_master_key_id_;
|
||||
KeyId group_id_;
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -345,6 +345,11 @@ enum CdmLicenseType {
|
||||
kLicenseTypeSubSession
|
||||
};
|
||||
|
||||
enum CdmLicenseKeyType {
|
||||
kLicenseKeyTypeContent,
|
||||
kLicenseKeyTypeEntitlement
|
||||
};
|
||||
|
||||
enum SecurityLevel {
|
||||
kLevelDefault,
|
||||
kLevel3
|
||||
|
||||
Reference in New Issue
Block a user