Allow Unprovisioning of Origins
(This is a merge of http://go/wvgerrit/14051) Adds support for passing a special provisioning response ("delete") to the provisioning API in order to unprovision the current origin. Note that the origin MUST be set or else this will fail. The existing, system-only unprovisionDevice() method is unaffected. Bug: 12247651 Change-Id: I16d296397d8e9e73c8f43e36c86838873318a398
This commit is contained in:
@@ -20,7 +20,8 @@ enum {
|
|||||||
kErrorSessionIsOpen = ERROR_DRM_VENDOR_MIN + 4,
|
kErrorSessionIsOpen = ERROR_DRM_VENDOR_MIN + 4,
|
||||||
kErrorTooManySessions = ERROR_DRM_VENDOR_MIN + 5,
|
kErrorTooManySessions = ERROR_DRM_VENDOR_MIN + 5,
|
||||||
kErrorInvalidKey = ERROR_DRM_VENDOR_MIN + 6,
|
kErrorInvalidKey = ERROR_DRM_VENDOR_MIN + 6,
|
||||||
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 6,
|
kErrorNoOriginSpecified = ERROR_DRM_VENDOR_MIN + 7,
|
||||||
|
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 7,
|
||||||
|
|
||||||
// Used by crypto test mode
|
// Used by crypto test mode
|
||||||
kErrorTestMode = ERROR_DRM_VENDOR_MAX,
|
kErrorTestMode = ERROR_DRM_VENDOR_MAX,
|
||||||
|
|||||||
@@ -276,6 +276,8 @@ class WVDrmPlugin : public android::DrmPlugin,
|
|||||||
|
|
||||||
bool InitDataResemblesPSSH(const Vector<uint8_t>& initData);
|
bool InitDataResemblesPSSH(const Vector<uint8_t>& initData);
|
||||||
|
|
||||||
|
status_t unprovision(const std::string& origin);
|
||||||
|
|
||||||
const char* determineOrigin() const;
|
const char* determineOrigin() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace {
|
|||||||
static const char* const kEnable = "enable";
|
static const char* const kEnable = "enable";
|
||||||
static const char* const kDisable = "disable";
|
static const char* const kDisable = "disable";
|
||||||
static const std::string kPsshTag = "pssh";
|
static const std::string kPsshTag = "pssh";
|
||||||
|
static const char* const kSpecialUnprovisionResponse = "unprovision";
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace wvdrm {
|
namespace wvdrm {
|
||||||
@@ -385,38 +386,35 @@ status_t WVDrmPlugin::provideProvisionResponse(
|
|||||||
Vector<uint8_t>& certificate,
|
Vector<uint8_t>& certificate,
|
||||||
Vector<uint8_t>& wrapped_key) {
|
Vector<uint8_t>& wrapped_key) {
|
||||||
CdmProvisioningResponse cdmResponse(response.begin(), response.end());
|
CdmProvisioningResponse cdmResponse(response.begin(), response.end());
|
||||||
string cdmCertificate;
|
if (cdmResponse == kSpecialUnprovisionResponse) {
|
||||||
string cdmWrappedKey;
|
const std::string origin = determineOrigin();
|
||||||
CdmResponseType res = mCDM->HandleProvisioningResponse(determineOrigin(),
|
if (origin == EMPTY_ORIGIN) return kErrorNoOriginSpecified;
|
||||||
cdmResponse,
|
return unprovision(origin);
|
||||||
&cdmCertificate,
|
} else {
|
||||||
&cdmWrappedKey);
|
string cdmCertificate;
|
||||||
if (isCdmResponseTypeSuccess(res)) {
|
string cdmWrappedKey;
|
||||||
certificate.clear();
|
CdmResponseType res = mCDM->HandleProvisioningResponse(determineOrigin(),
|
||||||
certificate.appendArray(
|
cdmResponse,
|
||||||
reinterpret_cast<const uint8_t*>(cdmCertificate.data()),
|
&cdmCertificate,
|
||||||
cdmCertificate.size());
|
&cdmWrappedKey);
|
||||||
|
if (isCdmResponseTypeSuccess(res)) {
|
||||||
|
certificate.clear();
|
||||||
|
certificate.appendArray(
|
||||||
|
reinterpret_cast<const uint8_t*>(cdmCertificate.data()),
|
||||||
|
cdmCertificate.size());
|
||||||
|
|
||||||
wrapped_key.clear();
|
wrapped_key.clear();
|
||||||
wrapped_key.appendArray(
|
wrapped_key.appendArray(
|
||||||
reinterpret_cast<const uint8_t*>(cdmWrappedKey.data()),
|
reinterpret_cast<const uint8_t*>(cdmWrappedKey.data()),
|
||||||
cdmWrappedKey.size());
|
cdmWrappedKey.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapCdmResponseType(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapCdmResponseType(res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t WVDrmPlugin::unprovisionDevice() {
|
status_t WVDrmPlugin::unprovisionDevice() {
|
||||||
CdmResponseType res1 = mCDM->Unprovision(kSecurityLevelL1, determineOrigin());
|
return unprovision(EMPTY_ORIGIN);
|
||||||
CdmResponseType res3 = mCDM->Unprovision(kSecurityLevelL3, determineOrigin());
|
|
||||||
if (!isCdmResponseTypeSuccess(res1))
|
|
||||||
{
|
|
||||||
return mapCdmResponseType(res1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return mapCdmResponseType(res3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t WVDrmPlugin::getSecureStop(const Vector<uint8_t>& ssid,
|
status_t WVDrmPlugin::getSecureStop(const Vector<uint8_t>& ssid,
|
||||||
@@ -1027,6 +1025,19 @@ bool WVDrmPlugin::InitDataResemblesPSSH(const Vector<uint8_t>& initData) {
|
|||||||
return id == kPsshTag;
|
return id == kPsshTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status_t WVDrmPlugin::unprovision(const std::string& origin) {
|
||||||
|
CdmResponseType res1 = mCDM->Unprovision(kSecurityLevelL1, origin);
|
||||||
|
CdmResponseType res3 = mCDM->Unprovision(kSecurityLevelL3, origin);
|
||||||
|
if (!isCdmResponseTypeSuccess(res1))
|
||||||
|
{
|
||||||
|
return mapCdmResponseType(res1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return mapCdmResponseType(res3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const char* WVDrmPlugin::determineOrigin() const {
|
const char* WVDrmPlugin::determineOrigin() const {
|
||||||
return mOrigin.empty() ? EMPTY_ORIGIN : mOrigin.c_str();
|
return mOrigin.empty() ? EMPTY_ORIGIN : mOrigin.c_str();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ namespace {
|
|||||||
const String8 kEmptyString;
|
const String8 kEmptyString;
|
||||||
const String8 kOrigin("widevine.com");
|
const String8 kOrigin("widevine.com");
|
||||||
const String8 kAppId("com.unittest.mock.app.id");
|
const String8 kAppId("com.unittest.mock.app.id");
|
||||||
|
const uint8_t* const kUnprovisionResponse =
|
||||||
|
reinterpret_cast<const uint8_t*>("unprovision");
|
||||||
|
const size_t kUnprovisionResponseSize = 11;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MockCDM : public WvContentDecryptionModule {
|
class MockCDM : public WvContentDecryptionModule {
|
||||||
@@ -627,6 +630,75 @@ TEST_F(WVDrmPluginTest, MuxesUnprovisioningErrors) {
|
|||||||
ASSERT_NE(OK, res);
|
ASSERT_NE(OK, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, UnprovisionsOrigin) {
|
||||||
|
StrictMock<MockCDM> cdm;
|
||||||
|
StrictMock<MockCrypto> crypto;
|
||||||
|
WVDrmPlugin plugin(&cdm, &crypto);
|
||||||
|
|
||||||
|
Vector<uint8_t> cert;
|
||||||
|
Vector<uint8_t> key;
|
||||||
|
Vector<uint8_t> specialResponse;
|
||||||
|
specialResponse.appendArray(kUnprovisionResponse, kUnprovisionResponseSize);
|
||||||
|
|
||||||
|
EXPECT_CALL(cdm, Unprovision(kSecurityLevelL1, StrEq(kOrigin.string())))
|
||||||
|
.Times(1);
|
||||||
|
EXPECT_CALL(cdm, Unprovision(kSecurityLevelL3, StrEq(kOrigin.string())))
|
||||||
|
.Times(1);
|
||||||
|
|
||||||
|
status_t res = plugin.setPropertyString(String8("origin"), kOrigin);
|
||||||
|
ASSERT_EQ(OK, res);
|
||||||
|
res = plugin.provideProvisionResponse(specialResponse, cert, key);
|
||||||
|
EXPECT_EQ(OK, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOrigin) {
|
||||||
|
StrictMock<MockCDM> cdm;
|
||||||
|
StrictMock<MockCrypto> crypto;
|
||||||
|
WVDrmPlugin plugin(&cdm, &crypto);
|
||||||
|
|
||||||
|
Vector<uint8_t> cert;
|
||||||
|
Vector<uint8_t> key;
|
||||||
|
Vector<uint8_t> specialResponse;
|
||||||
|
specialResponse.appendArray(kUnprovisionResponse, kUnprovisionResponseSize);
|
||||||
|
|
||||||
|
EXPECT_CALL(cdm, Unprovision(_, _))
|
||||||
|
.Times(0);
|
||||||
|
|
||||||
|
status_t res = plugin.provideProvisionResponse(specialResponse, cert, key);
|
||||||
|
EXPECT_NE(OK, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) {
|
||||||
|
StrictMock<MockCDM> cdm;
|
||||||
|
StrictMock<MockCrypto> crypto;
|
||||||
|
WVDrmPlugin plugin(&cdm, &crypto);
|
||||||
|
|
||||||
|
Vector<uint8_t> cert;
|
||||||
|
Vector<uint8_t> key;
|
||||||
|
Vector<uint8_t> specialResponse;
|
||||||
|
specialResponse.appendArray(kUnprovisionResponse, kUnprovisionResponseSize);
|
||||||
|
|
||||||
|
// Tests that both Unprovisions are called even if one fails. Also tests that
|
||||||
|
// no matter which fails, the function always propagates the error.
|
||||||
|
EXPECT_CALL(cdm, Unprovision(kSecurityLevelL1, StrEq(kOrigin.string())))
|
||||||
|
.WillOnce(Return(wvcdm::UNKNOWN_ERROR))
|
||||||
|
.WillOnce(Return(wvcdm::NO_ERROR))
|
||||||
|
.WillOnce(Return(wvcdm::UNKNOWN_ERROR));
|
||||||
|
EXPECT_CALL(cdm, Unprovision(kSecurityLevelL3, StrEq(kOrigin.string())))
|
||||||
|
.WillOnce(Return(wvcdm::NO_ERROR))
|
||||||
|
.WillOnce(Return(wvcdm::UNKNOWN_ERROR))
|
||||||
|
.WillOnce(Return(wvcdm::UNKNOWN_ERROR));
|
||||||
|
|
||||||
|
status_t res = plugin.setPropertyString(String8("origin"), kOrigin);
|
||||||
|
ASSERT_EQ(OK, res);
|
||||||
|
res = plugin.provideProvisionResponse(specialResponse, cert, key);
|
||||||
|
EXPECT_NE(OK, res);
|
||||||
|
res = plugin.provideProvisionResponse(specialResponse, cert, key);
|
||||||
|
EXPECT_NE(OK, res);
|
||||||
|
res = plugin.provideProvisionResponse(specialResponse, cert, key);
|
||||||
|
EXPECT_NE(OK, res);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(WVDrmPluginTest, GetsSecureStops) {
|
TEST_F(WVDrmPluginTest, GetsSecureStops) {
|
||||||
StrictMock<MockCDM> cdm;
|
StrictMock<MockCDM> cdm;
|
||||||
StrictMock<MockCrypto> crypto;
|
StrictMock<MockCrypto> crypto;
|
||||||
|
|||||||
Reference in New Issue
Block a user