From 26b888b0944ea72e1a8c29786867d02b921e92ec Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Tue, 8 Oct 2024 15:29:47 -0700 Subject: [PATCH] getOfflineLicenseKeySetIds() respects plugin security level. [ Merge of http://go/wvgerrit/208155 ] The MediaDrm plugin API getOfflineLicenseKeySetIds() was listing both L1 and L3 offline licenses. 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 list L3 only if the app had set the security level to L3. Bug: 357863269 Bug: 372105842 Test: DRM Compliance ATP via ABTD Test: libwvdrmdrmplugin_hal_test on Oriole Change-Id: I1a6e10b7eb880eef4ba36ed31b12ebfe8617f002 --- libwvdrmengine/mediadrm/include/WVDrmPlugin.h | 2 +- libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp | 24 ++++--- .../mediadrm/test/WVDrmPlugin_hal_test.cpp | 70 +++++++++++++++++++ 3 files changed, 85 insertions(+), 11 deletions(-) diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index b5e14891..4d374ac1 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -82,7 +82,7 @@ class WVDrmPlugin : public ::aidl::android::hardware::drm::BnDrmPlugin, ::ndk::ScopedAStatus getNumberOfSessions( ::aidl::android::hardware::drm::NumberOfSessions* _aidl_return) override; ::ndk::ScopedAStatus getOfflineLicenseKeySetIds( - std::vector<::aidl::android::hardware::drm::KeySetId>* _aidl_return) + std::vector<::aidl::android::hardware::drm::KeySetId>* keySetIds) override; ::ndk::ScopedAStatus getOfflineLicenseState( const ::aidl::android::hardware::drm::KeySetId& in_keySetId, diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index ed4041c5..8e72ec0e 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -965,21 +965,27 @@ Status WVDrmPlugin::unprovisionDevice() { } ::ndk::ScopedAStatus WVDrmPlugin::getOfflineLicenseKeySetIds( - vector<::aidl::android::hardware::drm::KeySetId>* _aidl_return) { - _aidl_return->clear(); + vector<::aidl::android::hardware::drm::KeySetId>* keySetIds) { + keySetIds->clear(); CdmIdentifier identifier; const auto status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); if (status != Status::OK) { return toNdkScopedAStatus(status); } - const std::vector levels = {wvcdm::kSecurityLevelL1, - wvcdm::kSecurityLevelL3}; + std::vector levelsToList; + if (mPropertySet.security_level() != wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) { + // Do not list L1 offline licenses if the DRM plugin is in + // L3-only mode. + levelsToList.push_back(wvcdm::kSecurityLevelL1); + } + // Always list L3, as "default" may imply either. + levelsToList.push_back(wvcdm::kSecurityLevelL3); std::vector allKeySetIds; CdmResponseType res(wvcdm::UNKNOWN_ERROR); bool success = false; - for (auto level : levels) { + for (const auto& level : levelsToList) { std::vector levelKeySetIds; res = mCDM->ListStoredLicenses(level, identifier, &levelKeySetIds); @@ -1004,15 +1010,13 @@ Status WVDrmPlugin::unprovisionDevice() { // Filter out key sets based on ATSC mode. const auto isAllowedKeySetId = mPropertySet.use_atsc_mode() ? IsAtscKeySetId : IsNotAtscKeySetId; - std::vector keySetIds; + keySetIds->reserve(allKeySetIds.size()); for (const CdmKeySetId& keySetId : allKeySetIds) { if (isAllowedKeySetId(keySetId)) { - keySetIds.push_back(KeySetId{StrToVector(keySetId)}); + keySetIds->push_back(KeySetId{StrToVector(keySetId)}); } } - - *_aidl_return = std::move(keySetIds); - return toNdkScopedAStatus(mapCdmResponseType(wvcdm::NO_ERROR)); + return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus WVDrmPlugin::getOfflineLicenseState( diff --git a/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp b/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp index 226fc0d4..260f7c7f 100644 --- a/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp +++ b/libwvdrmengine/mediadrm/test/WVDrmPlugin_hal_test.cpp @@ -2884,6 +2884,8 @@ TEST_F(WVDrmPluginHalTest, GetOfflineLicenseKeySetIds_NonAtscMode) { std::vector offlineKeySetIds; const auto ret = mPlugin->getOfflineLicenseKeySetIds(&offlineKeySetIds); ASSERT_TRUE(ret.isOk()); + + // Transform back into CDM types. std::vector offlineCdmKeySetIds; for (const auto &keySetId : offlineKeySetIds) { offlineCdmKeySetIds.emplace_back(keySetId.keySetId.begin(), @@ -2929,6 +2931,8 @@ TEST_F(WVDrmPluginHalTest, GetOfflineLicenseKeySetIds_AtscMode) { std::vector offlineKeySetIds; const auto ret = mPlugin->getOfflineLicenseKeySetIds(&offlineKeySetIds); ASSERT_TRUE(ret.isOk()); + + // Transform back into CDM types. std::vector offlineCdmKeySetIds; for (const auto &keySetId : offlineKeySetIds) { offlineCdmKeySetIds.emplace_back(keySetId.keySetId.begin(), @@ -2939,6 +2943,72 @@ TEST_F(WVDrmPluginHalTest, GetOfflineLicenseKeySetIds_AtscMode) { EXPECT_EQ(expectedCdmKeySetIds, offlineCdmKeySetIds); } +TEST_F(WVDrmPluginHalTest, GetOfflineLicenseKeySetIds_L1AndL3) { + const std::vector cdmKeySetIdsL1 = {"ksid1111", "ksid2222", + "ksid3333", "ksid4444"}; + const std::vector cdmKeySetIdsL3 = {"ksid5555", "ksid6666", + "ksid7777", "ksid8888"}; + // Expected key set IDs are the combination of both L1 and L3. + std::vector cdmKeySetIds = cdmKeySetIdsL1; + cdmKeySetIds.insert(cdmKeySetIds.end(), cdmKeySetIdsL3.begin(), + cdmKeySetIdsL3.end()); + + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL1, _, NotNull())) + .WillOnce(DoAll(SetArgPointee<2>(cdmKeySetIdsL1), + testing::Return(CdmResponseType(wvcdm::NO_ERROR)))); + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL3, _, NotNull())) + .WillOnce(DoAll(SetArgPointee<2>(cdmKeySetIdsL3), + testing::Return(CdmResponseType(wvcdm::NO_ERROR)))); + + // In if security level is default, then both L1 and L3 + // offline licenses should be returned. + mPlugin->setPropertyString("securityLevel", + wvcdm::QUERY_VALUE_SECURITY_LEVEL_DEFAULT); + + std::vector offlineKeySetIds; + const auto ret = mPlugin->getOfflineLicenseKeySetIds(&offlineKeySetIds); + ASSERT_TRUE(ret.isOk()); + + // Transform back into CDM types. + std::vector offlineCdmKeySetIds; + for (const auto &keySetId : offlineKeySetIds) { + offlineCdmKeySetIds.emplace_back(keySetId.keySetId.begin(), + keySetId.keySetId.end()); + } + + EXPECT_EQ(cdmKeySetIds.size(), offlineCdmKeySetIds.size()); + EXPECT_EQ(cdmKeySetIds, offlineCdmKeySetIds); +} + +TEST_F(WVDrmPluginHalTest, GetOfflineLicenseKeySetIds_L3Only) { + const std::vector cdmKeySetIdsL3 = {"ksid1111", "ksid2222", + "ksid3333", "ksid4444"}; + + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL1, _, NotNull())) + .Times(0); + EXPECT_CALL(*mCdm, ListStoredLicenses(kSecurityLevelL3, _, NotNull())) + .WillOnce(DoAll(SetArgPointee<2>(cdmKeySetIdsL3), + testing::Return(CdmResponseType(wvcdm::NO_ERROR)))); + + // After setting L3 mode, only L3 key set IDs should be returned. + mPlugin->setPropertyString("securityLevel", + wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3); + + std::vector offlineKeySetIds; + const auto ret = mPlugin->getOfflineLicenseKeySetIds(&offlineKeySetIds); + ASSERT_TRUE(ret.isOk()); + + // Transform back into CDM types. + std::vector offlineCdmKeySetIds; + for (const auto &keySetId : offlineKeySetIds) { + offlineCdmKeySetIds.emplace_back(keySetId.keySetId.begin(), + keySetId.keySetId.end()); + } + + EXPECT_EQ(cdmKeySetIdsL3.size(), offlineCdmKeySetIds.size()); + EXPECT_EQ(cdmKeySetIdsL3, offlineCdmKeySetIds); +} + TEST_F(WVDrmPluginHalTest, GetOfflineLicenseState) { EXPECT_CALL(*mCdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) .WillRepeatedly(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1),