Merge "Android CDM: Removed secure stop tests."

This commit is contained in:
Alex Dale
2022-10-19 21:04:25 +00:00
committed by Android (Google) Code Review
4 changed files with 40 additions and 1681 deletions

View File

@@ -984,68 +984,6 @@ TEST_F(WvCdmExtendedDurationTest, DecryptionCloseSessionConcurrencyTest) {
decryptor_->CloseSession(session_id);
}
// TODO(rfrias): Rewite this test when OEMCrypto v13 is the minimum version
// supported. The limitation of 50 usage entries are no longer present
// when using usage table header+entries.
TEST_F(WvCdmExtendedDurationTest, DISABLED_UsageOverflowTest) {
Provision();
TestWvCdmClientPropertySet client_property_set;
TestWvCdmClientPropertySet* property_set = nullptr;
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
std::vector<std::string> provider_session_tokens;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(
DeviceFiles::GetUsageInfoFileName(""), &provider_session_tokens));
for (size_t i = 0; i < kMaxUsageTableSize + 100; ++i) {
decryptor_->OpenSession(config_.key_system(), property_set,
kDefaultCdmIdentifier, nullptr, &session_id_);
std::string key_id = wvutil::a2bs_hex(
"000000427073736800000000" // blob size and pssh
"EDEF8BA979D64ACEA3C827DCD51D21ED00000022" // Widevine system id
"08011a0d7769646576696e655f74657374220f73" // pssh data
"747265616d696e675f636c697035");
GenerateKeyRequest(key_id, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false);
decryptor_->CloseSession(session_id_);
}
CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status =
decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
int error_count = 0;
while (usage_info.size() > 0) {
for (size_t i = 0; i < usage_info.size(); ++i) {
release_msg = GetUsageInfoResponse(config_.license_server(),
config_.client_auth(), usage_info[i]);
EXPECT_EQ(NO_ERROR,
decryptor_->ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier))
<< i << "/" << usage_info.size() << " (err " << (error_count++) << ")"
<< release_msg;
}
ASSERT_LE(error_count, 100); // Give up after 100 failures.
status = decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
switch (status) {
case KEY_MESSAGE:
EXPECT_FALSE(usage_info.empty());
break;
case NO_ERROR:
EXPECT_TRUE(usage_info.empty());
break;
default:
FAIL() << "GetUsageInfo failed with error " << static_cast<int>(status);
break;
}
}
}
// This test verifies that sessions allocated internally during key release
// message generation are deallocated after their time to live period expires
// by timer events (if other sessions are open).
@@ -1342,215 +1280,6 @@ TEST_P(WvCdmStreamingNoPstTest, UsageTest) {
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingNoPstTest,
::testing::Values(0, 1, 2));
class WvCdmStreamingPstTest : public WvCdmExtendedDurationTest,
public ::testing::WithParamInterface<size_t> {};
TEST_P(WvCdmStreamingPstTest, UsageTest) {
Unprovision();
Provision();
decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false);
ValidateResponse(video_widevine::STREAMING, true);
int64_t initial_license_duration_remaining = 0;
int64_t initial_playback_duration_remaining = 0;
QueryKeyStatus(true, false, &initial_license_duration_remaining,
&initial_playback_duration_remaining);
sleep(kMinute);
int64_t expected_seconds_since_license_received = kMinute;
int64_t expected_seconds_since_initial_playback = 0;
int64_t expected_seconds_since_last_playback = 0;
for (size_t i = 0; i < GetParam(); ++i) {
// Decrypt data
SubSampleInfo* data = &kEncryptedStreamingClip8SubSample;
for (size_t i = 0; i < data->num_of_subsamples; i++) {
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&(data + i)->key_id, &(data + i)->encrypt_data.front(),
(data + i)->encrypt_data.size(), &(data + i)->iv,
(data + i)->block_offset, &decrypt_buffer[0]);
decryption_parameters.is_encrypted = (data + i)->is_encrypted;
decryption_parameters.is_secure = (data + i)->is_secure;
decryption_parameters.subsample_flags = (data + i)->subsample_flags;
EXPECT_EQ(NO_ERROR,
decryptor_->Decrypt(session_id_, (data + i)->validate_key_id,
decryption_parameters));
EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer);
}
sleep(kMinute);
expected_seconds_since_license_received += kMinute;
expected_seconds_since_initial_playback += kMinute;
expected_seconds_since_last_playback = kMinute;
}
// Query and validate usage information
int64_t license_duration_remaining = 0;
int64_t playback_duration_remaining = 0;
QueryKeyStatus(true, false, &license_duration_remaining,
&playback_duration_remaining);
if (initial_license_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining,
expected_seconds_since_license_received, kClockTolerance)
<< "initial_license_duration_remaining = "
<< initial_license_duration_remaining
<< ", license_duration_remaining = " << license_duration_remaining;
}
if (initial_playback_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance)
<< "initial_playback_duration_remaining = "
<< initial_playback_duration_remaining
<< ", playback_duration_remaining = " << playback_duration_remaining;
}
decryptor_->CloseSession(session_id_);
}
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingPstTest, ::testing::Values(0, 1, 2));
class WvCdmStreamingUsageReportTest
: public WvCdmExtendedDurationTest,
public ::testing::WithParamInterface<size_t> {};
TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
Unprovision();
Provision();
decryptor_->OpenSession(config_.key_system(), nullptr, kDefaultCdmIdentifier,
nullptr, &session_id_);
GenerateKeyRequest(kStreamingClip8PstInitData, kLicenseTypeStreaming);
VerifyKeyRequestResponse(config_.license_server(), config_.client_auth(),
false);
ValidateResponse(video_widevine::STREAMING, true);
int64_t initial_license_duration_remaining = 0;
int64_t initial_playback_duration_remaining = 0;
QueryKeyStatus(true, false, &initial_license_duration_remaining,
&initial_playback_duration_remaining);
sleep(kMinute);
int64_t expected_seconds_since_license_received = kMinute;
int64_t expected_seconds_since_initial_playback = 0;
int64_t expected_seconds_since_last_playback = 0;
for (size_t i = 0; i < GetParam(); ++i) {
// Decrypt data
SubSampleInfo* data = &kEncryptedStreamingClip8SubSample;
for (size_t i = 0; i < data->num_of_subsamples; i++) {
std::vector<uint8_t> decrypt_buffer((data + i)->encrypt_data.size());
CdmDecryptionParameters decryption_parameters(
&(data + i)->key_id, &(data + i)->encrypt_data.front(),
(data + i)->encrypt_data.size(), &(data + i)->iv,
(data + i)->block_offset, &decrypt_buffer[0]);
decryption_parameters.is_encrypted = (data + i)->is_encrypted;
decryption_parameters.is_secure = (data + i)->is_secure;
decryption_parameters.subsample_flags = (data + i)->subsample_flags;
EXPECT_EQ(NO_ERROR,
decryptor_->Decrypt(session_id_, (data + i)->validate_key_id,
decryption_parameters));
EXPECT_EQ((data + i)->decrypt_data, decrypt_buffer);
}
sleep(kMinute);
expected_seconds_since_license_received += kMinute;
expected_seconds_since_initial_playback += kMinute;
expected_seconds_since_last_playback = kMinute;
}
// Query and validate usage information
int64_t license_duration_remaining = 0;
int64_t playback_duration_remaining = 0;
QueryKeyStatus(true, false, &license_duration_remaining,
&playback_duration_remaining);
// For unlimited "rental durations", the "license duration" will
// effectively be unlimited. Remaining license duration in this
// case is represented by |kUnlimitedDurationValue| and will not
// change over time.
if (initial_license_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(license_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_license_duration_remaining - license_duration_remaining,
expected_seconds_since_license_received, kClockTolerance)
<< "initial_license_duration_remaining = "
<< initial_license_duration_remaining
<< ", license_duration_remaining = " << license_duration_remaining;
}
if (initial_playback_duration_remaining == kUnlimitedDurationValue) {
EXPECT_EQ(playback_duration_remaining, kUnlimitedDurationValue);
} else {
EXPECT_NEAR(initial_playback_duration_remaining - playback_duration_remaining,
expected_seconds_since_initial_playback, kClockTolerance)
<< "initial_playback_duration_remaining = "
<< initial_playback_duration_remaining
<< ", playback_duration_remaining = " << playback_duration_remaining;
}
decryptor_->CloseSession(session_id_);
// Create usage report and validate
CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status =
decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
int error_count = 0;
while (usage_info.size() > 0) {
for (size_t i = 0; i < usage_info.size(); ++i) {
ValidateReleaseRequest(usage_info[i],
expected_seconds_since_initial_playback != 0,
expected_seconds_since_license_received,
expected_seconds_since_initial_playback,
expected_seconds_since_last_playback);
release_msg = GetUsageInfoResponse(config_.license_server(),
config_.client_auth(), usage_info[i]);
EXPECT_EQ(NO_ERROR,
decryptor_->ReleaseUsageInfo(release_msg, kDefaultCdmIdentifier))
<< i << "/" << usage_info.size() << " (err " << (error_count++) << ")"
<< release_msg;
}
ASSERT_LE(error_count, 100); // Give up after 100 failures.
status = decryptor_->GetUsageInfo("", kDefaultCdmIdentifier, &usage_info);
switch (status) {
case KEY_MESSAGE:
EXPECT_FALSE(usage_info.empty());
break;
case NO_ERROR:
EXPECT_TRUE(usage_info.empty());
break;
default:
FAIL() << "GetUsageInfo failed with error " << static_cast<int>(status);
break;
}
}
// Validate that update usage table entry is exercised.
drm_metrics::WvCdmMetrics metrics;
ASSERT_EQ(NO_ERROR, decryptor_->GetMetrics(kDefaultCdmIdentifier, &metrics));
ValidateHasUpdateUsageEntry(metrics);
}
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmStreamingUsageReportTest,
::testing::Values(0, 1, 2));
class WvCdmOfflineUsageReportTest
: public WvCdmExtendedDurationTest,
public ::testing::WithParamInterface<size_t> {};

