Do not convert the protection scheme to network byte order

[ Merge of http://go/wvgerrit/19960 ]

Protections schemes are specified using a 4CC code {"cbc1", "cbcs",
"cenc", "cens"}. A host to network conversion was performed when the
PSSH was created and inserted into the license request. A reverse
conversion was performed when the code was extracted from the
license response.

These conversions are problematic if the PSSH is created externally and
passed into mediaDrm. To address this, the conversions have been removed
and allow protobuf to handle byte ordering. For backward compatibility
we allow codes in either ordering.

b/30713238

Change-Id: I25f01ecc621549fd3c13b443e4c8b89168463249
This commit is contained in:
Rahul Frias
2016-08-10 15:44:50 -07:00
parent eeb6606784
commit 6a206191f0
4 changed files with 131 additions and 8 deletions

View File

@@ -476,9 +476,9 @@ bool InitializationData::ConstructWidevineInitData(
cenc_header.set_provider(provider);
cenc_header.set_content_id(content_id);
if (method == kHlsMethodAes128)
cenc_header.set_protection_scheme(htonl(kFourCcCbc1));
cenc_header.set_protection_scheme(kFourCcCbc1);
else
cenc_header.set_protection_scheme(htonl(kFourCcCbcs));
cenc_header.set_protection_scheme(kFourCcCbcs);
cenc_header.SerializeToString(init_data_proto);
return true;
}

View File

@@ -65,6 +65,8 @@ const unsigned char kServiceCertificateCAPublicKey[] = {
}
const uint32_t kFourCcCbc1 = 0x63626331;
const uint32_t kFourCcCbcs = 0x63626373;
const uint32_t kFourCcLittleEndianCbc1 = 0x31636263;
const uint32_t kFourCcLittleEndianCbcs = 0x73636263;
const uint32_t kFourCcCenc = 0x63656e63;
const uint32_t kFourCcCens = 0x63656e73;
@@ -115,12 +117,23 @@ static std::vector<CryptoKey> ExtractContentKeys(const License& license) {
}
uint32_t four_cc = kFourCcCenc;
if (license.has_protection_scheme()) {
four_cc = ntohl(license.protection_scheme());
four_cc = license.protection_scheme();
}
switch (four_cc) {
// b/30713238: Android N assumed that the "protection scheme" Four
// CC code, after being extracted from the protobuf, was host byte
// order dependent. Later versions do not assume this, and thus,
// for backwards compatibility, must support both byte orders.
case kFourCcCbc1:
case kFourCcCbcs:
case kFourCcLittleEndianCbc1:
case kFourCcLittleEndianCbcs:
key.set_cipher_mode(kCipherModeCbc);
break;
default:
key.set_cipher_mode(kCipherModeCtr);
break;
}
if (four_cc == kFourCcCbc1 || four_cc == kFourCcCbcs)
key.set_cipher_mode(kCipherModeCbc);
else
key.set_cipher_mode(kCipherModeCtr);
key_array.push_back(key);
break;
}

View File

@@ -624,7 +624,7 @@ TEST_P(HlsConstructionTest, InitData) {
case kHlsMethodSampleAes: protection_scheme = kFourCcCbcs; break;
default: break;
}
EXPECT_EQ(protection_scheme, ntohl(cenc_header.protection_scheme()));
EXPECT_EQ(protection_scheme, cenc_header.protection_scheme());
}
}

View File

