Merge "Correct request_license_test failures"

This commit is contained in:
Rahul Frias
2018-02-07 17:06:57 +00:00
committed by Android (Google) Code Review
7 changed files with 279 additions and 33 deletions

View File

@@ -10,7 +10,9 @@ class ContentKeySession : public KeySession {
public: public:
ContentKeySession(CryptoSessionId oec_session_id, ContentKeySession(CryptoSessionId oec_session_id,
metrics::CryptoMetrics* metrics) metrics::CryptoMetrics* metrics)
: KeySession(metrics), oec_session_id_(oec_session_id) {} : KeySession(metrics),
oec_session_id_(oec_session_id),
cipher_mode_(kCipherModeCtr) {}
virtual ~ContentKeySession() {} virtual ~ContentKeySession() {}
KeySessionType Type() { return kDefault; } KeySessionType Type() { return kDefault; }
@@ -32,7 +34,7 @@ class ContentKeySession : public KeySession {
CdmCipherMode* cipher_mode, CdmCipherMode* cipher_mode,
const std::string& srm_requirement); const std::string& srm_requirement);
OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>& keys) { OEMCryptoResult LoadEntitledContentKeys(const std::vector<CryptoKey>&) {
return OEMCrypto_ERROR_INVALID_CONTEXT; return OEMCrypto_ERROR_INVALID_CONTEXT;
} }
@@ -56,6 +58,7 @@ class ContentKeySession : public KeySession {
private: private:
KeyId cached_key_id_; KeyId cached_key_id_;
CdmCipherMode cipher_mode_;
}; };
} // namespace wvcdm } // namespace wvcdm

View File

