Refine TwoHundredEntries tests

Merge from Widevine repo of http://go/wvgerrit/58440

This CL modifies the oemcrypto test TwoHundredEntries so that it
attempts to create more than 200 entries.  A device is allowed to fail
when such an attempt is made, but it must return an insufficient
resources error.

The test then verifies that each of the entries that were succesfully
created can be used to reload its license and the keys can be used for
decryption.

It then shrinks the usage table header, and verifies that the
remaining licenses can still be used for decryption.

bug: 112486006
test: unit tests (test code only)
Change-Id: I6e6edfb00f0553724e0f99fb4e5ea5c817450937
This commit is contained in:
Fred Gylys-Colwell
2018-08-21 13:37:44 -07:00
parent a20034e3a2
commit a963e90bb8
3 changed files with 101 additions and 64 deletions

View File

@@ -24,6 +24,7 @@
#include <iostream>
#include <map>
#include <string>
#include <sstream>
#include <utility>
#include <vector>
@@ -4684,66 +4685,6 @@ TEST_F(UsageTableTest, OnlineMissingEntry) {
ASSERT_NO_FATAL_FAILURE(s.close());
}
TEST_F(UsageTableTest, TwoHundredEntries) {
Session s1;
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&s1));
std::string pst1 = "pst saved";
ASSERT_NO_FATAL_FAILURE(s1.FillSimpleMessage(
0, wvoec_mock::kControlNonceEnabled | wvoec_mock::kControlNonceRequired,
s1.get_nonce(), pst1));
ASSERT_NO_FATAL_FAILURE(s1.EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(s1.CreateNewUsageEntry());
ASSERT_EQ(0u, s1.usage_entry_number());
time_t start = time(NULL);
ASSERT_NO_FATAL_FAILURE(s1.LoadTestKeys(pst1, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s1.close());
// API says should hold at least 200 entries. Subtract one for s1's entry.
const size_t ENTRY_COUNT = 200 - 1;
vector<Session> sessions(ENTRY_COUNT);
for (size_t i = 0; i < ENTRY_COUNT; i++) {
ASSERT_NO_FATAL_FAILURE(sessions[i].open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i]));
std::string pst = "pst ";
char c1 = 'A' + (i/26);
char c2 = 'A' + (i%26);
pst = pst + c1 + c2;
ASSERT_NO_FATAL_FAILURE(sessions[i].FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, sessions[i].get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(sessions[i].EncryptAndSign());
ASSERT_NO_FATAL_FAILURE(sessions[i].CreateNewUsageEntry());
ASSERT_EQ(sessions[i].usage_entry_number(), i + 1);
ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(
sessions[i].UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(sessions[i].close());
}
sleep(kShortSleep);
for (size_t i = 0; i < ENTRY_COUNT; i++) {
ASSERT_NO_FATAL_FAILURE(sessions[i].open());
std::string pst = "pst ";
char c1 = 'A' + (i/26);
char c2 = 'A' + (i%26);
pst = pst + c1 + c2;
// Reuse license message created above.
ASSERT_NO_FATAL_FAILURE(sessions[i].ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i]));
ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_))
<< "Failed to reload license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(
sessions[i].UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(sessions[i].close());
}
// Make sure s1's entry is still in the table.
ASSERT_NO_FATAL_FAILURE(s1.open());
ASSERT_NO_FATAL_FAILURE(s1.ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(s1.UpdateUsageEntry(&encrypted_usage_header_));
ASSERT_NO_FATAL_FAILURE(s1.GenerateVerifyReport(pst1, kUnused, start));
ASSERT_NO_FATAL_FAILURE(s1.close());
}
TEST_P(UsageTableTestWithMAC, GenericCryptoEncrypt) {
std::string pst = "A PST";
uint32_t nonce = session_.get_nonce();
@@ -5418,6 +5359,95 @@ TEST_F(UsageTableDefragTest, ReloadUsageEntryBadData) {
&data[0], data.size()));
}
static std::string MakePST(size_t n) {
std::stringstream stream;
stream << "pst-" << n;
return stream.str();
}
TEST_F(UsageTableDefragTest, TwoHundredEntries) {
// OEMCrypto is required to store at least 200 entries in the usage table
// header, but it is allowed to store more. This test verifies that if we keep
// adding entries, the error indicates a resource limit. It then verifies
// that all of the successful entries are still valid after we throw out the
// last invalid entry.
const size_t ENTRY_COUNT = 2000;
vector<Session> sessions(ENTRY_COUNT);
size_t successful_count = 0;
for (size_t i = 0; i < ENTRY_COUNT; i++) {
if (i % 50 == 0) LOGD("Creating license %zd", i);
ASSERT_NO_FATAL_FAILURE(sessions[i].open());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i]));
std::string pst = MakePST(i);
ASSERT_NO_FATAL_FAILURE(sessions[i].FillSimpleMessage(
0, wvoec_mock::kControlNonceOrEntry, sessions[i].get_nonce(), pst));
ASSERT_NO_FATAL_FAILURE(sessions[i].EncryptAndSign());
// We attempt to create a new usage table entry for this session.
OEMCryptoResult status;
ASSERT_NO_FATAL_FAILURE(sessions[i].CreateNewUsageEntry(&status));
if (status == OEMCrypto_SUCCESS) {
ASSERT_EQ(sessions[i].usage_entry_number(), i);
ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_));
ASSERT_NO_FATAL_FAILURE(
sessions[i].UpdateUsageEntry(&encrypted_usage_header_));
successful_count++;
} else {
// If we failed to create this many entries because of limited resources,
// then the error returned should be insufficient resources.
EXPECT_EQ(OEMCrypto_ERROR_INSUFFICIENT_RESOURCES, status)
<< "Failed to create license " << i << " with pst = " << pst;
break;
}
ASSERT_NO_FATAL_FAILURE(sessions[i].close());
}
LOGD("successful_count = %d", successful_count);
EXPECT_GE(successful_count, 200u);
sleep(kShortSleep);
// Now we will loop through each valid entry, and verify that we can still
// reload the license and perform a decrypt.
for (size_t i = 0; i < successful_count; i++) {
if (i % 50 == 0) LOGD("Reloading license %zd", i);
ASSERT_NO_FATAL_FAILURE(sessions[i].open());
std::string pst = MakePST(i);
// Reuse license message created above.
ASSERT_NO_FATAL_FAILURE(sessions[i].ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i]));
ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_))
<< "Failed to reload license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(
sessions[i].UpdateUsageEntry(&encrypted_usage_header_))
<< "Failed to update license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(sessions[i].TestDecryptCTR())
<< "Failed to use license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(
sessions[i].UpdateUsageEntry(&encrypted_usage_header_))
<< "Failed to update license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(sessions[i].close());
}
// We also need to verify that a full table can be shrunk, and the remaining
// licenses still work.
size_t smaller_size = 10u; // 10 is smaller than 200.
ASSERT_NO_FATAL_FAILURE(ShrinkHeader(smaller_size));
for (size_t i = 0; i < smaller_size; i++) {
ASSERT_NO_FATAL_FAILURE(sessions[i].open());
std::string pst = MakePST(i);
// Reuse license message created above.
ASSERT_NO_FATAL_FAILURE(sessions[i].ReloadUsageEntry());
ASSERT_NO_FATAL_FAILURE(InstallTestSessionKeys(&sessions[i]));
ASSERT_NO_FATAL_FAILURE(sessions[i].LoadTestKeys(pst, new_mac_keys_))
<< "Failed to reload license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(
sessions[i].UpdateUsageEntry(&encrypted_usage_header_))
<< "Failed to update license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(sessions[i].TestDecryptCTR())
<< "Failed to use license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(
sessions[i].UpdateUsageEntry(&encrypted_usage_header_))
<< "Failed to update license " << i << " with pst = " << pst;
ASSERT_NO_FATAL_FAILURE(sessions[i].close());
}
}
TEST_F(UsageTableTest, CopyOldEntries) {
// First create three old entries. We open sessions first to force creation
// of the mac keys.