Allow Secure Stops to be queried and deleted by application ID

This CL changes the WVDrmPlugin so that an application can segregate
its secure stops from those of other applications by setting an
application ID.

This CL is a merge of the following Widevine CLs:
https://widevine-internal-review.googlesource.com/#/c/11565/
Add getSecureStop by ssid

https://widevine-internal-review.googlesource.com/#/c/11572
Add getSecureStop by SSID and releaseAllSecureStops by app id.

https://widevine-internal-review.googlesource.com/#/c/11564/
Store Usage Info by App Id (device_file stubs)

https://widevine-internal-review.googlesource.com/#/c/11563/
Add application id to StoreUsageInfo.

https://widevine-internal-review.googlesource.com/#/c/11561/
Added Application ID to PropertySet for secure stop.

bug: 18053197
bug: 18076411
Change-Id: I5444baf67ba1b960dee2dc958bced8de82ab70a3
This commit is contained in:
Fred Gylys-Colwell
2014-11-05 17:39:44 -08:00
parent b3650a9661
commit 20191d996c
19 changed files with 421 additions and 54 deletions

View File

@@ -85,8 +85,13 @@ class WVDrmPlugin : public android::DrmPlugin,
virtual status_t unprovisionDevice();
virtual status_t getSecureStop(const Vector<uint8_t>& ssid,
Vector<uint8_t>& secureStop);
virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops);
virtual status_t releaseAllSecureStops();
virtual status_t releaseSecureStops(const Vector<uint8_t>& ssRelease);
virtual status_t getPropertyString(const String8& name, String8& value) const;
@@ -219,6 +224,14 @@ class WVDrmPlugin : public android::DrmPlugin,
mSessionSharingId = id;
}
virtual const std::string& app_id() const {
return mAppId;
}
void set_app_id(const std::string& appId) {
mAppId = appId;
}
private:
DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet);
@@ -227,6 +240,7 @@ class WVDrmPlugin : public android::DrmPlugin,
std::string mServiceCertificate;
bool mShareKeys;
uint32_t mSessionSharingId;
std::string mAppId;
} mPropertySet;
WvContentDecryptionModule* mCDM;

View File

