diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index 8e3ccf40..83edc51b 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -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 diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 002646a8..27d68608 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -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) { diff --git a/libwvdrmengine/cdm/test/request_license_test.cpp b/libwvdrmengine/cdm/test/request_license_test.cpp index 3c1dfb1c..d0ff5099 100644 --- a/libwvdrmengine/cdm/test/request_license_test.cpp +++ b/libwvdrmengine/cdm/test/request_license_test.cpp @@ -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 {}; + public ::testing::WithParamInterface {}; 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 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(), diff --git a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp index 812f98c8..30c7a6a0 100644 --- a/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp +++ b/libwvdrmengine/mediacrypto/src/WVCryptoPlugin.cpp @@ -84,12 +84,17 @@ ssize_t WVCryptoPlugin::decrypt(bool secure, const uint8_t key[KEY_ID_SIZE], const uint8_t* const source = static_cast(srcPtr); uint8_t* const dest = static_cast(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", diff --git a/libwvdrmengine/mediacrypto/test/WVCryptoPlugin_test.cpp b/libwvdrmengine/mediacrypto/test/WVCryptoPlugin_test.cpp index ca188926..c71b9e42 100644 --- a/libwvdrmengine/mediacrypto/test/WVCryptoPlugin_test.cpp +++ b/libwvdrmengine/mediacrypto/test/WVCryptoPlugin_test.cpp @@ -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); }