@@ -29,6 +29,7 @@ void GenerateMacContext(const std::string& input_context,
void GenerateEncryptContext(const std::string& input_context, void GenerateEncryptContext(const std::string& input_context,
std::string* deriv_context); std::string* deriv_context);
size_t GetOffset(std::string message, std::string field); size_t GetOffset(std::string message, std::string field);
OEMCryptoCipherMode ToOEMCryptoCipherMode(CdmCipherMode cipher_mode);
class CryptoSession { class CryptoSession {
public: public:
@@ -272,8 +273,6 @@ class CryptoSession {
bool is_destination_buffer_type_valid_; bool is_destination_buffer_type_valid_;
SecurityLevel requested_security_level_; SecurityLevel requested_security_level_;
KeyId cached_key_id_;
bool is_usage_support_type_valid_; bool is_usage_support_type_valid_;
CdmUsageSupportType usage_support_type_; CdmUsageSupportType usage_support_type_;
UsageTableHeader* usage_table_header_; UsageTableHeader* usage_table_header_;
@@ -284,6 +283,7 @@ class CryptoSession {
static uint64_t request_id_index_; static uint64_t request_id_index_;
CdmCipherMode cipher_mode_; CdmCipherMode cipher_mode_;
uint32_t api_version_;
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoSession); CORE_DISALLOW_COPY_AND_ASSIGN(CryptoSession);
}; };

View File

@@ -74,12 +74,14 @@ OEMCryptoResult ContentKeySession::LoadKeys(
OEMCryptoResult ContentKeySession::SelectKey(const std::string& key_id, OEMCryptoResult ContentKeySession::SelectKey(const std::string& key_id,
CdmCipherMode cipher_mode) { CdmCipherMode cipher_mode) {
// Crypto session lock already locked. // Crypto session lock already locked.
if (!cached_key_id_.empty() && cached_key_id_ == key_id) { if (!cached_key_id_.empty() && cached_key_id_ == key_id &&
// Already using the desired key. cipher_mode_ == cipher_mode) {
// Already using the desired key and cipher mode.
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
} }
cached_key_id_ = key_id; cached_key_id_ = key_id;
cipher_mode_ = cipher_mode;
const uint8_t* key_id_string = const uint8_t* key_id_string =
reinterpret_cast<const uint8_t*>(cached_key_id_.data()); reinterpret_cast<const uint8_t*>(cached_key_id_.data());
@@ -87,7 +89,7 @@ OEMCryptoResult ContentKeySession::SelectKey(const std::string& key_id,
OEMCryptoResult sts; OEMCryptoResult sts;
M_TIME(sts = OEMCrypto_SelectKey( M_TIME(sts = OEMCrypto_SelectKey(
oec_session_id_, key_id_string, cached_key_id_.size(), oec_session_id_, key_id_string, cached_key_id_.size(),
static_cast<OEMCryptoCipherMode>(cipher_mode)), ToOEMCryptoCipherMode(cipher_mode)),
metrics_, oemcrypto_select_key_, sts); metrics_, oemcrypto_select_key_, sts);
if (OEMCrypto_SUCCESS != sts) { if (OEMCrypto_SUCCESS != sts) {
@@ -120,16 +122,17 @@ OEMCryptoResult ContentKeySession::LoadKeys(
const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data()); const uint8_t* msg = reinterpret_cast<const uint8_t*>(message.data());
const uint8_t* enc_mac_key = NULL; const uint8_t* enc_mac_key = NULL;
const uint8_t* enc_mac_key_iv = NULL; const uint8_t* enc_mac_key_iv = NULL;
cached_key_id_.clear();
if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) { if (mac_key.size() >= MAC_KEY_SIZE && mac_key_iv.size() >= KEY_IV_SIZE) {
enc_mac_key = msg + GetOffset(message, mac_key); enc_mac_key = msg + GetOffset(message, mac_key);
enc_mac_key_iv = msg + GetOffset(message, mac_key_iv); enc_mac_key_iv = msg + GetOffset(message, mac_key_iv);
} else { } else {
LOGV("ContentKeySession::LoadKeys: enc_mac_key not set"); LOGV("ContentKeySession::LoadKeys: enc_mac_key not set");
} }
std::vector<OEMCrypto_KeyObject> load_keys(keys.size()); std::vector<OEMCrypto_KeyObject_V13> load_keys(keys.size());
for (size_t i = 0; i < keys.size(); ++i) { for (size_t i = 0; i < keys.size(); ++i) {
const CryptoKey* ki = &keys[i]; const CryptoKey* ki = &keys[i];
OEMCrypto_KeyObject* ko = &load_keys[i]; OEMCrypto_KeyObject_V13* ko = &load_keys[i];
ko->key_id = msg + GetOffset(message, ki->key_id()); ko->key_id = msg + GetOffset(message, ki->key_id());
ko->key_id_length = ki->key_id().length(); ko->key_id_length = ki->key_id().length();
ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv()); ko->key_data_iv = msg + GetOffset(message, ki->key_data_iv());
@@ -144,6 +147,8 @@ OEMCryptoResult ContentKeySession::LoadKeys(
ko->key_control_iv = NULL; ko->key_control_iv = NULL;
ko->key_control = NULL; ko->key_control = NULL;
} }
ko->cipher_mode = ToOEMCryptoCipherMode(ki->cipher_mode());
// TODO(jfore): Is returning the cipher needed. If not drop this. // TODO(jfore): Is returning the cipher needed. If not drop this.
*cipher_mode = ki->cipher_mode(); *cipher_mode = ki->cipher_mode();
} }
@@ -162,7 +167,7 @@ OEMCryptoResult ContentKeySession::LoadKeys(
LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_); LOGV("LoadKeys: id=%ld", (uint32_t)oec_session_id_);
OEMCryptoResult sts; OEMCryptoResult sts;
M_TIME( M_TIME(
sts = OEMCrypto_LoadKeys( sts = ::OEMCrypto_LoadKeys_Back_Compat(
oec_session_id_, msg, message.size(), oec_session_id_, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst, enc_mac_key_iv, enc_mac_key, keys.size(), &load_keys[0], pst,

View File

@@ -41,6 +41,9 @@ const uint32_t kRsaSignatureLength = 256;
const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB const size_t kMaximumChunkSize = 100 * 1024; // 100 KiB
const size_t kEstimatedInitialUsageTableHeader = 40; const size_t kEstimatedInitialUsageTableHeader = 40;
const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13; const size_t kOemCryptoApiVersionSupportsBigUsageTables = 13;
// Ability to switch cipher modes in SelectKey() was introduced in this
// OEMCrypto version
const size_t kOemCryptoApiVersionSupportsSwitchingCipherMode = 14;
// Constants and utility objects relating to OEM Certificates // Constants and utility objects relating to OEM Certificates
const int kExtensionOidSize = 64; const int kExtensionOidSize = 64;
@@ -126,6 +129,11 @@ OEMCrypto_LicenseType OEMCryptoLicenseType(CdmLicenseKeyType cdm_license_type) {
: OEMCrypto_EntitlementLicense; : OEMCrypto_EntitlementLicense;
} }
OEMCryptoCipherMode ToOEMCryptoCipherMode(CdmCipherMode cipher_mode) {
return cipher_mode == kCipherModeCtr
? OEMCrypto_CipherMode_CTR : OEMCrypto_CipherMode_CBC;
}
CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics) CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
: metrics_(metrics), : metrics_(metrics),
system_id_(-1), system_id_(-1),
@@ -137,7 +145,8 @@ CryptoSession::CryptoSession(metrics::CryptoMetrics* metrics)
usage_support_type_(kUnknownUsageSupport), usage_support_type_(kUnknownUsageSupport),
usage_table_header_(NULL), usage_table_header_(NULL),
request_id_base_(0), request_id_base_(0),
cipher_mode_(kCipherModeCtr) { cipher_mode_(kCipherModeCtr),
api_version_(0) {
assert(metrics); assert(metrics);
Init(); Init();
life_span_.Start(); life_span_.Start();
@@ -664,6 +673,11 @@ CdmResponseType CryptoSession::Open(SecurityLevel requested_security_level) {
metrics_->oemcrypto_get_random_.Increment(random_sts); metrics_->oemcrypto_get_random_.Increment(random_sts);
++request_id_index_; ++request_id_index_;
if (!GetApiVersion(&api_version_)) {
LOGE("CryptoSession::Open: GetApiVersion failed");
return USAGE_SUPPORT_GET_API_FAILED;
}
CdmUsageSupportType usage_support_type; CdmUsageSupportType usage_support_type;
CdmResponseType result = GetUsageSupportType(&usage_support_type); CdmResponseType result = GetUsageSupportType(&usage_support_type);
if (result == NO_ERROR) { if (result == NO_ERROR) {
@@ -1071,8 +1085,10 @@ CdmResponseType CryptoSession::Decrypt(const CdmDecryptionParameters& params) {
sts = CopyBufferInChunks(params, buffer_descriptor); sts = CopyBufferInChunks(params, buffer_descriptor);
} }
} }
if (params.is_encrypted && params.cipher_mode != cipher_mode_) { if (api_version_ < kOemCryptoApiVersionSupportsSwitchingCipherMode) {
return INCORRECT_CRYPTO_MODE; if (params.is_encrypted && params.cipher_mode != cipher_mode_) {
return INCORRECT_CRYPTO_MODE;
}
} }
if (params.is_encrypted || sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) { if (params.is_encrypted || sts == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
OEMCrypto_CENCEncryptPatternDesc pattern_descriptor; OEMCrypto_CENCEncryptPatternDesc pattern_descriptor;
@@ -1928,14 +1944,8 @@ CdmResponseType CryptoSession::GetUsageSupportType(
return NO_ERROR; return NO_ERROR;
} }
uint32_t api_version = 0;
if (!GetApiVersion(&api_version)) {
LOGE("GetUsageSupportType: GetApiVersion failed");
return USAGE_SUPPORT_GET_API_FAILED;
}
*usage_support_type = usage_support_type_ = *usage_support_type = usage_support_type_ =
(api_version >= kOemCryptoApiVersionSupportsBigUsageTables) (api_version_ >= kOemCryptoApiVersionSupportsBigUsageTables)
? kUsageEntrySupport ? kUsageEntrySupport
: kUsageTableSupport; : kUsageTableSupport;
return NO_ERROR; return NO_ERROR;

View File

@@ -955,6 +955,8 @@ bool CdmLicense::RestoreLicenseForRelease(
if (!crypto_session_->GenerateDerivedKeys(key_request_, if (!crypto_session_->GenerateDerivedKeys(key_request_,
signed_response.session_key())) signed_response.session_key()))
return false; return false;
} else {
return KEY_ADDED == HandleKeyResponse(license_response);
} }
if (license.policy().has_renewal_server_url()) if (license.policy().has_renewal_server_url())

View File

@@ -100,7 +100,7 @@ OEMCryptoResult SubLicenseKeySession::SelectKey(const std::string& key_id,
it->second, it->second,
reinterpret_cast<const uint8_t*>(keys_[i].key_id().data()), reinterpret_cast<const uint8_t*>(keys_[i].key_id().data()),
keys_[i].key_id().size(), keys_[i].key_id().size(),
static_cast<OEMCryptoCipherMode>(cipher_mode)), ToOEMCryptoCipherMode(cipher_mode)),
metrics_, oemcrypto_select_key_, status); metrics_, oemcrypto_select_key_, status);
if (OEMCrypto_SUCCESS != status) { if (OEMCrypto_SUCCESS != status) {
return status; return status;
@@ -184,7 +184,7 @@ OEMCryptoResult SubLicenseKeySession::DoLoadKeys(
} }
for (size_t i = 0; i < keys.size(); i++) { for (size_t i = 0; i < keys.size(); i++) {
OEMCrypto_KeyObject key_object; OEMCrypto_KeyObject_V13 key_object;
const CryptoKey& key_data = keys[i]; const CryptoKey& key_data = keys[i];
key_object.key_id = msg + GetOffset(message, key_data.key_id()); key_object.key_id = msg + GetOffset(message, key_data.key_id());
key_object.key_id_length = key_data.key_id().length(); key_object.key_id_length = key_data.key_id().length();
@@ -201,6 +201,8 @@ OEMCryptoResult SubLicenseKeySession::DoLoadKeys(
key_object.key_control_iv = NULL; key_object.key_control_iv = NULL;
key_object.key_control = NULL; key_object.key_control = NULL;
} }
key_object.cipher_mode = ToOEMCryptoCipherMode(key_data.cipher_mode());
// TODO(jfore): Does returning the cipher mode serve any purpose? // TODO(jfore): Does returning the cipher mode serve any purpose?
// If not drop. // If not drop.
*cipher_mode = key_data.cipher_mode(); *cipher_mode = key_data.cipher_mode();
@@ -215,7 +217,7 @@ OEMCryptoResult SubLicenseKeySession::DoLoadKeys(
OEMCryptoResult sts; OEMCryptoResult sts;
M_TIME( M_TIME(
sts = OEMCrypto_LoadKeys( sts = OEMCrypto_LoadKeys_Back_Compat(
oec_session_id->second, msg, message.size(), oec_session_id->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), reinterpret_cast<const uint8_t*>(signature.data()),
signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object, pst, signature.size(), enc_mac_key_iv, enc_mac_key, 1, &key_object, pst,
@@ -230,7 +232,7 @@ OEMCryptoResult SubLicenseKeySession::DoLoadKeys(
oec_session_id->second, oec_session_id->second,
reinterpret_cast<const uint8_t*>(key_data.key_id().data()), reinterpret_cast<const uint8_t*>(key_data.key_id().data()),
key_data.key_id().size(), key_data.key_id().size(),
static_cast<OEMCryptoCipherMode>(key_data.cipher_mode())), ToOEMCryptoCipherMode(key_data.cipher_mode())),
metrics_, oemcrypto_select_key_, sts); metrics_, oemcrypto_select_key_, sts);
if (sts != OEMCrypto_SUCCESS) { if (sts != OEMCrypto_SUCCESS) {
@@ -312,7 +314,7 @@ OEMCryptoResult SubLicenseKeySession::DoSubLicenseLoadKeys(
return sts; return sts;
} }
OEMCrypto_KeyObject key_object; OEMCrypto_KeyObject_V13 key_object;
key_object.key_id = msg + GetOffset(message, keys_[key_index].key_id()); key_object.key_id = msg + GetOffset(message, keys_[key_index].key_id());
key_object.key_id_length = keys_[key_index].key_id().length(); key_object.key_id_length = keys_[key_index].key_id().length();
key_object.key_data_iv = key_object.key_data_iv =
@@ -325,9 +327,11 @@ OEMCryptoResult SubLicenseKeySession::DoSubLicenseLoadKeys(
key_object.key_control = key_object.key_control =
msg + GetOffset(message, keys_[key_index].key_control()); msg + GetOffset(message, keys_[key_index].key_control());
} }
key_object.cipher_mode =
ToOEMCryptoCipherMode(keys_[key_index].cipher_mode());
M_TIME( M_TIME(
sts = OEMCrypto_LoadKeys( sts = OEMCrypto_LoadKeys_Back_Compat(
it->second, msg, message.size(), it->second, msg, message.size(),
reinterpret_cast<const uint8_t*>(signature.data()), signature.size(), reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
enc_mac_key_iv, enc_mac_key, 1, &key_object, pst, enc_mac_key_iv, enc_mac_key, 1, &key_object, pst,
@@ -342,7 +346,7 @@ OEMCryptoResult SubLicenseKeySession::DoSubLicenseLoadKeys(
it->second, it->second,
reinterpret_cast<const uint8_t*>(keys_[key_index].key_id().data()), reinterpret_cast<const uint8_t*>(keys_[key_index].key_id().data()),
keys_[key_index].key_id().size(), keys_[key_index].key_id().size(),
static_cast<OEMCryptoCipherMode>(keys_[key_index].cipher_mode())), ToOEMCryptoCipherMode(keys_[key_index].cipher_mode())),
metrics_, oemcrypto_select_key_, sts); metrics_, oemcrypto_select_key_, sts);
return sts; return sts;

View File

@@ -871,6 +871,165 @@ HlsDecryptionInfo kHlsFourCCBackwardCompatibilityTestVectors[] = {
{true, 1, &kSampleAes160ByteSegmentInfo[0], kHlsPsshSampleAesFourCC}, {true, 1, &kSampleAes160ByteSegmentInfo[0], kHlsPsshSampleAesFourCC},
}; };
const std::string kFullCencPssh = wvcdm::a2bs_hex(
"00000044" // blob size
"70737368" // "pssh"
"00000000" // flags
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
"00000024" // pssh data size
"08011201321a0d7769646576696e655f" // pssh data
"74657374220a323031355f7465617273"
"2a024844");
const std::string kFullCbc1Pssh = wvcdm::a2bs_hex(
"00000053" // blob size
"70737368" // "pssh"
"00000000" // flags
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
"00000033" // pssh data size
"12103030303030303030303030303030" // pssh data
"30321a0d7769646576696e655f746573"
"74220a323031355f746561727348b1c6"
"899b06");
struct Cenc30SampleInfo {
bool is_encrypted;
wvcdm::KeyId key_id;
std::string iv;
std::string clear_data;
std::string encrypted_data;
uint8_t subsample_flags;
wvcdm::CdmCipherMode cipher_mode;
};
Cenc30SampleInfo kCenc30CencKey33Sample = {
true, wvcdm::a2bs_hex("30303030303030303030303030303033"),
wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
wvcdm::a2bs_hex(
"011E88387D58EBB8E5CDCC38D431EEF4B6094B9201F200932F8EB5E1A94FB0B977"
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC868701CB8BE038"
"15BBFFB95FD3A86F142127720A35234070799173B37219127141922CBA8CB2DC48"
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
wvcdm::a2bs_hex(
"E7C566D86E98C36D2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977"
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687B3A4AD15AD"
"A2ABBB84D8E3CBEC3E8771720A35234070799173B37219127141922CBA8CB2DC48"
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
wvcdm::kCipherModeCtr,
};
Cenc30SampleInfo kCenc30CencKey32Sample = {
true, wvcdm::a2bs_hex("30303030303030303030303030303032"),
wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
wvcdm::a2bs_hex(
"1B605E32B31D6245BCCC01C4E7720725B6094B9201F200932F8EB5E1A94FB0B977"
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687DBFDF7F684"
"3A552DCB7C38E461EDF5F3720A35234070799173B37219127141922CBA8CB2DC48"
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
wvcdm::a2bs_hex(
"E7C566D86E98C36D2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977"
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687B3A4AD15AD"
"A2ABBB84D8E3CBEC3E8771720A35234070799173B37219127141922CBA8CB2DC48"
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
wvcdm::kCipherModeCtr,
};
Cenc30SampleInfo kCenc30Cbc1Key33Sample = {
true, wvcdm::a2bs_hex("30303030303030303030303030303033"),
wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
wvcdm::a2bs_hex(
"E300F37FEB0CDD9F276E67B971FF423003F3BF21DCF6100BA453A473A4522A19A8"
"2E098AA25511011D386FC7092FE3B407DF2BEB3AD57D5E1178F041E3FCABE25193"
"3F5EE35670CEB96BA3DAF922484F9A37773EF75D4B17FACC80B475004A6229AB4C"
"DFFA426468E578DE6A0285D942CDE476E06FF907D03F382552C2E14399C3FC2D21"
"9A59819FFF837EBC88A9F83A42D37F48ED8564EB40AC3BA8A6D2634A81F04FC2F1"
"379A45869036FD72B39C88222646AB7486A8416D78AB75951EB87ED1E16DF69209"
"A6966AC93C7BB65B85E429357A732CBC75F6EFB1781859FB771D60D11EB381D9CA"
"63F793507B02207810773FCABED0240E5BEEAD30116014E481"),
wvcdm::a2bs_hex(
"E7C566D86E98C36D2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977"
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687B3A4AD15AD"
"A2ABBB84D8E3CBEC3E8771720A35234070799173B37219127141922CBA8CB2DC48"
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
wvcdm::kCipherModeCbc,
};
Cenc30SampleInfo kCenc30Cbc1Key32Sample = {
true, wvcdm::a2bs_hex("30303030303030303030303030303032"),
wvcdm::a2bs_hex("9FBE45DD47DA7EBA09A3E24CBA95C9AF"),
wvcdm::a2bs_hex(
"4392E38BAE263267ED15394DE349AD1577F37B7D906C3A61536EE5A288F66F22F2"
"F5098964B7F2860A848C3C4FD30E538B3BCD2E700DC3FBC1657A6E9EAE44DE97C4"
"6F27C82A49198EE185D92931F093C3342FDBF6CF8203E18CCDC4B88E79C95EC052"
"3FD10F9409945349169FAA8F6A37179D2BEDC04A158A09BCBF742DA05245428788"
"E972B9B465FED5849AEDDB74B8919673C0C8829B5B062A38B3146CB8D497F03A4D"
"5C0A1D463504C1F116A811EF32503695B8FF78D9E93CDF7B2F7493E8043D4DE110"
"FE1D342D1C0175BF1466A544FC0D02DD0E314098256DD65B48098323C3AED9B7E0"
"CF260DBC5A0F09A46E39AE5E26A66ABFA52CBA26FBA83975E4"),
wvcdm::a2bs_hex(
"E7C566D86E98C36D2DCA54A966E7B469B6094B9201F200932F8EB5E1A94FB0B977"
"FAB8DFDAD57C677E279615F4EAFA872CA8EFF83179E4DE2AB78E6B41A860C42203"
"4B875AC282406E03AC01F2E407A55DE38C6C35707F34B3319646FA016A01CE9056"
"E55D28C48ED72F10FA6625656ED62B758CBADA757DDC52533C9CBD54FC1A46F827"
"CC7B69BA66AE19A15D725FCBB972B23C83F95C0F00F481A7C9AC8687B3A4AD15AD"
"A2ABBB84D8E3CBEC3E8771720A35234070799173B37219127141922CBA8CB2DC48"
"EC2477832D1AE477942DCDA93C0886AF72D71E56DA3D7737E49670B024639A195B"
"7377C7F45A797C6E5DBB1BB2843DA3FC76043E33687BEF3172"),
OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample,
wvcdm::kCipherModeCbc,
};
struct Cenc30SwitchCipherInfo {
const std::string pssh;
Cenc30SampleInfo sample_info[4];
};
Cenc30SwitchCipherInfo kCenc30SwitchCipherData[8] = {
// Switch between cipher modes
{ kFullCencPssh, { kCenc30CencKey33Sample, kCenc30Cbc1Key33Sample,
kCenc30CencKey33Sample, kCenc30Cbc1Key33Sample, } },
{ kFullCbc1Pssh, { kCenc30Cbc1Key33Sample, kCenc30CencKey33Sample,
kCenc30Cbc1Key33Sample, kCenc30CencKey33Sample, } },
// Switch between cipher modes, but the first sample has a cipher mode
// that differs with the protection scheme in the pssh
{ kFullCencPssh, { kCenc30Cbc1Key33Sample, kCenc30CencKey33Sample,
kCenc30Cbc1Key33Sample, kCenc30CencKey33Sample, } },
{ kFullCbc1Pssh, { kCenc30CencKey33Sample, kCenc30Cbc1Key33Sample,
kCenc30CencKey33Sample, kCenc30Cbc1Key33Sample, } },
// Switch between cipher modes and keys
{ kFullCencPssh, { kCenc30CencKey33Sample, kCenc30CencKey32Sample,
kCenc30Cbc1Key33Sample, kCenc30Cbc1Key32Sample, } },
{ kFullCencPssh, { kCenc30Cbc1Key33Sample, kCenc30Cbc1Key32Sample,
kCenc30CencKey33Sample, kCenc30CencKey32Sample, } },
{ kFullCbc1Pssh, { kCenc30Cbc1Key33Sample, kCenc30Cbc1Key32Sample,
kCenc30CencKey33Sample, kCenc30CencKey32Sample, } },
{ kFullCbc1Pssh, { kCenc30CencKey33Sample, kCenc30CencKey32Sample,
kCenc30Cbc1Key33Sample, kCenc30Cbc1Key32Sample, } },
};
} // namespace } // namespace
namespace wvcdm { namespace wvcdm {
@@ -1055,7 +1214,6 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
// when appropriate. // when appropriate.
std::string init_data; std::string init_data;
wvcdm::CdmAppParameterMap app_parameters; wvcdm::CdmAppParameterMap app_parameters;
wvcdm::CdmKeyRequestType key_request_type;
CdmKeyRequest key_request; CdmKeyRequest key_request;
EXPECT_EQ(wvcdm::KEY_MESSAGE, EXPECT_EQ(wvcdm::KEY_MESSAGE,
decryptor_.GenerateKeyRequest( decryptor_.GenerateKeyRequest(
@@ -2496,7 +2654,6 @@ TEST_P(WvCdmUsageTest, WithClientId) {
decrypt_buffer.begin())); decrypt_buffer.begin()));
decryptor_.CloseSession(session_id_); decryptor_.CloseSession(session_id_);
uint32_t num_usage_info = 0;
CdmUsageInfo usage_info; CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg; CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = decryptor_.GetUsageInfo( CdmResponseType status = decryptor_.GetUsageInfo(
@@ -2582,7 +2739,6 @@ TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) {
decrypt_buffer.begin())); decrypt_buffer.begin()));
decryptor_.CloseSession(session_id_); decryptor_.CloseSession(session_id_);
uint32_t num_usage_info = 0;
CdmUsageInfo usage_info; CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg; CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = decryptor_.GetUsageInfo( CdmResponseType status = decryptor_.GetUsageInfo(
@@ -2680,7 +2836,6 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
decryptor_.CloseSession(session_id_); decryptor_.CloseSession(session_id_);
} }
uint32_t num_usage_info = 0;
CdmUsageInfo usage_info; CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg; CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = CdmResponseType status =
@@ -3705,6 +3860,73 @@ INSTANTIATE_TEST_CASE_P(
::testing::Range(&kHlsFourCCBackwardCompatibilityTestVectors[0], ::testing::Range(&kHlsFourCCBackwardCompatibilityTestVectors[0],
&kHlsFourCCBackwardCompatibilityTestVectors[4])); &kHlsFourCCBackwardCompatibilityTestVectors[4]));
class WvCenc30SwitchCipherModeTest
: public WvCdmRequestLicenseTest,
public ::testing::WithParamInterface<Cenc30SwitchCipherInfo*> {};
TEST_P(WvCenc30SwitchCipherModeTest, DecryptionTest) {
Provision(kLevel3);
TestWvCdmClientPropertySet client_property_set;
client_property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
std::string value;
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.QueryStatus(
kLevel3, wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION, &value));
std::istringstream ss(value);
uint32_t api_version;
ss >> api_version;
ASSERT_FALSE(ss.fail());
EXPECT_TRUE(ss.eof());
// Ability to switch between cipher modes without re-requesting a license
// was introduced in OEMCrypto v14
if (api_version < 14)
return;
Cenc30SwitchCipherInfo* info = GetParam();
TestWvCdmHlsEventListener listener;
decryptor_.OpenSession(g_key_system, &client_property_set,
kDefaultCdmIdentifier, &listener, &session_id_);
CdmAppParameterMap app_parameters;
GenerateKeyRequest(info->pssh, app_parameters,
kLicenseTypeStreaming, NULL);
VerifyKeyRequestResponse(g_license_server, g_client_auth);
CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap();
EXPECT_EQ(8u, key_status_map.size());
for (size_t i = 0; i < N_ELEM(info->sample_info); ++i) {
Cenc30SampleInfo* data = &info->sample_info[i];
std::vector<uint8_t> output_buffer(data->encrypted_data.size(), 0);
std::vector<uint8_t> iv(data->iv.begin(), data->iv.end());
CdmDecryptionParameters decryption_parameters(
&data->key_id,
reinterpret_cast<const uint8_t*>(data->encrypted_data.c_str()),
data->encrypted_data.size(), &iv, 0, &output_buffer[0]);
decryption_parameters.is_encrypted = data->is_encrypted;
decryption_parameters.is_secure = false;
decryption_parameters.cipher_mode = data->cipher_mode;
if (data->cipher_mode == kCipherModeCtr) {
decryption_parameters.pattern_descriptor.encrypt_blocks = 1;
decryption_parameters.pattern_descriptor.skip_blocks = 9;
}
decryption_parameters.subsample_flags = data->subsample_flags;
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, false,
decryption_parameters));
EXPECT_EQ(data->clear_data,
std::string(reinterpret_cast<const char*>(&output_buffer[0]),
output_buffer.size()));
}
decryptor_.CloseSession(session_id_);
}
INSTANTIATE_TEST_CASE_P(
Cdm, WvCenc30SwitchCipherModeTest,
::testing::Range(&kCenc30SwitchCipherData[0],
&kCenc30SwitchCipherData[8]));
} // namespace wvcdm } // namespace wvcdm
void show_menu(char* prog_name) { void show_menu(char* prog_name) {