@@ -23,7 +23,6 @@ namespace {
static const char* const kResetSecurityLevel = "";
static const char* const kEnable = "enable";
static const char* const kDisable = "disable";
static const std::string kPsshTag = "pssh";
}
@@ -394,9 +393,30 @@ status_t WVDrmPlugin::unprovisionDevice() {
}
}
status_t WVDrmPlugin::getSecureStop(const Vector<uint8_t>& ssid,
Vector<uint8_t>& secureStop) {
CdmUsageInfo cdmUsageInfo;
CdmSecureStopId cdmSsid(ssid.begin(), ssid.end());
CdmResponseType res = mCDM->GetUsageInfo(
mPropertySet.app_id(), cdmSsid, &cdmUsageInfo);
if (isCdmResponseTypeSuccess(res)) {
secureStop.clear();
for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin();
iter != cdmUsageInfo.end();
++iter) {
const string& cdmStop = *iter;
secureStop.appendArray(reinterpret_cast<const uint8_t*>(cdmStop.data()),
cdmStop.size());
}
}
return mapCdmResponseType(res);
}
status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
CdmUsageInfo cdmUsageInfo;
CdmResponseType res = mCDM->GetUsageInfo(&cdmUsageInfo);
CdmResponseType res =
mCDM->GetUsageInfo(mPropertySet.app_id(), &cdmUsageInfo);
if (isCdmResponseTypeSuccess(res)) {
secureStops.clear();
for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin();
@@ -414,6 +434,11 @@ status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
return mapCdmResponseType(res);
}
status_t WVDrmPlugin::releaseAllSecureStops() {
CdmResponseType res = mCDM->ReleaseAllUsageInfo(mPropertySet.app_id());
return mapCdmResponseType(res);
}
status_t WVDrmPlugin::releaseSecureStops(const Vector<uint8_t>& ssRelease) {
CdmUsageInfoReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end());
CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage);
@@ -628,6 +653,18 @@ status_t WVDrmPlugin::setPropertyString(const String8& name,
ALOGE("App tried to change key sharing while sessions are open.");
return kErrorSessionIsOpen;
}
} else if (name == "appId") {
size_t sessionCount = 0;
{
Mutex::Autolock lock(mCryptoSessionsMutex);
sessionCount = mCryptoSessions.size();
}
if (sessionCount == 0) {
mPropertySet.set_app_id(value.string());
} else {
ALOGE("App tried to set the application id while sessions are opened.");
return kErrorSessionIsOpen;
}
} else {
ALOGE("App set unknown string property %s", name.string());
return android::ERROR_DRM_CANNOT_HANDLE;

View File

@@ -12,6 +12,7 @@ LOCAL_C_INCLUDES := \
frameworks/native/include \
vendor/widevine/libwvdrmengine/cdm/core/include \
vendor/widevine/libwvdrmengine/cdm/include \
vendor/widevine/libwvdrmengine/include \
vendor/widevine/libwvdrmengine/mediadrm/include \
vendor/widevine/libwvdrmengine/oemcrypto/include \
vendor/widevine/libwvdrmengine/test/gmock/include \

View File

@@ -16,6 +16,7 @@
#include "wv_cdm_types.h"
#include "wv_content_decryption_module.h"
#include "WVDrmPlugin.h"
#include "WVErrors.h"
using namespace android;
using namespace std;
@@ -65,10 +66,17 @@ class MockCDM : public WvContentDecryptionModule {
MOCK_METHOD3(HandleProvisioningResponse,
CdmResponseType(CdmProvisioningResponse&, std::string*, std::string*));
MOCK_METHOD1(GetUsageInfo, CdmResponseType(CdmUsageInfo*));
MOCK_METHOD2(GetUsageInfo, CdmResponseType(const std::string&,
CdmUsageInfo*));
MOCK_METHOD3(GetUsageInfo, CdmResponseType(const std::string&,
const CdmSecureStopId&,
CdmUsageInfo*));
MOCK_METHOD1(Unprovision, CdmResponseType(CdmSecurityLevel));
MOCK_METHOD1(ReleaseAllUsageInfo, CdmResponseType(const std::string&));
MOCK_METHOD1(ReleaseUsageInfo,
CdmResponseType(const CdmUsageInfoReleaseMessage&));
@@ -599,6 +607,8 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
WVDrmPlugin plugin(&cdm, &crypto);
const char* app_id = "my_app_id";
plugin.setPropertyString(String8("appId"), String8(app_id));
static const uint32_t kStopSize = 53;
static const uint32_t kStopCount = 7;
@@ -614,8 +624,8 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize));
}
EXPECT_CALL(cdm, GetUsageInfo(_))
.WillOnce(DoAll(SetArgPointee<0>(cdmStops),
EXPECT_CALL(cdm, GetUsageInfo(StrEq(app_id), _))
.WillOnce(DoAll(SetArgPointee<1>(cdmStops),
Return(wvcdm::NO_ERROR)));
List<Vector<uint8_t> > stops;
@@ -637,6 +647,21 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
EXPECT_EQ(stops.end(), iter);
}
TEST_F(WVDrmPluginTest, ReleasesAllSecureStops) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
WVDrmPlugin plugin(&cdm, &crypto);
status_t res = plugin.setPropertyString(String8("appId"), String8(""));
ASSERT_EQ(OK, res);
EXPECT_CALL(cdm, ReleaseAllUsageInfo(StrEq("")))
.Times(1);
res = plugin.releaseAllSecureStops();
ASSERT_EQ(OK, res);
}
TEST_F(WVDrmPluginTest, ReleasesSecureStops) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
@@ -1309,6 +1334,59 @@ TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
EXPECT_EQ(0u, propertySet->service_certificate().size());
EXPECT_FALSE(propertySet->is_session_sharing_enabled());
EXPECT_EQ(0u, propertySet->session_sharing_id());
EXPECT_STREQ("", propertySet->app_id().c_str());
}
TEST_F(WVDrmPluginTest, CanSetAppId) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
WVDrmPlugin plugin(&cdm, &crypto);
const CdmClientPropertySet* propertySet = NULL;
// Provide expected mock behavior
{
// Provide expected behavior in response to OpenSession and store the
// property set
EXPECT_CALL(cdm, OpenSession(_, _, _))
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
SaveArg<1>(&propertySet),
Return(wvcdm::NO_ERROR)));
// Provide expected behavior when plugin requests session control info
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
.WillRepeatedly(Invoke(setSessionIdOnMap<4>));
// Let gMock know these calls will happen but we aren't interested in them.
EXPECT_CALL(cdm, AttachEventListener(_, _))
.Times(AtLeast(0));
EXPECT_CALL(cdm, DetachEventListener(_, _))
.Times(AtLeast(0));
EXPECT_CALL(cdm, CloseSession(_))
.Times(AtLeast(0));
}
status_t res;
// Test setting an empty string
res = plugin.setPropertyString(String8("appId"), String8(""));
ASSERT_EQ(OK, res);
// Test setting an application id before a session is opened.
const String8 kAppId("com.unittest.mock.app.id");
res = plugin.setPropertyString(String8("appId"), kAppId);
ASSERT_EQ(OK, res);
plugin.openSession(sessionId);
ASSERT_THAT(propertySet, NotNull());
// Verify application id is set correctly.
EXPECT_STREQ(kAppId, propertySet->app_id().c_str());
// Test setting application id while session is opened, this should fail.
res = plugin.setPropertyString(String8("appId"), kAppId);
ASSERT_EQ(kErrorSessionIsOpen, res);
}
TEST_F(WVDrmPluginTest, CanSetSecurityLevel) {