Merge "Add testcases for restoreKeys API." into oc-dev

This commit is contained in:
TreeHugger Robot
2017-04-14 21:38:30 +00:00
committed by Android (Google) Code Review
3 changed files with 223 additions and 129 deletions

View File

@@ -245,6 +245,7 @@ class DrmHalClearkeyPluginTest : public DrmHalClearkeyFactoryTest {
SessionId openSession(); SessionId openSession();
void closeSession(const SessionId& sessionId); void closeSession(const SessionId& sessionId);
hidl_vec<uint8_t> loadKeys(const SessionId& sessionId, const KeyType& type);
sp<IMemory> getDecryptMemory(size_t size, size_t index); sp<IMemory> getDecryptMemory(size_t size, size_t index);
protected: protected:
@@ -312,6 +313,70 @@ void DrmHalClearkeyPluginTest::closeSession(const SessionId& sessionId) {
EXPECT_EQ(Status::OK, result); EXPECT_EQ(Status::OK, result);
} }
/**
* Helper method to load keys for subsequent decrypt tests.
* These tests use predetermined key request/response to
* avoid requiring a round trip to a license server.
*/
hidl_vec<uint8_t> DrmHalClearkeyPluginTest::loadKeys(
const SessionId& sessionId, const KeyType& type = KeyType::STREAMING) {
hidl_vec<uint8_t> initData = {
// BMFF box header (4 bytes size + 'pssh')
0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
// full box header (version = 1 flags = 0)
0x01, 0x00, 0x00, 0x00,
// system id
0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
0x52, 0xe2, 0xfb, 0x4b,
// number of key ids
0x00, 0x00, 0x00, 0x01,
// key id
0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0, 0x0d,
0x1e, 0xd0, 0x0d, 0x1e,
// size of data, must be zero
0x00, 0x00, 0x00, 0x00};
hidl_vec<uint8_t> expectedKeyRequest = {
0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59,
0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b,
0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22,
0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x74,
0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d};
hidl_vec<uint8_t> knownKeyResponse = {
0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22,
0x6b, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c,
0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, 0x41, 0x59, 0x65,
0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b, 0x56, 0x39, 0x41,
0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b,
0x22, 0x3a, 0x22, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65,
0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, 0x36, 0x34,
0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a};
hidl_string mimeType = "video/mp4";
KeyedVector optionalParameters;
auto res = drmPlugin->getKeyRequest(
sessionId, initData, mimeType, type, optionalParameters,
[&](Status status, const hidl_vec<uint8_t>& request,
KeyRequestType requestType, const hidl_string&) {
EXPECT_EQ(Status::OK, status);
EXPECT_EQ(KeyRequestType::INITIAL, requestType);
EXPECT_EQ(request, expectedKeyRequest);
});
EXPECT_OK(res);
hidl_vec<uint8_t> keySetId;
res = drmPlugin->provideKeyResponse(
sessionId, knownKeyResponse,
[&](Status status, const hidl_vec<uint8_t>& myKeySetId) {
EXPECT_EQ(Status::OK, status);
EXPECT_EQ(0u, myKeySetId.size());
keySetId = myKeySetId;
});
EXPECT_OK(res);
return keySetId;
}
/** /**
* Test that a session can be opened and closed * Test that a session can be opened and closed
*/ */
@@ -470,6 +535,30 @@ TEST_F(DrmHalClearkeyPluginTest, RemoveKeysNewSession) {
closeSession(sessionId); closeSession(sessionId);
} }
/**
* Test that ClearKey cannot handle key restoring.
* Expected message is Status::ERROR_DRM_CANNOT_HANDLE.
*/
TEST_F(DrmHalClearkeyPluginTest, RestoreKeysCannotHandle) {
hidl_vec<uint8_t> keySetId = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
SessionId sessionId = openSession();
Status status = drmPlugin->restoreKeys(sessionId, keySetId);
EXPECT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
closeSession(sessionId);
}
/**
* Test that restoreKeys fails with a null key set ID.
* Error message is expected to be Status::BAD_VALUE.
*/
TEST_F(DrmHalClearkeyPluginTest, RestoreKeysNull) {
SessionId sessionId = openSession();
hidl_vec<uint8_t> nullKeySetId;
Status status = drmPlugin->restoreKeys(sessionId, nullKeySetId);
EXPECT_EQ(Status::BAD_VALUE, status);
closeSession(sessionId);
}
/** /**
* Test that the clearkey plugin doesn't support getting * Test that the clearkey plugin doesn't support getting
* secure stops. * secure stops.
@@ -831,7 +920,6 @@ TEST_F(DrmHalClearkeyPluginTest, SetMediaDrmSessionEmptySession) {
class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest { class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest {
public: public:
void loadKeys(const SessionId& sessionId);
void fillRandom(const sp<IMemory>& memory); void fillRandom(const sp<IMemory>& memory);
hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) { hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
EXPECT_EQ(16u, vec.size()); EXPECT_EQ(16u, vec.size());
@@ -845,67 +933,6 @@ class DrmHalClearkeyDecryptTest : public DrmHalClearkeyPluginTest {
const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key); const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
}; };
/**
* Helper method to load keys for subsequent decrypt tests.
* These tests use predetermined key request/response to
* avoid requiring a round trip to a license server.
*/
void DrmHalClearkeyDecryptTest::loadKeys(const SessionId& sessionId) {
hidl_vec<uint8_t> initData = {
// BMFF box header (4 bytes size + 'pssh')
0x00, 0x00, 0x00, 0x34, 0x70, 0x73, 0x73, 0x68,
// full box header (version = 1 flags = 0)
0x01, 0x00, 0x00, 0x00,
// system id
0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, 0xac, 0xe3, 0x3c,
0x1e, 0x52, 0xe2, 0xfb, 0x4b,
// number of key ids
0x00, 0x00, 0x00, 0x01,
// key id
0x60, 0x06, 0x1e, 0x01, 0x7e, 0x47, 0x7e, 0x87, 0x7e, 0x57, 0xd0,
0x0d, 0x1e, 0xd0, 0x0d, 0x1e,
// size of data, must be zero
0x00, 0x00, 0x00, 0x00};
hidl_vec<uint8_t> expectedKeyRequest = {
0x7b, 0x22, 0x6b, 0x69, 0x64, 0x73, 0x22, 0x3a, 0x5b, 0x22, 0x59,
0x41, 0x59, 0x65, 0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b,
0x56, 0x39, 0x41, 0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22,
0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x74,
0x65, 0x6d, 0x70, 0x6f, 0x72, 0x61, 0x72, 0x79, 0x22, 0x7d};
hidl_vec<uint8_t> knownKeyResponse = {
0x7b, 0x22, 0x6b, 0x65, 0x79, 0x73, 0x22, 0x3a, 0x5b, 0x7b, 0x22,
0x6b, 0x74, 0x79, 0x22, 0x3a, 0x22, 0x6f, 0x63, 0x74, 0x22, 0x2c,
0x22, 0x6b, 0x69, 0x64, 0x22, 0x3a, 0x22, 0x59, 0x41, 0x59, 0x65,
0x41, 0x58, 0x35, 0x48, 0x66, 0x6f, 0x64, 0x2b, 0x56, 0x39, 0x41,
0x4e, 0x48, 0x74, 0x41, 0x4e, 0x48, 0x67, 0x22, 0x2c, 0x22, 0x6b,
0x22, 0x3a, 0x22, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54, 0x65,
0x73, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x61, 0x73, 0x65, 0x36, 0x34,
0x67, 0x67, 0x67, 0x22, 0x7d, 0x5d, 0x7d, 0x0a};
hidl_string mimeType = "video/mp4";
KeyedVector optionalParameters;
auto res = drmPlugin->getKeyRequest(
sessionId, initData, mimeType, KeyType::STREAMING,
optionalParameters,
[&](Status status, const hidl_vec<uint8_t>& request,
KeyRequestType requestType, const hidl_string&) {
EXPECT_EQ(Status::OK, status);
EXPECT_EQ(KeyRequestType::INITIAL, requestType);
EXPECT_EQ(request, expectedKeyRequest);
});
EXPECT_OK(res);
res = drmPlugin->provideKeyResponse(
sessionId, knownKeyResponse,
[&](Status status, const hidl_vec<uint8_t>& keySetId) {
EXPECT_EQ(Status::OK, status);
EXPECT_EQ(0u, keySetId.size());
});
EXPECT_OK(res);
}
void DrmHalClearkeyDecryptTest::fillRandom(const sp<IMemory>& memory) { void DrmHalClearkeyDecryptTest::fillRandom(const sp<IMemory>& memory) {
random_device rd; random_device rd;
mt19937 rand(rd()); mt19937 rand(rd());

View File

@@ -157,18 +157,31 @@ class DrmHalVTSVendorModule_V1 : public DrmHalVTSVendorModule {
*/ */
const std::map<std::string, std::string> optionalParameters; const std::map<std::string, std::string> optionalParameters;
/**
* Define license policy attributes for the content configuration.
* These attributes can affect which tests are able to be applied.
*/
struct Policy {
/**
* Indicate if the license policy allows offline playback.
* Content configurated with this policy supports KeyType::OFFLINE
* key requests/responses. A vendor module should provide at least
* one content configuration where allowOffline is true if the drm
* scheme supports offline content.
*/
bool allowOffline;
} policy;
/** /**
* The keys that will be available once the keys are loaded * The keys that will be available once the keys are loaded
*/ */
struct Key { struct Key {
/** /**
* Indicate if the key content is configured to require secure * Indicate if the key content is configured to require secure
* buffers, * buffers, where the output buffers are protected and cannot be
* where the output buffers are protected and cannot be accessed. * accessed by the non-secure cpu. A vendor module should provide
* A vendor module should provide some content configurations where * at least one content configurations where isSecure is false, to
* isSecure is false, to allow decrypt result verification tests to * allow decrypt result verification tests to be run.
* be
* run.
*/ */
bool isSecure; bool isSecure;

View File

@@ -142,6 +142,7 @@ class DrmHalVendorFactoryTest : public testing::TestWithParam<std::string> {
TEST_P(DrmHalVendorFactoryTest, ValidateConfigurations) { TEST_P(DrmHalVendorFactoryTest, ValidateConfigurations) {
const char* kVendorStr = "Vendor module "; const char* kVendorStr = "Vendor module ";
size_t count = 0;
for (auto config : contentConfigurations) { for (auto config : contentConfigurations) {
ASSERT_TRUE(config.name.size() > 0) << kVendorStr << "has no name"; ASSERT_TRUE(config.name.size() > 0) << kVendorStr << "has no name";
ASSERT_TRUE(config.serverUrl.size() > 0) << kVendorStr ASSERT_TRUE(config.serverUrl.size() > 0) << kVendorStr
@@ -157,7 +158,9 @@ TEST_P(DrmHalVendorFactoryTest, ValidateConfigurations) {
ASSERT_TRUE(key.keyId.size() > 0) << kVendorStr ASSERT_TRUE(key.keyId.size() > 0) << kVendorStr
<< " has zero length key value"; << " has zero length key value";
} }
count++;
} }
EXPECT_NE(0u, count);
} }
/** /**
@@ -299,6 +302,10 @@ class DrmHalVendorPluginTest : public DrmHalVendorFactoryTest {
SessionId openSession(); SessionId openSession();
void closeSession(const SessionId& sessionId); void closeSession(const SessionId& sessionId);
sp<IMemory> getDecryptMemory(size_t size, size_t index); sp<IMemory> getDecryptMemory(size_t size, size_t index);
KeyedVector toHidlKeyedVector(const map<string, string>& params);
hidl_vec<uint8_t> loadKeys(const SessionId& sessionId,
const ContentConfiguration& configuration,
const KeyType& type);
protected: protected:
sp<IDrmPlugin> drmPlugin; sp<IDrmPlugin> drmPlugin;
@@ -389,6 +396,64 @@ void DrmHalVendorPluginTest::closeSession(const SessionId& sessionId) {
EXPECT_EQ(Status::OK, status); EXPECT_EQ(Status::OK, status);
} }
KeyedVector DrmHalVendorPluginTest::toHidlKeyedVector(
const map<string, string>& params) {
std::vector<KeyValue> stdKeyedVector;
for (auto it = params.begin(); it != params.end(); ++it) {
KeyValue keyValue;
keyValue.key = it->first;
keyValue.value = it->second;
stdKeyedVector.push_back(keyValue);
}
return KeyedVector(stdKeyedVector);
}
/**
* Helper method to load keys for subsequent decrypt tests.
* These tests use predetermined key request/response to
* avoid requiring a round trip to a license server.
*/
hidl_vec<uint8_t> DrmHalVendorPluginTest::loadKeys(
const SessionId& sessionId, const ContentConfiguration& configuration,
const KeyType& type = KeyType::STREAMING) {
hidl_vec<uint8_t> keyRequest;
auto res = drmPlugin->getKeyRequest(
sessionId, configuration.initData, configuration.mimeType, type,
toHidlKeyedVector(configuration.optionalParameters),
[&](Status status, const hidl_vec<uint8_t>& request,
KeyRequestType type, const hidl_string&) {
EXPECT_EQ(Status::OK, status) << "Failed to get "
"key request for configuration "
<< configuration.name;
EXPECT_EQ(type, KeyRequestType::INITIAL);
EXPECT_NE(request.size(), 0u) << "Expected key request size"
" to have length > 0 bytes";
keyRequest = request;
});
EXPECT_OK(res);
/**
* Get key response from vendor module
*/
hidl_vec<uint8_t> keyResponse =
vendorModule->handleKeyRequest(keyRequest, configuration.serverUrl);
EXPECT_NE(keyResponse.size(), 0u) << "Expected key response size "
"to have length > 0 bytes";
hidl_vec<uint8_t> keySetId;
res = drmPlugin->provideKeyResponse(
sessionId, keyResponse,
[&](Status status, const hidl_vec<uint8_t>& myKeySetId) {
EXPECT_EQ(Status::OK, status) << "Failure providing "
"key response for configuration "
<< configuration.name;
keySetId = myKeySetId;
});
EXPECT_OK(res);
return keySetId;
}
/** /**
* Test that a session can be opened and closed * Test that a session can be opened and closed
*/ */
@@ -487,6 +552,56 @@ TEST_P(DrmHalVendorPluginTest, RemoveKeysNewSession) {
closeSession(sessionId); closeSession(sessionId);
} }
/**
* Test that keys are successfully restored to a new session
* for all content having a policy that allows offline use.
*/
TEST_P(DrmHalVendorPluginTest, RestoreKeys) {
for (auto config : contentConfigurations) {
if (config.policy.allowOffline) {
auto sessionId = openSession();
hidl_vec<uint8_t> keySetId =
loadKeys(sessionId, config, KeyType::OFFLINE);
closeSession(sessionId);
sessionId = openSession();
EXPECT_NE(0u, keySetId.size());
Status status = drmPlugin->restoreKeys(sessionId, keySetId);
EXPECT_EQ(Status::OK, status);
closeSession(sessionId);
}
}
}
/**
* Test that restoreKeys fails with a null key set ID.
* Error message is expected to be Status::BAD_VALUE.
*/
TEST_P(DrmHalVendorPluginTest, RestoreKeysNull) {
SessionId sessionId = openSession();
hidl_vec<uint8_t> nullKeySetId;
Status status = drmPlugin->restoreKeys(sessionId, nullKeySetId);
EXPECT_EQ(Status::BAD_VALUE, status);
closeSession(sessionId);
}
/**
* Test that restoreKeys fails to restore keys to a closed
* session. Error message is expected to be
* Status::ERROR_DRM_SESSION_NOT_OPENED.
*/
TEST_P(DrmHalVendorPluginTest, RestoreKeysClosedSession) {
for (auto config : contentConfigurations) {
auto sessionId = openSession();
hidl_vec<uint8_t> keySetId = loadKeys(sessionId, config);
EXPECT_NE(0u, keySetId.size());
closeSession(sessionId);
sessionId = openSession();
closeSession(sessionId);
Status status = drmPlugin->restoreKeys(sessionId, keySetId);
EXPECT_EQ(Status::ERROR_DRM_SESSION_NOT_OPENED, status);
}
}
/** /**
* Test that the plugin either doesn't support getting * Test that the plugin either doesn't support getting
* secure stops, or has no secure stops available after * secure stops, or has no secure stops available after
@@ -821,7 +936,6 @@ TEST_P(DrmHalVendorPluginTest, RequiresSecureDecoderInvalidMimeType) {
* configurations * configurations
*/ */
TEST_P(DrmHalVendorPluginTest, RequiresSecureDecoderConfig) { TEST_P(DrmHalVendorPluginTest, RequiresSecureDecoderConfig) {
const char* kVendorStr = "Vendor module ";
for (auto config : contentConfigurations) { for (auto config : contentConfigurations) {
for (auto key : config.keys) { for (auto key : config.keys) {
if (key.isSecure) { if (key.isSecure) {
@@ -1060,10 +1174,7 @@ class DrmHalVendorDecryptTest : public DrmHalVendorPluginTest {
virtual ~DrmHalVendorDecryptTest() {} virtual ~DrmHalVendorDecryptTest() {}
protected: protected:
void loadKeys(const SessionId& sessionId,
const ContentConfiguration& configuration);
void fillRandom(const sp<IMemory>& memory); void fillRandom(const sp<IMemory>& memory);
KeyedVector toHidlKeyedVector(const map<string, string>& params);
hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) { hidl_array<uint8_t, 16> toHidlArray(const vector<uint8_t>& vec) {
EXPECT_EQ(vec.size(), 16u); EXPECT_EQ(vec.size(), 16u);
return hidl_array<uint8_t, 16>(&vec[0]); return hidl_array<uint8_t, 16>(&vec[0]);
@@ -1080,63 +1191,6 @@ class DrmHalVendorDecryptTest : public DrmHalVendorPluginTest {
const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key); const hidl_vec<SubSample>& subSamples, const vector<uint8_t>& key);
}; };
KeyedVector DrmHalVendorDecryptTest::toHidlKeyedVector(
const map<string, string>& params) {
std::vector<KeyValue> stdKeyedVector;
for (auto it = params.begin(); it != params.end(); ++it) {
KeyValue keyValue;
keyValue.key = it->first;
keyValue.value = it->second;
stdKeyedVector.push_back(keyValue);
}
return KeyedVector(stdKeyedVector);
}
/**
* Helper method to load keys for subsequent decrypt tests.
* These tests use predetermined key request/response to
* avoid requiring a round trip to a license server.
*/
void DrmHalVendorDecryptTest::loadKeys(const SessionId& sessionId,
const ContentConfiguration& configuration) {
hidl_vec<uint8_t> keyRequest;
auto res = drmPlugin->getKeyRequest(
sessionId, configuration.initData, configuration.mimeType,
KeyType::STREAMING,
toHidlKeyedVector(configuration.optionalParameters),
[&](Status status, const hidl_vec<uint8_t>& request,
KeyRequestType type, const hidl_string&) {
EXPECT_EQ(Status::OK, status)
<< "Failed to get "
"key request for configuration "
<< configuration.name;
EXPECT_EQ(type, KeyRequestType::INITIAL);
EXPECT_NE(request.size(), 0u) << "Expected key request size"
" to have length > 0 bytes";
keyRequest = request;
});
EXPECT_OK(res);
/**
* Get key response from vendor module
*/
hidl_vec<uint8_t> keyResponse =
vendorModule->handleKeyRequest(keyRequest, configuration.serverUrl);
EXPECT_NE(keyResponse.size(), 0u) << "Expected key response size "
"to have length > 0 bytes";
res = drmPlugin->provideKeyResponse(
sessionId, keyResponse,
[&](Status status, const hidl_vec<uint8_t>&) {
EXPECT_EQ(Status::OK, status)
<< "Failure providing "
"key response for configuration "
<< configuration.name;
});
EXPECT_OK(res);
}
void DrmHalVendorDecryptTest::fillRandom(const sp<IMemory>& memory) { void DrmHalVendorDecryptTest::fillRandom(const sp<IMemory>& memory) {
random_device rd; random_device rd;
mt19937 rand(rd()); mt19937 rand(rd());