File util, generic crypto, and key query

This CL merges several CLs from the widevine repo:

http://go/wvgerrit/18012 Add support for querying allowed usage for key.
http://go/wvgerrit/17971 Add per-origin storage.
http://go/wvgerrit/18152 Add OEMCrypto's generic crypto operations to CDM.
http://go/wvgerrit/17911 QueryKeyControlInfo => QueryOemCryptoSessionId

Note: numbering in wv_cdm_types.h was added in this CL and will be
back ported to wvgerrit in a future CL.

Change-Id: Idb9e9a67e94f62f25dc16c5307f75a08b3430b64
This commit is contained in:
Fred Gylys-Colwell
2016-09-14 12:44:09 -07:00
parent 24124ea6e3
commit eb3f8b786a
56 changed files with 4632 additions and 2083 deletions

View File

@@ -11,6 +11,7 @@
#include "config_test_env.h"
#include "device_files.h"
#include "file_store.h"
#include "file_utils.h"
#include "license_protocol.pb.h"
#include "license_request.h"
#include "log.h"
@@ -47,6 +48,8 @@ const int kHttpOk = 200;
const int kHttpBadRequest = 400;
const int kHttpInternalServerError = 500;
const char kOrigin[] = "com.example";
// Protobuf generated classes
using video_widevine_server::sdk::LicenseIdentification;
using video_widevine_server::sdk::LicenseRequest_ContentIdentification;
@@ -1136,6 +1139,10 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
void Provision(SecurityLevel level) {
Provision(EMPTY_ORIGIN, level);
}
void Provision(const std::string& origin, SecurityLevel level) {
TestWvCdmClientPropertySet property_set_L3;
TestWvCdmClientPropertySet* property_set = NULL;
@@ -1145,7 +1152,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
}
CdmResponseType status = decryptor_.OpenSession(
g_key_system, property_set, EMPTY_ORIGIN, NULL, &session_id_);
g_key_system, property_set, origin, NULL, &session_id_);
switch (status) {
case NO_ERROR:
decryptor_.CloseSession(session_id_);
@@ -1162,7 +1169,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
std::string cert_authority, cert, wrapped_key;
status = decryptor_.GetProvisioningRequest(cert_type, cert_authority,
EMPTY_ORIGIN, &key_msg_,
origin, &key_msg_,
&provisioning_server_url);
EXPECT_EQ(wvcdm::NO_ERROR, status);
if (NO_ERROR != status) return;
@@ -1172,7 +1179,7 @@ class WvCdmRequestLicenseTest : public WvCdmTestBase {
GetCertRequestResponse(g_config->provisioning_server_url());
EXPECT_NE(0, static_cast<int>(response.size()));
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.HandleProvisioningResponse(EMPTY_ORIGIN, response,
decryptor_.HandleProvisioningResponse(origin, response,
&cert, &wrapped_key));
EXPECT_EQ(0, static_cast<int>(cert.size()));
EXPECT_EQ(0, static_cast<int>(wrapped_key.size()));
@@ -1238,20 +1245,57 @@ TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
decryptor_.CloseSession(session_id_);
}
TEST_F(WvCdmRequestLicenseTest, PerOriginProvisioningTest) {
EXPECT_EQ(NO_ERROR, decryptor_.Unprovision(kSecurityLevelL3, kOrigin));
// Verify the empty origin is provisioned.
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, NULL,
&session_id_));
decryptor_.CloseSession(session_id_);
// The other origin should not be provisioned.
EXPECT_EQ(
wvcdm::NEED_PROVISIONING,
decryptor_.OpenSession(g_key_system, NULL, kOrigin, NULL, &session_id_));
}
TEST_F(WvCdmRequestLicenseTest, PerOriginProvisioningSupportsOldPaths) {
// This is the current file name scheme. This test exists to ensure we do
// not break existing clients if we decide to change the naming/paths of
// certificates.
const char kOldFileName[] = "cert0LF0GfM75iqlNA_sByaQMA==.bin";
ASSERT_EQ("com.example", kOrigin);
// Unprovision the device and delete all files.
EXPECT_EQ(NO_ERROR, decryptor_.Unprovision(kSecurityLevelL3, kOrigin));
EXPECT_EQ(NO_ERROR, decryptor_.Unprovision(kSecurityLevelL3, EMPTY_ORIGIN));
Provision(kOrigin, kLevel3);
std::string base_path;
ASSERT_TRUE(Properties::GetDeviceFilesBasePath(kSecurityLevelL3, &base_path));
// Make sure that the cert exists.
std::vector<std::string> files;
ASSERT_TRUE(FileUtils::List(base_path, &files));
ASSERT_EQ(1u, files.size());
EXPECT_EQ(kOldFileName, files[0]);
// Reprovision the empty origin.
Provision(EMPTY_ORIGIN, kLevel3);
}
TEST_F(WvCdmRequestLicenseTest, UnprovisionTest) {
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
DeviceFiles handle;
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
File file;
handle.SetTestFile(&file);
std::string certificate;
std::string wrapped_private_key;
EXPECT_TRUE(handle.RetrieveCertificate(EMPTY_ORIGIN, &certificate,
&wrapped_private_key));
EXPECT_TRUE(handle.RetrieveCertificate(&certificate, &wrapped_private_key));
EXPECT_EQ(NO_ERROR, decryptor_.Unprovision(security_level, EMPTY_ORIGIN));
EXPECT_FALSE(handle.RetrieveCertificate(EMPTY_ORIGIN, &certificate,
&wrapped_private_key));
EXPECT_FALSE(handle.RetrieveCertificate(&certificate, &wrapped_private_key));
}
TEST_F(WvCdmRequestLicenseTest, ProvisioningInterposedRetryTest) {
@@ -1437,10 +1481,9 @@ TEST_F(WvCdmRequestLicenseTest, ForceL3Test) {
TestWvCdmClientPropertySet property_set;
property_set.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
File file;
DeviceFiles handle;
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(kSecurityLevelL3));
handle.SetTestFile(&file);
EXPECT_TRUE(handle.DeleteAllFiles());
EXPECT_EQ(NEED_PROVISIONING,
@@ -2151,10 +2194,9 @@ TEST_P(WvCdmUsageTest, WithClientId) {
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
std::string app_id = "";
DeviceFiles handle;
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
File file;
handle.SetTestFile(&file);
std::vector<std::string> psts;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(app_id, &psts));
@@ -2269,10 +2311,9 @@ TEST_F(WvCdmRequestLicenseTest, UsageInfoRetryTest) {
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
std::string app_id = "";
DeviceFiles handle;
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
File file;
handle.SetTestFile(&file);
std::vector<std::string> psts;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(app_id, &psts));
@@ -2351,10 +2392,9 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
}
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
DeviceFiles handle;
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
File file;
handle.SetTestFile(&file);
std::vector<std::string> psts;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp(usage_info_data->app_id, &psts));
@@ -2425,10 +2465,9 @@ TEST_F(WvCdmRequestLicenseTest, UsageReleaseAllTest) {
Provision(kLevelDefault);
CdmSecurityLevel security_level = GetDefaultSecurityLevel();
DeviceFiles handle;
FileSystem file_system;
DeviceFiles handle(&file_system);
EXPECT_TRUE(handle.Init(security_level));
File file;
handle.SetTestFile(&file);
std::vector<std::string> psts;
EXPECT_TRUE(handle.DeleteAllUsageInfoForApp("", &psts));
@@ -2739,7 +2778,7 @@ TEST_F(WvCdmRequestLicenseTest, QueryStatusL3) {
EXPECT_LE(10u, api_version);
}
TEST_F(WvCdmRequestLicenseTest, QueryKeyControlInfo) {
TEST_F(WvCdmRequestLicenseTest, QueryOemCryptoSessionId) {
Unprovision();
Provision(kLevelDefault);
@@ -2750,7 +2789,7 @@ TEST_F(WvCdmRequestLicenseTest, QueryKeyControlInfo) {
CdmQueryMap query_info;
CdmQueryMap::iterator itr;
EXPECT_EQ(wvcdm::NO_ERROR,
decryptor_.QueryKeyControlInfo(session_id_, &query_info));
decryptor_.QueryOemCryptoSessionId(session_id_, &query_info));
uint32_t oem_crypto_session_id;
itr = query_info.find(wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID);
@@ -2797,14 +2836,16 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
if (std::string::npos != pos) break;
}
// Delete any old files.
EXPECT_NE(std::string::npos, pos);
std::string old_base_path(base_path, 0, pos);
File file;
FileSystem file_system;
for (size_t i = 0; i < security_dirs.size(); i++) {
std::string path = old_base_path + kPathDelimiter + security_dirs[i];
file.Remove(path);
file_system.Remove(path);
}
// Provision the device to create any required files.
decryptor_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, NULL, &session_id_);
std::string provisioning_server_url;
CdmCertificateType cert_type = kCertificateWidevine;
@@ -2821,9 +2862,10 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
decryptor_.CloseSession(session_id_);
std::vector<std::string> files;
EXPECT_TRUE(file.List(base_path, &files));
EXPECT_TRUE(FileUtils::List(base_path, &files));
size_t number_of_files = files.size();
// Create an offline license to create license files.
decryptor_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, NULL, &session_id_);
GenerateKeyRequest(key_id, kLicenseTypeOffline);
VerifyKeyRequestResponse(g_license_server, client_auth, false);
@@ -2831,23 +2873,30 @@ TEST_F(WvCdmRequestLicenseTest, SecurityLevelPathBackwardCompatibility) {
EXPECT_FALSE(key_set_id_.empty());
decryptor_.CloseSession(session_id_);
EXPECT_TRUE(file.List(base_path, &files));
EXPECT_TRUE(FileUtils::List(base_path, &files));
int number_of_new_files = files.size() - number_of_files;
// There should be a new license file, and maybe a new usage table
// file.
EXPECT_LE(1, number_of_new_files);
EXPECT_GE(2, number_of_new_files);
// Move files to the old location.
for (size_t i = 0; i < files.size(); ++i) {
std::string from = base_path + files[i];
if (file.IsRegularFile(from)) {
if (FileUtils::IsRegularFile(from)) {
std::string to = old_base_path + files[i];
EXPECT_TRUE(file.Copy(from, to));
EXPECT_TRUE(FileUtils::Copy(from, to));
}
}
EXPECT_TRUE(file.Remove(base_path));
EXPECT_TRUE(file_system.Remove(base_path));
//// Setup complete to earlier version (non-security level based) path.
// Create a new file system. This will cause the files to be moved over.
// Normally this will happen when the plugin is created, but since we are
// reusing the same decryptor, we need it to update here.
FileSystem dummy_file_system;
// Setup complete to earlier version (non-security level based) path.
// Restore persistent license, retrieve L1, L3 streaming licenses to verify
session_id_.clear();
decryptor_.OpenSession(g_key_system, NULL, EMPTY_ORIGIN, NULL, &session_id_);