From 0aa6aad1af5dcfaed03895c26bcfd08ab8782d1c Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Tue, 8 Oct 2024 15:36:39 -0700 Subject: [PATCH] removeOfflineLicense() respects plugin security level. [ Merge of http://go/wvgerrit/208116 ] The MediaDrm plugin API removeOfflineLicense() would check both L1 and L3 for the offline license. While this is generally acceptable, apps might force set L3 via the setStringProperty(), which should cause the DRM plugin to behave as if it is L3 only. This change will cause the WVDrmPlugin only remove L3 key set IDs while in L3 mode. L1 key set IDs in this case will be treated as non-existing. Bug: 357863269 Bug: 372105842 Test: DRM Compliance ATP via ABTD Test: libwvdrmdrmplugin_hal_test on Oriole Change-Id: I81dddbacaee28da6c0a94527b0e390e86f55f81f --- libwvdrmengine/mediadrm/include/WVDrmPlugin.h | 3 +- libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp | 21 ++++--- .../mediadrm/test/WVDrmPlugin_hal_test.cpp | 56 +++++++++++++++++++ 3 files changed, 72 insertions(+), 8 deletions(-) diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 4d374ac1..63a428d4 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -134,7 +134,8 @@ class WVDrmPlugin : public ::aidl::android::hardware::drm::BnDrmPlugin, ::ndk::ScopedAStatus removeKeys( const std::vector& in_sessionId) override; ::ndk::ScopedAStatus removeOfflineLicense( - const ::aidl::android::hardware::drm::KeySetId& in_keySetId) override; + const ::aidl::android::hardware::drm::KeySetId& in_keySetIdPackage) + override; ::ndk::ScopedAStatus removeSecureStop( const ::aidl::android::hardware::drm::SecureStopId& in_secureStopId) override; diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index 8e72ec0e..e222128d 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -1071,8 +1071,9 @@ Status WVDrmPlugin::unprovisionDevice() { } ::ndk::ScopedAStatus WVDrmPlugin::removeOfflineLicense( - const ::aidl::android::hardware::drm::KeySetId& in_keySetId) { - if (in_keySetId.keySetId.empty()) { + const ::aidl::android::hardware::drm::KeySetId& keySetIdPackage) { + const auto& keySetId = keySetIdPackage.keySetId; + if (keySetId.empty()) { return toNdkScopedAStatus(Status::BAD_VALUE); } @@ -1082,12 +1083,18 @@ Status WVDrmPlugin::unprovisionDevice() { return toNdkScopedAStatus(status); } - const std::vector levels = {wvcdm::kSecurityLevelL1, - wvcdm::kSecurityLevelL3}; - const CdmKeySetId cdmKeySetId(in_keySetId.keySetId.begin(), - in_keySetId.keySetId.end()); + std::vector levelsToCheck; + if (mPropertySet.security_level() != wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) { + // Do not attempt to remove an L1 offline licenses if the DRM plugin + // is in L3-only mode. + levelsToCheck.push_back(wvcdm::kSecurityLevelL1); + } + // Always check L3, as "default" may imply either. + levelsToCheck.push_back(wvcdm::kSecurityLevelL3); - for (const CdmSecurityLevel level : levels) { + const CdmKeySetId cdmKeySetId(keySetId.begin(), keySetId.end()); + + for (const CdmSecurityLevel level : levelsToCheck) { std::vector keySetIds; const CdmResponseType res = mCDM->ListStoredLicenses(level, identifier, &keySetIds); diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp index 260f7c7f..0e55641a 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp @@ -3115,6 +3115,62 @@ TEST_F(WVDrmPluginHalTest, RemoveOfflineLicense_NotFound) { ASSERT_FALSE(status.isOk()); } +TEST_F(WVDrmPluginHalTest, RemoveOfflineLicense_L3_OnlyMode) { + // Key set to remove. + const CdmKeySetId cdmKeySetId = "ksidDEADBEAF"; + const KeySetId keySetId{ + std::vector(cdmKeySetId.begin(), cdmKeySetId.end())}; + + // Desired key set ID is found in L3. + const std::vector cdmKeySetIdsL3 = { + "ksidDEADC0DE", "ksid1337", cdmKeySetId, "ksidBAD", "ksidCAFEB0BA"}; + + // In L3 mode, there should be no call to L1. + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL1, _, _)).Times(0); + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL3, _, NotNull())) + .WillOnce(DoAll(SetArgPointee<2>(cdmKeySetIdsL3), + testing::Return(CdmResponseType(wvcdm::NO_ERROR)))); + + // Only call L3. + EXPECT_CALL(*mCdm, RemoveOfflineLicense(_, kSecurityLevelL1, _)).Times(0); + EXPECT_CALL(*mCdm, RemoveOfflineLicense(cdmKeySetId, kSecurityLevelL3, _)) + .WillOnce(testing::Return(CdmResponseType(wvcdm::NO_ERROR))); + + // After setting L3 mode, only L3 should be checked for removal. + mPlugin->setPropertyString("securityLevel", + wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3); + + const auto status = mPlugin->removeOfflineLicense(keySetId); + ASSERT_TRUE(status.isOk()); +} + +TEST_F(WVDrmPluginHalTest, RemoveOfflineLicense_L3_OnlyMode_NotFound) { + // Key set to remove. + const CdmKeySetId cdmKeySetId = "ksidDEADBEAF"; + const KeySetId keySetId{ + std::vector(cdmKeySetId.begin(), cdmKeySetId.end())}; + + // Desired key set ID is not found in L3. + const std::vector cdmKeySetIdsL3 = {"ksidDEADC0DE", "ksid1337", + "ksidBAD", "ksidCAFEB0BA"}; + + // In L3 mode, there should be no call to L1. + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL1, _, _)).Times(0); + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL3, _, NotNull())) + .WillOnce(DoAll(SetArgPointee<2>(cdmKeySetIdsL3), + testing::Return(CdmResponseType(wvcdm::NO_ERROR)))); + + // No call to RemoveOfflineLicense should be made. + EXPECT_CALL(*mCdm, RemoveOfflineLicense(_, _, _)).Times(0); + + // After setting L3 mode, only L3 should be checked for removal. + mPlugin->setPropertyString("securityLevel", + wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3); + + const auto status = mPlugin->removeOfflineLicense(keySetId); + ASSERT_FALSE(status.isOk()); +} + TEST_F(WVDrmPluginHalTest, CanStoreAtscLicense) { android::sp> cdm = new StrictMock(); StrictMock crypto;