Implement license protocol 2.2 for OEMCrypto v19
This updates the code and tests to allow for using license protocol 2.2 when using OEMCrypto v19. Issue: 80428549 Issue: 121031064 Issue: 232464183 Change-Id: Ib6bb61f86dd310b566227462658530bca5940b88
This commit is contained in:
committed by
Robert Shih
parent
5f3bc77c52
commit
4b32cb4b10
@@ -140,6 +140,7 @@ class CdmLicense {
|
||||
bool initialized_;
|
||||
std::set<KeyId> loaded_keys_;
|
||||
std::string provider_session_token_;
|
||||
video_widevine::ProtocolVersion protocol_version_;
|
||||
bool renew_with_client_id_;
|
||||
bool is_offline_;
|
||||
|
||||
|
||||
@@ -83,6 +83,7 @@ bool ExtractExtensionValueFromCertificate(const std::string& cert,
|
||||
|
||||
std::string Md5Hash(const std::string& data);
|
||||
std::string Sha256Hash(const std::string& data);
|
||||
std::string Sha512Hash(const std::string& data);
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
|
||||
@@ -113,7 +113,8 @@ std::vector<CryptoKey> ExtractEntitlementKeys(const License& license) {
|
||||
return key_array;
|
||||
}
|
||||
|
||||
std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
std::vector<CryptoKey> ExtractContentKeys(
|
||||
const License& license, video_widevine::ProtocolVersion version) {
|
||||
std::vector<CryptoKey> key_array;
|
||||
|
||||
// Extract content key(s)
|
||||
@@ -130,21 +131,20 @@ std::vector<CryptoKey> ExtractContentKeys(const License& license) {
|
||||
// TODO(b/232464183): When we switch to License Protocol 2.2, there will
|
||||
// no longer be padding on these keys, so this
|
||||
// removal code must be removed at the same time.
|
||||
if (license.key(i).key().size() !=
|
||||
CONTENT_KEY_SIZE + LICENSE_PROTOCOL_2_1_PADDING &&
|
||||
license.key(i).key().size() !=
|
||||
MAC_KEY_SIZE + LICENSE_PROTOCOL_2_1_PADDING) {
|
||||
const auto padding = version <= video_widevine::VERSION_2_1
|
||||
? LICENSE_PROTOCOL_2_1_PADDING
|
||||
: 0;
|
||||
if (license.key(i).key().size() != CONTENT_KEY_SIZE + padding &&
|
||||
license.key(i).key().size() != MAC_KEY_SIZE + padding) {
|
||||
LOGE(
|
||||
"Skipping key %s because it is an unexpected size. Expected: %zu "
|
||||
"or %zu, Actual: %zu",
|
||||
license.key(i).id().c_str(),
|
||||
CONTENT_KEY_SIZE + LICENSE_PROTOCOL_2_1_PADDING,
|
||||
MAC_KEY_SIZE + LICENSE_PROTOCOL_2_1_PADDING,
|
||||
license.key(i).key().size());
|
||||
license.key(i).id().c_str(), CONTENT_KEY_SIZE + padding,
|
||||
MAC_KEY_SIZE + padding, license.key(i).key().size());
|
||||
continue;
|
||||
}
|
||||
const size_t length =
|
||||
license.key(i).key().size() - LICENSE_PROTOCOL_2_1_PADDING;
|
||||
license.key(i).key().size() - padding;
|
||||
key.set_key_data(license.key(i).key().substr(0, length));
|
||||
key.set_key_data_iv(license.key(i).iv());
|
||||
if (license.key(i).has_key_control()) {
|
||||
@@ -199,6 +199,7 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id)
|
||||
policy_engine_(nullptr),
|
||||
session_id_(session_id),
|
||||
initialized_(false),
|
||||
protocol_version_(video_widevine::VERSION_2_2),
|
||||
renew_with_client_id_(false),
|
||||
is_offline_(false),
|
||||
use_privacy_mode_(false),
|
||||
@@ -210,6 +211,7 @@ CdmLicense::CdmLicense(const CdmSessionId& session_id, wvutil::Clock* clock)
|
||||
policy_engine_(nullptr),
|
||||
session_id_(session_id),
|
||||
initialized_(false),
|
||||
protocol_version_(video_widevine::VERSION_2_2),
|
||||
renew_with_client_id_(false),
|
||||
is_offline_(false),
|
||||
use_privacy_mode_(false),
|
||||
@@ -244,6 +246,13 @@ bool CdmLicense::Init(bool use_privacy_mode,
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t api_version;
|
||||
if (!session->GetApiVersion(&api_version)) {
|
||||
api_version = 16;
|
||||
}
|
||||
protocol_version_ = api_version >= 19 ? video_widevine::VERSION_2_2
|
||||
: video_widevine::VERSION_2_1;
|
||||
|
||||
crypto_session_ = session;
|
||||
policy_engine_ = policy_engine;
|
||||
use_privacy_mode_ = use_privacy_mode;
|
||||
@@ -338,7 +347,7 @@ CdmResponseType CdmLicense::PrepareKeyRequest(
|
||||
return CdmResponseType(LICENSE_REQUEST_NONCE_GENERATION_ERROR);
|
||||
}
|
||||
license_request.set_key_control_nonce(license_nonce_);
|
||||
license_request.set_protocol_version(video_widevine::VERSION_2_1);
|
||||
license_request.set_protocol_version(protocol_version_);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
std::string serialized_license_req;
|
||||
@@ -494,7 +503,7 @@ CdmResponseType CdmLicense::PrepareKeyUpdateRequest(
|
||||
current_license->set_seconds_since_last_played(seconds_since_last_played);
|
||||
}
|
||||
|
||||
license_request.set_protocol_version(video_widevine::VERSION_2_1);
|
||||
license_request.set_protocol_version(protocol_version_);
|
||||
|
||||
// License request is complete. Serialize it.
|
||||
std::string serialized_license_req;
|
||||
@@ -619,7 +628,7 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
||||
CdmLicenseKeyType key_type = kLicenseKeyTypeEntitlement;
|
||||
std::vector<CryptoKey> key_array = ExtractEntitlementKeys(license);
|
||||
if (key_array.empty()) {
|
||||
key_array = ExtractContentKeys(license);
|
||||
key_array = ExtractContentKeys(license, protocol_version_);
|
||||
key_type = kLicenseKeyTypeContent;
|
||||
}
|
||||
if (key_array.empty()) {
|
||||
@@ -794,6 +803,7 @@ CdmResponseType CdmLicense::RestoreOfflineLicense(
|
||||
LOGW("Could not parse original request.");
|
||||
} else {
|
||||
license_nonce_ = original_license_request.key_control_nonce();
|
||||
protocol_version_ = original_license_request.protocol_version();
|
||||
}
|
||||
|
||||
CdmResponseType sts = HandleKeyResponse(true, license_response);
|
||||
@@ -1091,9 +1101,11 @@ CdmResponseType CdmLicense::HandleContentKeyResponse(
|
||||
LOGE("No content keys provided");
|
||||
return CdmResponseType(NO_CONTENT_KEY);
|
||||
}
|
||||
const CdmResponseType resp =
|
||||
crypto_session_->LoadLicense(key_request_, session_key, msg, core_message,
|
||||
signature, kLicenseKeyTypeContent);
|
||||
const CdmResponseType resp = crypto_session_->LoadLicense(
|
||||
protocol_version_ <= video_widevine::VERSION_2_1
|
||||
? key_request_
|
||||
: Sha512Hash(key_request_),
|
||||
session_key, msg, core_message, signature, kLicenseKeyTypeContent);
|
||||
if (KEY_ADDED == resp) {
|
||||
loaded_keys_.clear();
|
||||
for (const CryptoKey& key : key_array) {
|
||||
@@ -1113,9 +1125,11 @@ CdmResponseType CdmLicense::HandleEntitlementKeyResponse(
|
||||
LOGE("No entitlement keys provided");
|
||||
return CdmResponseType(NO_CONTENT_KEY);
|
||||
}
|
||||
const CdmResponseType resp =
|
||||
crypto_session_->LoadLicense(key_request_, session_key, msg, core_message,
|
||||
signature, kLicenseKeyTypeEntitlement);
|
||||
const CdmResponseType resp = crypto_session_->LoadLicense(
|
||||
protocol_version_ <= video_widevine::VERSION_2_1
|
||||
? key_request_
|
||||
: Sha512Hash(key_request_),
|
||||
session_key, msg, core_message, signature, kLicenseKeyTypeEntitlement);
|
||||
|
||||
if (KEY_ADDED != resp) {
|
||||
return resp;
|
||||
|
||||
@@ -417,4 +417,11 @@ std::string Sha256Hash(const std::string& data) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::string Sha512Hash(const std::string& data) {
|
||||
std::string hash(SHA512_DIGEST_LENGTH, '\0');
|
||||
SHA512(reinterpret_cast<const uint8_t*>(data.data()), data.size(),
|
||||
reinterpret_cast<uint8_t*>(&hash[0]));
|
||||
return hash;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
# include <CommonCrypto/CommonDigest.h>
|
||||
# define SHA256 CC_SHA256
|
||||
# define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
|
||||
# define SHA512 CC_SHA512
|
||||
# define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
|
||||
# define MD5 CC_MD5
|
||||
# define MD5_DIGEST_LENGTH CC_MD5_DIGEST_LENGTH
|
||||
#else
|
||||
@@ -69,4 +71,10 @@ std::string Sha256Hash(const std::string& data) {
|
||||
return hash;
|
||||
}
|
||||
|
||||
std::string Sha512Hash(const std::string& data) {
|
||||
std::string hash(SHA512_DIGEST_LENGTH, '\0');
|
||||
SHA512(data.data(), data.size(), reinterpret_cast<uint8_t*>(&hash[0]));
|
||||
return hash;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -315,7 +315,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidation) {
|
||||
// Supported certificates set by SetUp().
|
||||
EXPECT_CALL(*crypto_session_, GetSupportedCertificateTypes(NotNull()));
|
||||
EXPECT_CALL(*crypto_session_, GetApiVersion(NotNull()))
|
||||
.WillOnce(
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(crypto_session_api_version), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, GetResourceRatingTier(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(resource_rating_tier), Return(true)));
|
||||
@@ -450,7 +450,7 @@ TEST_F(CdmLicenseTest, PrepareKeyRequestValidationV15) {
|
||||
Return(CdmResponseType(NO_ERROR))));
|
||||
EXPECT_CALL(*crypto_session_, GetSupportedCertificateTypes(NotNull()));
|
||||
EXPECT_CALL(*crypto_session_, GetApiVersion(NotNull()))
|
||||
.WillOnce(
|
||||
.WillRepeatedly(
|
||||
DoAll(SetArgPointee<0>(crypto_session_api_version), Return(true)));
|
||||
EXPECT_CALL(*crypto_session_, GetResourceRatingTier(NotNull()))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(resource_rating_tier), Return(true)));
|
||||
@@ -617,7 +617,7 @@ TEST_P(CdmLicenseEntitledKeyTest, LoadsEntitledKeys) {
|
||||
|
||||
// Set up the CdmLicense with the mocks and fake entitlement key
|
||||
CreateCdmLicense();
|
||||
EXPECT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
|
||||
ASSERT_TRUE(cdm_license_->Init(true, kDefaultServiceCertificate,
|
||||
crypto_session_, policy_engine_));
|
||||
cdm_license_->set_entitlement_keys(entitlement_license);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user