Fix seg fault when playing WV video on Molly with the MediaShell
During session sharing, when a sample contains both clear and encrypted subsamples, subsample flags would on occasion be set incorrectly. Clear subsamples would be sent to the current session, while encrypted ones would incur a key id to session lookup and be sent to the appropriate session. The sessions would then receive decrypt calls with subsample flags incorrectly set. In order for this to work correctly all subsamples within a sample need to be sent to the same session. This requires that key ids be specified and checked if at least one of the subsamples is encrypted. If however none of the subsamples are encrypted then a valid key id may not have been provided to MediaCrypto, and the subsamples may be sent to any session. In order to support this, the CDM decrypt will now allow the caller to specify whether to validate the key Id. Then a check is added to wvcrypto determine whether to ask the CDM to validate the key ID based on the clear/encrypted states of the subsamples. The list of subsamples is already being preprocessed, so this additional check just determines if any subsamples are encrypted, and sets the validation flag appropriately. b/11967440 Merge of https://widevine-internal-review.googlesource.com/#/c/8510/3 and https://widevine-internal-review.googlesource.com/#/c/8520/2 from the widevine cdm repo. Change-Id: If65c36a31e56b69f514f0cc547a0becf0c54c40a
This commit is contained in:
@@ -79,6 +79,7 @@ class WvContentDecryptionModule {
|
||||
// iv, block_offset, decrypt_buffer, decrypt_buffer_length,
|
||||
// decrypt_buffer_offset and subsample_flags
|
||||
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
bool validate_key_id,
|
||||
const CdmDecryptionParameters& parameters);
|
||||
|
||||
// Event listener related methods
|
||||
|
||||
@@ -122,9 +122,10 @@ CdmResponseType WvContentDecryptionModule::ReleaseSecureStops(
|
||||
|
||||
CdmResponseType WvContentDecryptionModule::Decrypt(
|
||||
const CdmSessionId& session_id,
|
||||
bool validate_key_id,
|
||||
const CdmDecryptionParameters& parameters) {
|
||||
CdmSessionId id = session_id;
|
||||
if (parameters.is_encrypted &&
|
||||
if (validate_key_id &&
|
||||
Properties::GetSessionSharingId(session_id) != 0) {
|
||||
bool status = cdm_engine_->FindSessionForKey(*parameters.key_id, &id);
|
||||
if (!status) {
|
||||
|
||||
@@ -51,6 +51,7 @@ std::string kServiceCertificate =
|
||||
struct SubSampleInfo {
|
||||
bool retrieve_key;
|
||||
size_t num_of_subsamples;
|
||||
bool validate_key_id;
|
||||
bool is_encrypted;
|
||||
bool is_secure;
|
||||
wvcdm::KeyId key_id;
|
||||
@@ -61,7 +62,8 @@ struct SubSampleInfo {
|
||||
};
|
||||
|
||||
SubSampleInfo clear_sub_sample = {
|
||||
true, 1, false, false, wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||
true, 1, true, false, false,
|
||||
wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||
wvcdm::a2b_hex(
|
||||
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
||||
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
||||
@@ -83,7 +85,8 @@ SubSampleInfo clear_sub_sample = {
|
||||
wvcdm::a2b_hex("50a6c61c3f7c2b37e72b0c047000dd4a"), 0};
|
||||
|
||||
SubSampleInfo clear_sub_sample_no_key = {
|
||||
false, 1, false, false, wvcdm::a2bs_hex("77777777777777777777777777777777"),
|
||||
false, 1, false, false, false,
|
||||
wvcdm::a2bs_hex("77777777777777777777777777777777"),
|
||||
wvcdm::a2b_hex(
|
||||
"9da401105ab8da443e93e6fe089dfc69e00a9a51690d406872f338c5fa7dd3d5"
|
||||
"abf8dfd660aaff3e327850a56eedf707c03e2d1a00f9f0371e3e19ea32b13267"
|
||||
@@ -106,7 +109,8 @@ SubSampleInfo clear_sub_sample_no_key = {
|
||||
|
||||
SubSampleInfo single_encrypted_sub_sample = {
|
||||
// key 1, encrypted, 256b
|
||||
true, 1, true, false, wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||
true, 1, true, true, false,
|
||||
wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||
wvcdm::a2b_hex(
|
||||
"3b2cbde084973539329bd5656da22d20396249bf4a18a51c38c4743360cc9fea"
|
||||
"a1c78d53de1bd7e14dc5d256fd20a57178a98b83804258c239acd7aa38f2d7d2"
|
||||
@@ -129,7 +133,8 @@ SubSampleInfo single_encrypted_sub_sample = {
|
||||
|
||||
SubSampleInfo switch_key_encrypted_sub_sample[2] = {
|
||||
// block 0, key 1, encrypted, 256b
|
||||
{true, 2, true, false, wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||
{true, 2, true, true, false,
|
||||
wvcdm::a2bs_hex("E02562E04CD55351B14B3D748D36ED8E"),
|
||||
wvcdm::a2b_hex(
|
||||
"3b2cbde084973539329bd5656da22d20396249bf4a18a51c38c4743360cc9fea"
|
||||
"a1c78d53de1bd7e14dc5d256fd20a57178a98b83804258c239acd7aa38f2d7d2"
|
||||
@@ -150,7 +155,8 @@ SubSampleInfo switch_key_encrypted_sub_sample[2] = {
|
||||
"58b938c2e3ca4c2ce48942da97f9e45797f2c074ac6004734e93784a48af6160"),
|
||||
wvcdm::a2b_hex("4cca615fc013102892f91efee936639b"), 0},
|
||||
// block 1, key 3, encrypted, 256b
|
||||
{true, 2, true, false, wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||
{true, 2, true, true, false,
|
||||
wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||
wvcdm::a2b_hex(
|
||||
"337f294addb4c16d1015fd839e80314472432eda503bd0529422318bec7d2b34"
|
||||
"2b28d24b2c0bf999fd31711901a2b90e03373cb9553ffd4b2e6e655b80a39fe8"
|
||||
@@ -173,7 +179,8 @@ SubSampleInfo switch_key_encrypted_sub_sample[2] = {
|
||||
|
||||
SubSampleInfo partial_single_encrypted_sub_sample = {
|
||||
// key 3, encrypted, 125b, offset 0
|
||||
true, 1, true, false, wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||
true, 1, true, true, false,
|
||||
wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||
wvcdm::a2b_hex(
|
||||
"337f294addb4c16d1015fd839e80314472432eda503bd0529422318bec7d2b34"
|
||||
"2b28d24b2c0bf999fd31711901a2b90e03373cb9553ffd4b2e6e655b80a39fe8"
|
||||
@@ -188,7 +195,8 @@ SubSampleInfo partial_single_encrypted_sub_sample = {
|
||||
|
||||
SubSampleInfo partial_offset_single_encrypted_sub_sample = {
|
||||
// key 3, encrypted, 123b, offset 5
|
||||
true, 1, true, false, wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||
true, 1, true, true, false,
|
||||
wvcdm::a2bs_hex("0065901A64A25899A5193664ABF9AF62"),
|
||||
wvcdm::a2b_hex(
|
||||
"97f39b919ba56f3c3a51ecdcd7318bc130f054320c74db3990f925"
|
||||
"054734c03ec79ee0da68938dc4f8c2d91e46ec2342ef24f9328294a9475f7ead"
|
||||
@@ -201,6 +209,20 @@ SubSampleInfo partial_offset_single_encrypted_sub_sample = {
|
||||
"73d6c9604517b1a622b66b8f4e8414e40b00351cc9859061bde810190c7b5df8"),
|
||||
wvcdm::a2b_hex("43ba341482212c70f79d81c0f4faef8a"), 5};
|
||||
|
||||
struct SessionSharingSubSampleInfo {
|
||||
SubSampleInfo* sub_sample;
|
||||
bool session_sharing_enabled;
|
||||
};
|
||||
|
||||
SessionSharingSubSampleInfo session_sharing_sub_samples[] = {
|
||||
{ &clear_sub_sample, false },
|
||||
{ &clear_sub_sample, true },
|
||||
{ &clear_sub_sample_no_key, false },
|
||||
{ &clear_sub_sample_no_key, true },
|
||||
{ &single_encrypted_sub_sample, false },
|
||||
{ &single_encrypted_sub_sample, true }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvcdm {
|
||||
@@ -393,7 +415,7 @@ class WvCdmDecryptionTest
|
||||
|
||||
class WvCdmSessionSharingTest
|
||||
: public WvCdmRequestLicenseTest,
|
||||
public ::testing::WithParamInterface<bool> {};
|
||||
public ::testing::WithParamInterface<SessionSharingSubSampleInfo*> {};
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
@@ -542,10 +564,11 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_PrivacyModeWithServiceCertificateTest)
|
||||
}
|
||||
|
||||
TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
||||
bool enable_session_sharing = GetParam();
|
||||
SessionSharingSubSampleInfo* session_sharing_info = GetParam();
|
||||
|
||||
TestWvCdmClientPropertySet property_set;
|
||||
property_set.set_session_sharing_mode(enable_session_sharing);
|
||||
property_set.set_session_sharing_mode(
|
||||
session_sharing_info->session_sharing_enabled);
|
||||
|
||||
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||
CdmSessionId gp_session_id_1 = session_id_;
|
||||
@@ -566,7 +589,7 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
||||
GenerateKeyRequest(g_key_system, gp_key_id2, kLicenseTypeStreaming);
|
||||
VerifyKeyRequestResponse(g_license_server, gp_client_auth2, gp_key_id2, false);
|
||||
|
||||
SubSampleInfo* data = &single_encrypted_sub_sample;
|
||||
SubSampleInfo* data = session_sharing_info->sub_sample;
|
||||
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
||||
CdmDecryptionParameters decryption_parameters(&data->key_id,
|
||||
&data->encrypt_data.front(),
|
||||
@@ -577,13 +600,15 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
||||
decryption_parameters.is_encrypted = data->is_encrypted;
|
||||
decryption_parameters.is_secure = data->is_secure;
|
||||
|
||||
if (enable_session_sharing) {
|
||||
if (session_sharing_info->session_sharing_enabled || !data->is_encrypted) {
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(gp_session_id_2,
|
||||
data->validate_key_id,
|
||||
decryption_parameters));
|
||||
EXPECT_TRUE(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
||||
decrypt_buffer.begin()));
|
||||
} else {
|
||||
EXPECT_EQ(NEED_KEY, decryptor_.Decrypt(gp_session_id_2,
|
||||
data->validate_key_id,
|
||||
decryption_parameters));
|
||||
}
|
||||
|
||||
@@ -591,7 +616,10 @@ TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
||||
decryptor_.CloseSession(gp_session_id_2);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingTest, ::testing::Bool());
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
Cdm, WvCdmSessionSharingTest,
|
||||
::testing::Range(&session_sharing_sub_samples[0],
|
||||
&session_sharing_sub_samples[6]));
|
||||
|
||||
TEST_F(WvCdmRequestLicenseTest, BaseMessageTest) {
|
||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||
@@ -968,7 +996,9 @@ TEST_P(WvCdmDecryptionTest, DecryptionTest) {
|
||||
(data + i)->block_offset, &decrypt_buffer[0]);
|
||||
decryption_parameters.is_encrypted = (data + i)->is_encrypted;
|
||||
decryption_parameters.is_secure = (data + i)->is_secure;
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_, decryption_parameters));
|
||||
EXPECT_EQ(NO_ERROR, decryptor_.Decrypt(session_id_,
|
||||
(data+i)->validate_key_id,
|
||||
decryption_parameters));
|
||||
|
||||
EXPECT_TRUE(std::equal((data + i)->decrypt_data.begin(),
|
||||
(data + i)->decrypt_data.end(),
|
||||
|
||||
@@ -84,12 +84,17 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
|
||||
const uint8_t* const source = static_cast<const uint8_t*>(srcPtr);
|
||||
uint8_t* const dest = static_cast<uint8_t*>(dstPtr);
|
||||
|
||||
// Calculate the output buffer size
|
||||
// Calculate the output buffer size and determine if any subsamples are
|
||||
// encrypted.
|
||||
size_t destSize = 0;
|
||||
bool haveEncryptedSubsamples = false;
|
||||
for (size_t i = 0; i < numSubSamples; i++) {
|
||||
const SubSample &subSample = subSamples[i];
|
||||
destSize += subSample.mNumBytesOfClearData;
|
||||
destSize += subSample.mNumBytesOfEncryptedData;
|
||||
if (subSample.mNumBytesOfEncryptedData > 0) {
|
||||
haveEncryptedSubsamples = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the decrypt params that do not vary.
|
||||
@@ -147,7 +152,8 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
|
||||
params.decrypt_buffer_offset = offset;
|
||||
params.subsample_flags = clearFlags;
|
||||
|
||||
CdmResponseType res = mCDM->Decrypt(mSessionId, params);
|
||||
CdmResponseType res = mCDM->Decrypt(mSessionId, haveEncryptedSubsamples,
|
||||
params);
|
||||
|
||||
if (!isCdmResponseTypeSuccess(res)) {
|
||||
ALOGE("Decrypt error result in session %s during unencrypted block: %d",
|
||||
@@ -176,7 +182,8 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE],
|
||||
params.decrypt_buffer_offset = offset;
|
||||
params.subsample_flags = encryptedFlags;
|
||||
|
||||
CdmResponseType res = mCDM->Decrypt(mSessionId, params);
|
||||
CdmResponseType res = mCDM->Decrypt(mSessionId, haveEncryptedSubsamples,
|
||||
params);
|
||||
|
||||
if (!isCdmResponseTypeSuccess(res)) {
|
||||
ALOGE("Decrypt error result in session %s during encrypted block: %d",
|
||||
|
||||
@@ -24,7 +24,7 @@ using namespace wvdrm;
|
||||
|
||||
class MockCDM : public WvContentDecryptionModule {
|
||||
public:
|
||||
MOCK_METHOD2(Decrypt, CdmResponseType(const CdmSessionId&,
|
||||
MOCK_METHOD3(Decrypt, CdmResponseType(const CdmSessionId&, bool,
|
||||
const CdmDecryptionParameters&));
|
||||
|
||||
MOCK_METHOD2(QuerySessionStatus, CdmResponseType(const CdmSessionId&,
|
||||
@@ -186,40 +186,48 @@ TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
|
||||
// SubSample 0
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in, 16, iv[0], 0, 0,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 1
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(false, in + 16, 16, iv[1], 0, 16, 0)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 32, 16, iv[1], 0, 32, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 2
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 48, 8, iv[2], 0, 48, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 3
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(false, in + 56, 29, iv[2], 0, 56, 0)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 85, 24, iv[2], 8, 85, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 4
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 109, 60, iv[3], 0, 109, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 5
|
||||
EXPECT_CALL(cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 169, 16, iv[4], 12, 169,
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(1);
|
||||
@@ -266,10 +274,10 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
|
||||
typedef CdmDecryptionParameters CDP;
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::is_secure, false)))
|
||||
EXPECT_CALL(cdm, Decrypt(_, _, Field(&CDP::is_secure, false)))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::is_secure, true)))
|
||||
EXPECT_CALL(cdm, Decrypt(_, _, Field(&CDP::is_secure, true)))
|
||||
.Times(2);
|
||||
}
|
||||
|
||||
@@ -328,17 +336,17 @@ TEST_F(WVCryptoPluginTest, SetsFlagsForMinimumSubsampleRuns) {
|
||||
|
||||
typedef CdmDecryptionParameters CDP;
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample |
|
||||
OEMCrypto_LastSubsample)))
|
||||
EXPECT_CALL(cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample |
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
EXPECT_CALL(cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(cdm, Decrypt(_, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_LastSubsample)))
|
||||
EXPECT_CALL(cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user