|
|
|
|
@@ -75,6 +75,7 @@ using wvcdm::kLicenseTypeRelease;
|
|
|
|
|
using wvcdm::kLicenseTypeStreaming;
|
|
|
|
|
using wvcdm::kSecurityLevelL1;
|
|
|
|
|
using wvcdm::kSecurityLevelL3;
|
|
|
|
|
using wvcdm::Base64Encode;
|
|
|
|
|
using wvcdm::CdmAppParameterMap;
|
|
|
|
|
using wvcdm::CdmCertificateType;
|
|
|
|
|
using wvcdm::CdmClientPropertySet;
|
|
|
|
|
@@ -100,6 +101,7 @@ using wvcdm::KEY_SET_ID_PREFIX;
|
|
|
|
|
using wvcdm::NEVER_EXPIRES;
|
|
|
|
|
using wvcdm::QUERY_KEY_CURRENT_SRM_VERSION;
|
|
|
|
|
using wvcdm::QUERY_KEY_DEVICE_ID;
|
|
|
|
|
using wvcdm::QUERY_KEY_DECRYPT_HASH_SUPPORT;
|
|
|
|
|
using wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS;
|
|
|
|
|
using wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS;
|
|
|
|
|
using wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION;
|
|
|
|
|
@@ -208,6 +210,8 @@ class MockCDM : public WvContentDecryptionModule {
|
|
|
|
|
|
|
|
|
|
MOCK_METHOD2(GetMetrics, CdmResponseType(const CdmIdentifier&,
|
|
|
|
|
drm_metrics::WvCdmMetrics*));
|
|
|
|
|
|
|
|
|
|
MOCK_METHOD2(GetDecryptHashError, CdmResponseType(const CdmSessionId&, std::string*));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class MockCrypto : public WVGenericCryptoInterface {
|
|
|
|
|
@@ -344,7 +348,7 @@ TEST_F(WVDrmPluginTest, OpensSessions_1_1) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
// Provide expected mock behavior
|
|
|
|
|
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _))
|
|
|
|
|
@@ -655,7 +659,7 @@ TEST_F(WVDrmPluginTest, HandlesPrivacyCertCaseOfAddKey) {
|
|
|
|
|
sp<StrictMock<MockDrmPluginListener> > listener =
|
|
|
|
|
new StrictMock<MockDrmPluginListener>();
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
// Provide expected behavior in response to OpenSession and store the
|
|
|
|
|
// property set
|
|
|
|
|
@@ -1138,6 +1142,10 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
|
|
|
|
static const std::string cdmVersion = "Infinity Minus 1";
|
|
|
|
|
static const std::string resourceRatingTier = "1";
|
|
|
|
|
static const std::string oemCryptoBuildInformation = "Mostly Harmless";
|
|
|
|
|
static const std::string oemCryptoHashNotSupported = "0";
|
|
|
|
|
static const std::string oemCryptoCrcClearBuffer = "1";
|
|
|
|
|
static const std::string oemCryptoPartnerDefinedHash = "2";
|
|
|
|
|
static const std::string decryptHashErrorBadHashAndFrameNumber = "53, 1";
|
|
|
|
|
drm_metrics::WvCdmMetrics expected_metrics;
|
|
|
|
|
std::string serialized_metrics = wvcdm::a2bs_hex(kSerializedMetricsHex);
|
|
|
|
|
ASSERT_TRUE(expected_metrics.ParseFromString(serialized_metrics));
|
|
|
|
|
@@ -1188,10 +1196,18 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
|
|
|
|
.WillOnce(DoAll(SetArgPointee<2>(resourceRatingTier),
|
|
|
|
|
testing::Return(wvcdm::NO_ERROR)));
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DECRYPT_HASH_SUPPORT, _))
|
|
|
|
|
.WillOnce(DoAll(SetArgPointee<2>("1"),
|
|
|
|
|
testing::Return(wvcdm::NO_ERROR)));
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, _))
|
|
|
|
|
.WillOnce(DoAll(SetArgPointee<2>(oemCryptoBuildInformation),
|
|
|
|
|
testing::Return(wvcdm::NO_ERROR)));
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*cdm, GetDecryptHashError(_, _))
|
|
|
|
|
.WillOnce(DoAll(SetArgPointee<1>(decryptHashErrorBadHashAndFrameNumber),
|
|
|
|
|
testing::Return(wvcdm::NO_ERROR)));
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*cdm, GetMetrics(_, _))
|
|
|
|
|
.WillOnce(DoAll(SetArgPointee<1>(expected_metrics),
|
|
|
|
|
testing::Return(wvcdm::NO_ERROR)));
|
|
|
|
|
@@ -1311,6 +1327,24 @@ TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
|
|
|
|
|
EXPECT_STREQ(oemCryptoBuildInformation.c_str(), stringResult.c_str());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << oemCryptoHashNotSupported << " " << oemCryptoCrcClearBuffer << " "
|
|
|
|
|
<< oemCryptoPartnerDefinedHash;
|
|
|
|
|
std::string validResults = ss.str();
|
|
|
|
|
plugin.getPropertyString(
|
|
|
|
|
hidl_string("decryptHashSupport"),
|
|
|
|
|
[&](Status status, hidl_string stringResult) {
|
|
|
|
|
ASSERT_EQ(Status::OK, status);
|
|
|
|
|
EXPECT_EQ(oemCryptoCrcClearBuffer, stringResult);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
plugin.getPropertyString(
|
|
|
|
|
hidl_string("decryptHashError"),
|
|
|
|
|
[&](Status status, hidl_string stringResult) {
|
|
|
|
|
ASSERT_EQ(Status::OK, status);
|
|
|
|
|
EXPECT_EQ(decryptHashErrorBadHashAndFrameNumber, stringResult);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// This call occurs before any open session or other call. This means
|
|
|
|
|
// that the cdm identifer is not yet sealed, and metrics return empty
|
|
|
|
|
// metrics data.
|
|
|
|
|
@@ -2065,7 +2099,7 @@ TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
// Provide expected mock behavior
|
|
|
|
|
{
|
|
|
|
|
@@ -2104,7 +2138,7 @@ TEST_F(WVDrmPluginTest, CanSetAppId) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
// Provide expected mock behavior
|
|
|
|
|
{
|
|
|
|
|
@@ -2205,7 +2239,7 @@ TEST_F(WVDrmPluginTest, CanSetSecurityLevel) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _))
|
|
|
|
|
.WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3),
|
|
|
|
|
@@ -2335,7 +2369,7 @@ TEST_F(WVDrmPluginTest, CanSetPrivacyMode) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
// Provide expected mock behavior
|
|
|
|
|
{
|
|
|
|
|
@@ -2386,7 +2420,7 @@ TEST_F(WVDrmPluginTest, CanSetServiceCertificate) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
static const size_t kPrivacyCertSize = 256;
|
|
|
|
|
uint8_t privacyCertRaw[kPrivacyCertSize];
|
|
|
|
|
@@ -2459,7 +2493,7 @@ TEST_F(WVDrmPluginTest, CanSetSessionSharing) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
const CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
const CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
// Provide expected mock behavior
|
|
|
|
|
{
|
|
|
|
|
@@ -2534,7 +2568,7 @@ TEST_F(WVDrmPluginTest, AllowsStoringOfSessionSharingId) {
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
CdmClientPropertySet* propertySet = NULL;
|
|
|
|
|
CdmClientPropertySet* propertySet = nullptr;
|
|
|
|
|
|
|
|
|
|
uint32_t sharingId;
|
|
|
|
|
FILE* fp = fopen("/dev/urandom", "r");
|
|
|
|
|
@@ -2570,6 +2604,126 @@ TEST_F(WVDrmPluginTest, AllowsStoringOfSessionSharingId) {
|
|
|
|
|
EXPECT_EQ(sharingId, propertySet->session_sharing_id());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WVDrmPluginTest, CanSetDecryptHashProperties) {
|
|
|
|
|
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
// Provide expected mock behavior
|
|
|
|
|
{
|
|
|
|
|
// Provide expected behavior in response to OpenSession and store the
|
|
|
|
|
// property set
|
|
|
|
|
EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _))
|
|
|
|
|
.WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId),
|
|
|
|
|
testing::Return(wvcdm::NO_ERROR)));
|
|
|
|
|
|
|
|
|
|
// Provide expected behavior when plugin requests session control info
|
|
|
|
|
EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _))
|
|
|
|
|
.WillRepeatedly(Invoke(setSessionIdOnMap<4>));
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*cdm, CloseSession(_))
|
|
|
|
|
.Times(AtLeast(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
|
|
|
|
|
|
|
|
|
hidl_vec<uint8_t> hSessionId;
|
|
|
|
|
hSessionId.setToExternal(sessionIdRaw, kSessionIdSize);
|
|
|
|
|
plugin.openSession([&](Status status, hidl_vec<uint8_t> hSessionId) {
|
|
|
|
|
ASSERT_EQ(Status::OK, status);
|
|
|
|
|
sessionId.clear();
|
|
|
|
|
sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// CDM expects the string property value to be in the following format:
|
|
|
|
|
// "<sessionId>,<frameNumber>,<base64encodedHash>"
|
|
|
|
|
static const std::string frameNumber = ",1";
|
|
|
|
|
uint32_t hash = 0xbeef; // crc32 hash
|
|
|
|
|
std::vector<uint8_t> hashVector(
|
|
|
|
|
reinterpret_cast<uint8_t*>(&hash),
|
|
|
|
|
reinterpret_cast<uint8_t*>(&hash) + sizeof(uint32_t));
|
|
|
|
|
std::string base64EncodedHash = Base64Encode(hashVector);
|
|
|
|
|
std::string computedHash(sessionId.begin(), sessionId.end());
|
|
|
|
|
computedHash.append(frameNumber.c_str());
|
|
|
|
|
computedHash.append(base64EncodedHash.c_str());
|
|
|
|
|
Status status = plugin.setPropertyString(hidl_string("decryptHash"),
|
|
|
|
|
hidl_string(computedHash));
|
|
|
|
|
ASSERT_NE(Status::OK, status);
|
|
|
|
|
|
|
|
|
|
status = plugin.closeSession(toHidlVec(sessionId));
|
|
|
|
|
ASSERT_EQ(Status::OK, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST_F(WVDrmPluginTest, DoesNotSetDecryptHashProperties) {
|
|
|
|
|
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
|
|
|
|
StrictMock<MockCrypto> crypto;
|
|
|
|
|
std::string appPackageName;
|
|
|
|
|
|
|
|
|
|
// Provide expected mock behavior
|
|
|
|
|
{
|
|
|
|
|
// Provide expected behavior in response to OpenSession and store the
|
|
|
|
|
// property set
|
|
|
|
|
EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _))
|
|
|
|
|
.WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId),
|
|
|
|
|
testing::Return(wvcdm::NO_ERROR)));
|
|
|
|
|
|
|
|
|
|
// Provide expected behavior when plugin requests session control info
|
|
|
|
|
EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _))
|
|
|
|
|
.WillRepeatedly(Invoke(setSessionIdOnMap<4>));
|
|
|
|
|
|
|
|
|
|
EXPECT_CALL(*cdm, CloseSession(_))
|
|
|
|
|
.Times(AtLeast(0));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
|
|
|
|
|
|
|
|
|
|
hidl_vec<uint8_t> hSessionId;
|
|
|
|
|
hSessionId.setToExternal(sessionIdRaw, kSessionIdSize);
|
|
|
|
|
plugin.openSession([&](Status status, hidl_vec<uint8_t> hSessionId) {
|
|
|
|
|
ASSERT_EQ(Status::OK, status);
|
|
|
|
|
sessionId.clear();
|
|
|
|
|
sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size());
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// CDM expects the string property value to be in the following format:
|
|
|
|
|
// "<sessionId>,<frameNumber>,<base64encodedHash>"
|
|
|
|
|
static const std::string frameNumber = ",1";
|
|
|
|
|
static const std::string hash = ",AZaz0+,/";
|
|
|
|
|
std::string value(sessionId.begin(), sessionId.end());
|
|
|
|
|
value.append(frameNumber.c_str());
|
|
|
|
|
|
|
|
|
|
// Tests for missing token handling
|
|
|
|
|
Status status = plugin.setPropertyString(hidl_string("decryptHash"),
|
|
|
|
|
hidl_string(value));
|
|
|
|
|
EXPECT_NE(Status::OK, status);
|
|
|
|
|
|
|
|
|
|
// Tests for empty token
|
|
|
|
|
value.append(",");
|
|
|
|
|
status = plugin.setPropertyString(hidl_string("decryptHash"),
|
|
|
|
|
hidl_string(value));
|
|
|
|
|
EXPECT_NE(Status::OK, status);
|
|
|
|
|
|
|
|
|
|
// Tests for invalid sessionId
|
|
|
|
|
value.clear();
|
|
|
|
|
value.append("bad session id");
|
|
|
|
|
value.append(",1");
|
|
|
|
|
value.append(hash.c_str());
|
|
|
|
|
status = plugin.setPropertyString(hidl_string("decryptHash"),
|
|
|
|
|
hidl_string(value));
|
|
|
|
|
EXPECT_NE(Status::OK, status);
|
|
|
|
|
|
|
|
|
|
// Tests for malformed Base64encode hash, with a ","
|
|
|
|
|
std::string computedHash(sessionId.begin(), sessionId.end());
|
|
|
|
|
computedHash.append(frameNumber.c_str());
|
|
|
|
|
computedHash.append(hash.c_str());
|
|
|
|
|
status = plugin.setPropertyString(hidl_string("decryptHash"),
|
|
|
|
|
hidl_string(computedHash));
|
|
|
|
|
EXPECT_NE(Status::OK, status);
|
|
|
|
|
|
|
|
|
|
status = plugin.closeSession(toHidlVec(sessionId));
|
|
|
|
|
ASSERT_EQ(Status::OK, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace widevine
|
|
|
|
|
} // namespace V1_2
|
|
|
|
|
} // namespace drm
|
|
|
|
|
|