File diff suppressed because it is too large Load Diff

View File

@@ -47,8 +47,6 @@ using ::aidl::android::hardware::drm::KeyValue;
using ::aidl::android::hardware::drm::OfflineLicenseState;
using ::aidl::android::hardware::drm::ProvideProvisionResponseResult;
using ::aidl::android::hardware::drm::ProvisionRequest;
using ::aidl::android::hardware::drm::SecureStop;
using ::aidl::android::hardware::drm::SecureStopId;
using ::aidl::android::hardware::drm::SecurityLevel;
using ::aidl::android::hardware::drm::Status;
@@ -91,10 +89,7 @@ using wvcdm::CdmOfflineLicenseState;
using wvcdm::CdmProvisioningRequest;
using wvcdm::CdmProvisioningResponse;
using wvcdm::CdmQueryMap;
using wvcdm::CdmSecureStopId;
using wvcdm::CdmSecurityLevel;
using wvcdm::CdmUsageInfo;
using wvcdm::CdmUsageInfoReleaseMessage;
using wvcdm::EMPTY_ORIGIN;
using wvcdm::kCertificateWidevine;
using wvcdm::KEY_ID_SIZE;
@@ -222,22 +217,6 @@ public:
bool),
(override));
MOCK_METHOD(CdmResponseType, GetUsageInfo,
(const std::string &, const CdmIdentifier &, CdmUsageInfo *),
(override));
MOCK_METHOD(CdmResponseType, GetUsageInfo,
(const std::string &, const CdmSecureStopId &,
const CdmIdentifier &, CdmUsageInfo *),
(override));
MOCK_METHOD(CdmResponseType, RemoveAllUsageInfo,
(const std::string &, const CdmIdentifier &), (override));
MOCK_METHOD(CdmResponseType, ReleaseUsageInfo,
(const CdmUsageInfoReleaseMessage &, const CdmIdentifier &),
(override));
MOCK_METHOD(bool, IsValidServiceCertificate, (const std::string &),
(override));
@@ -980,75 +959,6 @@ TEST_F(WVDrmPluginHalTest, RejectsAtscUnprovisionDeviceRequests) {
ASSERT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
}
TEST_F(WVDrmPluginHalTest, GetsSecureStops) {
static const uint32_t kStopSize = 53;
static const uint32_t kStopCount = 7;
uint8_t stopsRaw[kStopCount][kStopSize];
FILE *fp = fopen("/dev/urandom", "r");
ASSERT_NE(fp, nullptr) << "Failed to open /dev/urandom";
for (uint32_t i = 0; i < kStopCount; ++i) {
fread(stopsRaw[i], sizeof(uint8_t), kStopSize, fp);
}
fclose(fp);
CdmUsageInfo mCdmStops;
for (uint32_t i = 0; i < kStopCount; ++i) {
mCdmStops.push_back(std::string(stopsRaw[i], stopsRaw[i] + kStopSize));
}
const char *app_id = "my_app_id";
EXPECT_CALL(*mCdm, GetUsageInfo(StrEq(app_id), _, _))
.WillOnce(
DoAll(SetArgPointee<2>(mCdmStops), testing::Return(wvcdm::NO_ERROR)));
auto ret =
mPlugin->setPropertyString(std::string("appId"), std::string(app_id));
EXPECT_TRUE(ret.isOk());
std::vector<SecureStop> secureStops;
ret = mPlugin->getSecureStops(&secureStops);
EXPECT_TRUE(ret.isOk());
std::vector<std::vector<uint8_t>> stops;
for (const auto &stop : secureStops) {
stops.push_back(stop.opaqueData);
}
size_t index = 0;
for (const auto &stop : stops) {
EXPECT_THAT(stop, ElementsAreArray(stopsRaw[index++], kStopSize));
}
EXPECT_EQ(kStopCount, index);
}
TEST_F(WVDrmPluginHalTest, ReleasesAllSecureStops) {
EXPECT_CALL(*mCdm, RemoveAllUsageInfo(StrEq(""), _)).Times(1);
auto ret = mPlugin->setPropertyString(std::string("appId"), "");
EXPECT_TRUE(ret.isOk());
ret = mPlugin->releaseAllSecureStops();
EXPECT_TRUE(ret.isOk());
}
TEST_F(WVDrmPluginHalTest, ReleasesSecureStop) {
static const uint32_t kMessageSize = 128;
uint8_t messageRaw[kMessageSize];
FILE *fp = fopen("/dev/urandom", "r");
ASSERT_NE(fp, nullptr) << "Failed to open /dev/urandom";
fread(messageRaw, sizeof(uint8_t), kMessageSize, fp);
fclose(fp);
EXPECT_CALL(*mCdm,
ReleaseUsageInfo(ElementsAreArray(messageRaw, kMessageSize), _))
.Times(1);
SecureStopId stopId;
stopId.secureStopId.assign(messageRaw, messageRaw + kMessageSize);
auto ret = mPlugin->releaseSecureStop(stopId);
EXPECT_TRUE(ret.isOk());
}
TEST_F(WVDrmPluginHalTest, ReturnsExpectedPropertyValues) {
CdmQueryMap l1Map;
l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1;

View File

@@ -59,16 +59,6 @@ using ::testing::Values;
using ::testing::WithParamInterface;
using ::testing::internal::ElementsAreArrayMatcher;
using wvcdm::kCertificateWidevine;
using wvcdm::kKeyRequestTypeInitial;
using wvcdm::kKeyRequestTypeRelease;
using wvcdm::kKeyRequestTypeRenewal;
using wvcdm::kLicenseTypeOffline;
using wvcdm::kLicenseTypeRelease;
using wvcdm::kLicenseTypeStreaming;
using wvcdm::kSecurityLevelL1;
using wvcdm::kSecurityLevelL3;
using wvutil::Base64Encode;
using wvcdm::CdmAppParameterMap;
using wvcdm::CdmCertificateType;
using wvcdm::CdmClientPropertySet;
@@ -84,10 +74,7 @@ using wvcdm::CdmOfflineLicenseState;
using wvcdm::CdmProvisioningRequest;
using wvcdm::CdmProvisioningResponse;
using wvcdm::CdmQueryMap;
using wvcdm::CdmSecureStopId;
using wvcdm::CdmSecurityLevel;
using wvcdm::CdmUsageInfo;
using wvcdm::CdmUsageInfoReleaseMessage;
using wvcdm::EMPTY_ORIGIN;
using wvcdm::kCertificateWidevine;
using wvcdm::KEY_ID_SIZE;
@@ -121,6 +108,7 @@ using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1;
using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3;
using wvcdm::SESSION_ID_PREFIX;
using wvcdm::WvCdmEventListener;
using wvutil::Base64Encode;
namespace {
const std::string kEmptyString;
@@ -204,21 +192,6 @@ class MockCDM : public WvContentDecryptionModule {
MOCK_METHOD(bool, IsProvisioned, (CdmSecurityLevel, const std::string&,
const std::string&, bool), (override));
MOCK_METHOD(CdmResponseType, GetUsageInfo, (const std::string&,
const CdmIdentifier&,
CdmUsageInfo*), (override));
MOCK_METHOD(CdmResponseType, GetUsageInfo, (const std::string&,
const CdmSecureStopId&,
const CdmIdentifier&,
CdmUsageInfo*), (override));
MOCK_METHOD(CdmResponseType, RemoveAllUsageInfo, (const std::string&,
const CdmIdentifier&), (override));
MOCK_METHOD(CdmResponseType, ReleaseUsageInfo,
(const CdmUsageInfoReleaseMessage&, const CdmIdentifier&), (override));
MOCK_METHOD(bool, IsValidServiceCertificate, (const std::string&), (override));
MOCK_METHOD(CdmResponseType, GetMetrics, (const CdmIdentifier&,
@@ -1144,96 +1117,6 @@ TEST_F(WVDrmPluginTest, RejectsAtscUnprovisionDeviceRequests) {
ASSERT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status);
}
TEST_F(WVDrmPluginTest, GetsSecureStops) {
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
StrictMock<MockCrypto> crypto;
std::string appPackageName;
static const uint32_t kStopSize = 53;
static const uint32_t kStopCount = 7;
uint8_t stopsRaw[kStopCount][kStopSize];
FILE* fp = fopen("/dev/urandom", "r");
for (uint32_t i = 0; i < kStopCount; ++i) {
fread(stopsRaw[i], sizeof(uint8_t), kStopSize, fp);
}
fclose(fp);
CdmUsageInfo cdmStops;
for (uint32_t i = 0; i < kStopCount; ++i) {
cdmStops.push_back(std::string(stopsRaw[i], stopsRaw[i] + kStopSize));
}
const char* app_id = "my_app_id";
EXPECT_CALL(*cdm, GetUsageInfo(StrEq(app_id), _, _))
.WillOnce(
DoAll(SetArgPointee<2>(cdmStops), testing::Return(wvcdm::NO_ERROR)));
std::vector<std::vector<uint8_t>> stops;
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
Status status =
plugin.setPropertyString(hidl_string("appId"), hidl_string(app_id));
ASSERT_EQ(Status::OK, status);
plugin.getSecureStops([&](Status status, hidl_vec<SecureStop> hSecureStops) {
ASSERT_EQ(Status::OK, status);
std::vector<SecureStop> secureStops(hSecureStops);
std::vector<SecureStop>::iterator iter = secureStops.begin();
std::vector<uint8_t> stop;
while (iter != secureStops.end()) {
stop = (*iter++).opaqueData;
stops.push_back(stop);
}
});
size_t index = 0;
for (auto stop : stops) {
EXPECT_THAT(stop, ElementsAreArray(stopsRaw[index++], kStopSize));
}
EXPECT_EQ(kStopCount, index);
}
TEST_F(WVDrmPluginTest, ReleasesAllSecureStops) {
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
StrictMock<MockCrypto> crypto;
std::string appPackageName;
EXPECT_CALL(*cdm, RemoveAllUsageInfo(StrEq(""), _)).Times(1);
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
Status status =
plugin.setPropertyString(hidl_string("appId"), hidl_string(""));
ASSERT_EQ(Status::OK, status);
status = plugin.releaseAllSecureStops();
ASSERT_EQ(Status::OK, status);
}
TEST_F(WVDrmPluginTest, ReleasesSecureStop) {
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
StrictMock<MockCrypto> crypto;
std::string appPackageName;
static const uint32_t kMessageSize = 128;
uint8_t messageRaw[kMessageSize];
FILE* fp = fopen("/dev/urandom", "r");
fread(messageRaw, sizeof(uint8_t), kMessageSize, fp);
fclose(fp);
std::vector<uint8_t> message;
message.assign(messageRaw, messageRaw + kMessageSize);
EXPECT_CALL(*cdm,
ReleaseUsageInfo(ElementsAreArray(messageRaw, kMessageSize), _))
.Times(1);
WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false);
Status status = plugin.releaseSecureStop(toHidlVec(message));
ASSERT_EQ(Status::OK, status);
}
TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) {
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
StrictMock<MockCrypto> crypto;