@@ -755,6 +755,62 @@ HlsDecryptionInfo kHlsDecryptionTestVectors[] = {
{true, 1, &kSampleAes192ByteSegmentInfo[0], kAttributeListSampleAes},
{true, 1, &kSampleAes338ByteSegmentInfo[0], kAttributeListSampleAes},
};
const std::string kHlsPsshAes128LittleEndianFourCC = wvcdm::a2bs_hex(
"00000060" // blob size
"70737368" // "pssh"
"00000000" // flags
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
"00000040" // pssh data size
// pssh data:
"08011210AB6531FF6E6EA15E387B019E"
"59C2DE0A1A0D7769646576696E655F74"
"6573742215686C735F6165735F313238"
"5F73747265616D696E6748E3C48D8B03");
const std::string kHlsPsshSampleAesLittleEndianFourCC = wvcdm::a2bs_hex(
"00000063" // blob size
"70737368" // "pssh"
"00000000" // flags
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
"00000043" // pssh data size
// pssh data:
"08011210613DB35603320EB8E7EA24BD"
"EEA3FDB81A0D7769646576696E655F74"
"6573742218686C735F73616D706C655F"
"6165735F73747265616D696E6748E3C4"
"8D9B07");
const std::string kHlsPsshAes128FourCC = wvcdm::a2bs_hex(
"00000060" // blob size
"70737368" // "pssh"
"00000000" // flags
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
"00000040" // pssh data size
// pssh data:
"08011210AB6531FF6E6EA15E387B019E"
"59C2DE0A1A0D7769646576696E655F74"
"6573742215686C735F6165735F313238"
"5F73747265616D696E6748B1C6899B06");
const std::string kHlsPsshSampleAesFourCC = wvcdm::a2bs_hex(
"00000063" // blob size
"70737368" // "pssh"
"00000000" // flags
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
"00000043" // pssh data size
// pssh data:
"08011210613DB35603320EB8E7EA24BD"
"EEA3FDB81A0D7769646576696E655F74"
"6573742218686C735F73616D706C655F"
"6165735F73747265616D696E6748F3C6"
"899B06");
HlsDecryptionInfo kHlsFourCCBackwardCompatibilityTestVectors[] = {
{false, 2, &kAes128MultiSegmentInfo[0], kHlsPsshAes128LittleEndianFourCC},
{true, 1, &kSampleAes160ByteSegmentInfo[0],
kHlsPsshSampleAesLittleEndianFourCC},
{false, 2, &kAes128MultiSegmentInfo[0], kHlsPsshAes128FourCC},
{true, 1, &kSampleAes160ByteSegmentInfo[0], kHlsPsshSampleAesFourCC},
};
} // namespace
namespace wvcdm {
@@ -3313,6 +3369,60 @@ INSTANTIATE_TEST_CASE_P(Cdm, WvHlsDecryptionTest,
::testing::Range(&kHlsDecryptionTestVectors[0],
&kHlsDecryptionTestVectors[11]));
class WvHlsFourCCBackwardCompatibilityTest
: public WvCdmRequestLicenseTest,
public ::testing::WithParamInterface<HlsDecryptionInfo*> {};
TEST_P(WvHlsFourCCBackwardCompatibilityTest, HlsDecryptionTest) {
Provision(kLevel3);
TestWvCdmClientPropertySet client_property_set;
client_property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
HlsDecryptionInfo* info = GetParam();
TestWvCdmHlsEventListener listener;
decryptor_.OpenSession(g_key_system, &client_property_set, EMPTY_ORIGIN,
&listener, &session_id_);
CdmAppParameterMap app_parameters;
GenerateKeyRequest(wvcdm::KEY_MESSAGE, ISO_BMFF_VIDEO_MIME_TYPE,
info->attribute_list, app_parameters,
kLicenseTypeStreaming, NULL);
//TODO(rfrias): Remove once we switch to git-on-borg
std::string license_server = "https://proxy.uat.widevine.com/proxy";
VerifyKeyRequestResponse(license_server, g_client_auth, false);
CdmKeyStatusMap key_status_map = listener.GetKeyStatusMap();
EXPECT_EQ(1u, key_status_map.size());
KeyId key_id = key_status_map.begin()->first;
EXPECT_EQ(KEY_ID_SIZE, key_id.size());
for (size_t i = 0; i < info->number_of_segments; ++i) {
HlsSegmentInfo* data = info->segment_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(
&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 = true;
decryption_parameters.is_secure = false;
decryption_parameters.cipher_mode = kCipherModeCbc;
if (info->sample_aes) {
decryption_parameters.pattern_descriptor.encrypt_blocks = 1;
decryption_parameters.pattern_descriptor.skip_blocks = 9;
}
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, WvHlsFourCCBackwardCompatibilityTest,
::testing::Range(&kHlsFourCCBackwardCompatibilityTestVectors[0],
&kHlsFourCCBackwardCompatibilityTestVectors[4]));
} // namespace wvcdm
void show_menu(char* prog_name) {