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

@@ -13,68 +13,69 @@
#include <sys/types.h>
#include <unistd.h>
#include "file_utils.h"
#include "log.h"
#include "string_conversions.h"
namespace {
const char kCurrentDirectory[] = ".";
const char kParentDirectory[] = "..";
const char kDirectoryDelimiter = '/';
const char kWildcard[] = "*";
bool IsCurrentOrParentDirectory(char* dir) {
return strcmp(dir, kCurrentDirectory) == 0 ||
strcmp(dir, kParentDirectory) == 0;
}
} // namespace
#include <openssl/md5.h>
#include <openssl/sha.h>
namespace wvcdm {
namespace {
const char kCertificateFileNamePrefix[] = "cert";
const char kCertificateFileNameExt[] = ".bin";
const char kCertificateFileName[] = "cert.bin";
std::string GetFileNameSafeHash(const std::string& input) {
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
const unsigned char* input_ptr =
reinterpret_cast<const unsigned char*>(input.data());
MD5(input_ptr, input.size(), &hash[0]);
return wvcdm::Base64SafeEncode(hash);
}
std::string GetFileNameForOrigin(const std::string path,
const std::string origin) {
std::string file_name = path;
std::string dir_path;
const size_t delimiter_pos = path.rfind(kDirectoryDelimiter);
if (delimiter_pos != std::string::npos) {
dir_path = file_name.substr(0, delimiter_pos);
file_name = path.substr(delimiter_pos + 1);
}
if (file_name == kCertificateFileName && !origin.empty()) {
const std::string hash = GetFileNameSafeHash(origin);
file_name = kCertificateFileNamePrefix + hash + kCertificateFileNameExt;
}
if (dir_path.empty())
return file_name;
else
return dir_path + kDirectoryDelimiter + file_name;
}
} // namespace
class File::Impl {
public:
Impl() : file_(NULL) {}
Impl(const std::string& file_path) : file_(NULL), file_path_(file_path) {}
Impl(FILE* file, const std::string& file_path)
: file_(file), file_path_(file_path) {}
virtual ~Impl() {}
FILE* file_;
std::string file_path_;
};
File::File() : impl_(new File::Impl()) {}
File::File(Impl* impl) : impl_(impl) {}
File::~File() {
Close();
delete impl_;
}
bool File::Open(const std::string& name, int flags) {
std::string open_flags;
// ensure only owners has access
mode_t old_mask = umask(077);
if (((flags & File::kTruncate) && Exists(name)) ||
((flags & File::kCreate) && !Exists(name))) {
FILE* fp = fopen(name.c_str(), "w+");
if (fp) {
fclose(fp);
}
}
if (flags & File::kBinary) {
open_flags = (flags & File::kReadOnly) ? "rb" : "rb+";
} else {
open_flags = (flags & File::kReadOnly) ? "r" : "r+";
}
impl_->file_ = fopen(name.c_str(), open_flags.c_str());
if (!impl_->file_) {
LOGW("File::Open: fopen failed: %d", errno);
}
impl_->file_path_ = name;
umask(old_mask);
return impl_->file_ != NULL;
}
void File::Close() {
if (impl_->file_){
if (impl_ && impl_->file_) {
fflush(impl_->file_);
fsync(fileno(impl_->file_));
fclose(impl_->file_);
@@ -83,7 +84,7 @@ void File::Close() {
}
ssize_t File::Read(char* buffer, size_t bytes) {
if (impl_->file_) {
if (impl_ && impl_->file_) {
size_t len = fread(buffer, sizeof(char), bytes, impl_->file_);
if (len == 0) {
LOGW("File::Read: fread failed: %d", errno);
@@ -95,7 +96,7 @@ ssize_t File::Read(char* buffer, size_t bytes) {
}
ssize_t File::Write(const char* buffer, size_t bytes) {
if (impl_->file_) {
if (impl_ && impl_->file_) {
size_t len = fwrite(buffer, sizeof(char), bytes, impl_->file_);
if (len == 0) {
LOGW("File::Write: fwrite failed: %d", errno);
@@ -106,194 +107,62 @@ ssize_t File::Write(const char* buffer, size_t bytes) {
return -1;
}
bool File::Exists(const std::string& path) {
struct stat buf;
int res = stat(path.c_str(), &buf) == 0;
if (!res) {
LOGV("File::Exists: stat failed: %d", errno);
}
return res;
class FileSystem::Impl {};
FileSystem::FileSystem() : FileSystem("", NULL) {}
FileSystem::FileSystem(const std::string& origin, void* /* extra_data */)
: origin_(origin) {
FileUtils::SecurityLevelPathBackwardCompatibility(kSecurityLevelL1);
FileUtils::SecurityLevelPathBackwardCompatibility(kSecurityLevelL3);
}
bool File::Remove(const std::string& path) {
if (IsDirectory(path)) {
// Handle directory deletion
DIR* dir;
if ((dir = opendir(path.c_str())) != NULL) {
// first remove files and dir within it
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (!IsCurrentOrParentDirectory(entry->d_name)) {
std::string path_to_remove = path + kDirectoryDelimiter;
path_to_remove += entry->d_name;
if (!Remove(path_to_remove)) {
closedir(dir);
return false;
}
}
}
closedir(dir);
}
if (rmdir(path.c_str())) {
LOGW("File::Remove: rmdir failed: %d", errno);
return false;
}
return true;
} else {
size_t wildcard_pos = path.find(kWildcard);
if (wildcard_pos == std::string::npos) {
// Handle file deletion
if (unlink(path.c_str()) && (errno != ENOENT)) {
LOGW("File::Remove: unlink failed: %d", errno);
return false;
}
} else {
// Handle wildcard specified file deletion
size_t delimiter_pos = path.rfind(kDirectoryDelimiter, wildcard_pos);
if (delimiter_pos == std::string::npos) {
LOGW("File::Remove: unable to find path delimiter before wildcard");
return false;
}
FileSystem::~FileSystem() {}
DIR* dir;
std::string dir_path = path.substr(0, delimiter_pos);
if ((dir = opendir(dir_path.c_str())) == NULL) {
LOGW("File::Remove: directory open failed for wildcard");
return false;
}
File* FileSystem::Open(const std::string& in_name, int flags) {
std::string open_flags;
struct dirent* entry;
std::string ext = path.substr(wildcard_pos + 1);
std::string name = GetFileNameForOrigin(in_name, origin_);
while ((entry = readdir(dir)) != NULL) {
size_t filename_len = strlen(entry->d_name);
if (filename_len > ext.size()) {
if (strcmp(entry->d_name + filename_len - ext.size(), ext.c_str()) ==
0) {
std::string file_path_to_remove =
dir_path + kDirectoryDelimiter + entry->d_name;
if (!Remove(file_path_to_remove)) {
closedir(dir);
return false;
}
}
}
}
closedir(dir);
}
return true;
}
}
bool File::Copy(const std::string& src, const std::string& dest) {
struct stat stat_buf;
if (stat(src.c_str(), &stat_buf)) {
LOGV("File::Copy: file %s stat error: %d", src.c_str(), errno);
return false;
// create the enclosing directory if it does not exist
size_t delimiter_pos = name.rfind(kDirectoryDelimiter);
if (delimiter_pos != std::string::npos) {
std::string dir_path = name.substr(0, delimiter_pos);
if ((flags & FileSystem::kCreate) && !Exists(dir_path))
FileUtils::CreateDirectory(dir_path);
}
int fd_src = open(src.c_str(), O_RDONLY);
if (fd_src < 0) {
LOGW("File::Copy: unable to open file %s: %d", src.c_str(), errno);
return false;
}
int fd_dest = open(dest.c_str(), O_WRONLY | O_CREAT, stat_buf.st_mode);
if (fd_dest < 0) {
LOGW("File::Copy: unable to open file %s: %d", dest.c_str(), errno);
close(fd_src);
return false;
}
off_t offset = 0;
bool status = true;
if (sendfile(fd_dest, fd_src, &offset, stat_buf.st_size) < 0) {
LOGV("File::Copy: unable to copy %s to %s: %d", src.c_str(), dest.c_str(),
errno);
status = false;
}
close(fd_src);
close(fd_dest);
return status;
}
bool File::List(const std::string& path, std::vector<std::string>* files) {
if (NULL == files) {
LOGV("File::List: files destination not provided");
return false;
}
if (!Exists(path)) {
LOGV("File::List: path %s does not exist: %d", path.c_str(), errno);
return false;
}
DIR* dir = opendir(path.c_str());
if (dir == NULL) {
LOGW("File::List: unable to open directory %s: %d", path.c_str(), errno);
return false;
}
files->clear();
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (!IsCurrentOrParentDirectory(entry->d_name)) {
files->push_back(entry->d_name);
// ensure only owners has access
mode_t old_mask = umask(077);
if (((flags & FileSystem::kTruncate) && Exists(name)) ||
((flags & FileSystem::kCreate) && !Exists(name))) {
FILE* fp = fopen(name.c_str(), "w+");
if (fp) {
fclose(fp);
}
}
closedir(dir);
return true;
}
open_flags = (flags & FileSystem::kReadOnly) ? "rb" : "rb+";
bool File::CreateDirectory(std::string path) {
size_t size = path.size();
if ((size == 1) && (path[0] == kDirectoryDelimiter)) return true;
if (size <= 1) return false;
size_t pos = path.find(kDirectoryDelimiter, 1);
while (pos < size) {
path[pos] = '\0';
if (mkdir(path.c_str(), 0700) != 0) {
if (errno != EEXIST) {
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
return false;
}
}
path[pos] = kDirectoryDelimiter;
pos = path.find(kDirectoryDelimiter, pos + 1);
FILE* file = fopen(name.c_str(), open_flags.c_str());
umask(old_mask);
if (!file) {
LOGW("File::Open: fopen failed: %d", errno);
return NULL;
}
if (path[size - 1] != kDirectoryDelimiter) {
if (mkdir(path.c_str(), 0700) != 0) {
if (errno != EEXIST) {
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
return false;
}
}
}
return true;
return new File(new File::Impl(file, name));
}
bool File::IsDirectory(const std::string& path) {
struct stat buf;
if (stat(path.c_str(), &buf) == 0)
return buf.st_mode & S_IFDIR;
else
return false;
bool FileSystem::Exists(const std::string& path) {
return FileUtils::Exists(GetFileNameForOrigin(path, origin_));
}
bool File::IsRegularFile(const std::string& path) {
struct stat buf;
if (stat(path.c_str(), &buf) == 0)
return buf.st_mode & S_IFREG;
else
return false;
bool FileSystem::Remove(const std::string& path) {
return FileUtils::Remove(GetFileNameForOrigin(path, origin_));
}
ssize_t File::FileSize(const std::string& path) {
ssize_t FileSystem::FileSize(const std::string& in_path) {
std::string path = GetFileNameForOrigin(in_path, origin_);
struct stat buf;
if (stat(path.c_str(), &buf) == 0)
return buf.st_size;
@@ -301,4 +170,6 @@ ssize_t File::FileSize(const std::string& path) {
return -1;
}
void FileSystem::SetOrigin(const std::string& origin) { origin_ = origin; }
} // namespace wvcdm

View File

@@ -0,0 +1,282 @@
// Copyright 2016 Google Inc. All Rights Reserved.
#include "file_utils.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "file_store.h"
#include "log.h"
#include "properties.h"
namespace {
const char* kSecurityLevelPathCompatibilityExclusionList[] = {
"ay64.dat", "ay64.dat2", "ay64.dat3"};
size_t kSecurityLevelPathCompatibilityExclusionListSize =
sizeof(kSecurityLevelPathCompatibilityExclusionList) /
sizeof(*kSecurityLevelPathCompatibilityExclusionList);
} // namespace
namespace wvcdm {
bool IsCurrentOrParentDirectory(char* dir) {
return strcmp(dir, kCurrentDirectory) == 0 ||
strcmp(dir, kParentDirectory) == 0;
}
bool FileUtils::Exists(const std::string& path) {
struct stat buf;
int res = stat(path.c_str(), &buf) == 0;
if (!res) {
LOGV("File::Exists: stat failed: %d", errno);
}
return res;
}
bool FileUtils::Remove(const std::string& path) {
if (FileUtils::IsDirectory(path)) {
// Handle directory deletion
DIR* dir;
if ((dir = opendir(path.c_str())) != NULL) {
// first remove files and dir within it
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (!IsCurrentOrParentDirectory(entry->d_name)) {
std::string path_to_remove = path + kDirectoryDelimiter;
path_to_remove += entry->d_name;
if (!Remove(path_to_remove)) {
closedir(dir);
return false;
}
}
}
closedir(dir);
}
if (rmdir(path.c_str())) {
LOGW("File::Remove: rmdir failed: %d", errno);
return false;
}
return true;
} else {
size_t wildcard_pos = path.find(kWildcard);
if (wildcard_pos == std::string::npos) {
// Handle file deletion
if (unlink(path.c_str()) && (errno != ENOENT)) {
LOGW("File::Remove: unlink failed: %d", errno);
return false;
}
} else {
// Handle wildcard specified file deletion
size_t delimiter_pos = path.rfind(kDirectoryDelimiter, wildcard_pos);
if (delimiter_pos == std::string::npos) {
LOGW("File::Remove: unable to find path delimiter before wildcard");
return false;
}
DIR* dir;
std::string dir_path = path.substr(0, delimiter_pos);
if ((dir = opendir(dir_path.c_str())) == NULL) {
LOGW("File::Remove: directory open failed for wildcard");
return false;
}
struct dirent* entry;
std::string ext = path.substr(wildcard_pos + 1);
while ((entry = readdir(dir)) != NULL) {
size_t filename_len = strlen(entry->d_name);
if (filename_len > ext.size()) {
if (strcmp(entry->d_name + filename_len - ext.size(), ext.c_str()) ==
0) {
std::string file_path_to_remove =
dir_path + kDirectoryDelimiter + entry->d_name;
if (!Remove(file_path_to_remove)) {
closedir(dir);
return false;
}
}
}
}
closedir(dir);
}
return true;
}
}
bool FileUtils::Copy(const std::string& src, const std::string& dest) {
struct stat stat_buf;
if (stat(src.c_str(), &stat_buf)) {
LOGV("File::Copy: file %s stat error: %d", src.c_str(), errno);
return false;
}
int fd_src = open(src.c_str(), O_RDONLY);
if (fd_src < 0) {
LOGW("File::Copy: unable to open file %s: %d", src.c_str(), errno);
return false;
}
int fd_dest = open(dest.c_str(), O_WRONLY | O_CREAT, stat_buf.st_mode);
if (fd_dest < 0) {
LOGW("File::Copy: unable to open file %s: %d", dest.c_str(), errno);
close(fd_src);
return false;
}
off_t offset = 0;
bool status = true;
if (sendfile(fd_dest, fd_src, &offset, stat_buf.st_size) < 0) {
LOGV("File::Copy: unable to copy %s to %s: %d", src.c_str(), dest.c_str(),
errno);
status = false;
}
close(fd_src);
close(fd_dest);
return status;
}
bool FileUtils::List(const std::string& path, std::vector<std::string>* files) {
if (NULL == files) {
LOGV("File::List: files destination not provided");
return false;
}
if (!FileUtils::Exists(path)) {
LOGV("File::List: path %s does not exist: %d", path.c_str(), errno);
return false;
}
DIR* dir = opendir(path.c_str());
if (dir == NULL) {
LOGW("File::List: unable to open directory %s: %d", path.c_str(), errno);
return false;
}
files->clear();
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
if (!IsCurrentOrParentDirectory(entry->d_name)) {
files->push_back(entry->d_name);
}
}
closedir(dir);
return true;
}
bool FileUtils::IsRegularFile(const std::string& path) {
struct stat buf;
if (stat(path.c_str(), &buf) == 0)
return buf.st_mode & S_IFREG;
else
return false;
}
bool FileUtils::IsDirectory(const std::string& path) {
struct stat buf;
if (stat(path.c_str(), &buf) == 0)
return buf.st_mode & S_IFDIR;
else
return false;
}
bool FileUtils::CreateDirectory(const std::string& path_in) {
std::string path = path_in;
size_t size = path.size();
if ((size == 1) && (path[0] == kDirectoryDelimiter)) return true;
if (size <= 1) return false;
size_t pos = path.find(kDirectoryDelimiter, 1);
while (pos < size) {
path[pos] = '\0';
if (mkdir(path.c_str(), 0700) != 0) {
if (errno != EEXIST) {
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
return false;
}
}
path[pos] = kDirectoryDelimiter;
pos = path.find(kDirectoryDelimiter, pos + 1);
}
if (path[size - 1] != kDirectoryDelimiter) {
if (mkdir(path.c_str(), 0700) != 0) {
if (errno != EEXIST) {
LOGW("File::CreateDirectory: mkdir failed: %d\n", errno);
return false;
}
}
}
return true;
}
void FileUtils::SecurityLevelPathBackwardCompatibility(
CdmSecurityLevel security_level) {
std::string path;
if (!Properties::GetDeviceFilesBasePath(security_level, &path)) {
LOGW("SecurityLevelPathBackwardCompatibility: Unable to get base path");
return;
}
std::vector<std::string> security_dirs;
if (!Properties::GetSecurityLevelDirectories(&security_dirs)) {
LOGW("SecurityLevelPathBackwardCompatibility: Unable to get security "
"directories");
return;
}
size_t pos = std::string::npos;
for (size_t i = 0; i < security_dirs.size(); ++i) {
pos = path.find(security_dirs[i]);
if (pos != std::string::npos && pos > 0 &&
pos == path.size() - security_dirs[i].size() &&
path[pos - 1] == kDirectoryDelimiter) {
break;
}
}
if (pos == std::string::npos) {
LOGV("SecurityLevelPathBackwardCompatibility: Security level specific path "
"not found. Check properties?");
return;
}
std::string from_dir(path, 0, pos);
std::vector<std::string> files;
if (!FileUtils::List(from_dir, &files)) {
return;
}
for (size_t i = 0; i < files.size(); ++i) {
std::string from = from_dir + files[i];
bool exclude = false;
for (size_t j = 0; j < kSecurityLevelPathCompatibilityExclusionListSize;
++j) {
if (files[i] == kSecurityLevelPathCompatibilityExclusionList[j]) {
exclude = true;
break;
}
}
if (exclude) continue;
if (!FileUtils::IsRegularFile(from)) continue;
for (size_t j = 0; j < security_dirs.size(); ++j) {
std::string to_dir = from_dir + security_dirs[j];
if (!FileUtils::Exists(to_dir)) FileUtils::CreateDirectory(to_dir);
std::string to = to_dir + files[i];
FileUtils::Copy(from, to);
}
FileUtils::Remove(from);
}
}
} // namespace wvcdm

View File

@@ -19,8 +19,7 @@ namespace wvcdm {
Lock WvContentDecryptionModule::session_sharing_id_generation_lock_;
WvContentDecryptionModule::WvContentDecryptionModule()
: cdm_engine_(new CdmEngine()) {}
WvContentDecryptionModule::WvContentDecryptionModule() {}
WvContentDecryptionModule::~WvContentDecryptionModule() {
DisablePolicyTimer(true);
@@ -52,19 +51,31 @@ CdmResponseType WvContentDecryptionModule::OpenSession(
property_set->set_session_sharing_id(GenerateSessionSharingId());
}
return cdm_engine_->OpenSession(key_system, property_set, origin,
event_listener, session_id);
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set,
event_listener, session_id);
if (sts == NO_ERROR) {
cdm_by_session_id_[*session_id] = cdm_engine;
}
return sts;
}
CdmResponseType WvContentDecryptionModule::CloseSession(
const CdmSessionId& session_id) {
CdmResponseType sts = cdm_engine_->CloseSession(session_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
// TODO(rfrias): Avoid reusing the error codes from CdmEngine.
if (!cdm_engine) return SESSION_NOT_FOUND_1;
CdmResponseType sts = cdm_engine->CloseSession(session_id);
if (sts == NO_ERROR) {
cdm_by_session_id_.erase(session_id);
}
DisablePolicyTimer(false);
return sts;
}
bool WvContentDecryptionModule::IsOpenSession(const CdmSessionId& session_id) {
return cdm_engine_->IsOpenSession(session_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
return cdm_engine && cdm_engine->IsOpenSession(session_id);
}
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
@@ -73,21 +84,24 @@ CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
const CdmLicenseType license_type, CdmAppParameterMap& app_parameters,
CdmClientPropertySet* property_set, const std::string& origin,
CdmKeyRequest* key_request) {
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
CdmResponseType sts;
if (license_type == kLicenseTypeRelease) {
sts = cdm_engine_->OpenKeySetSession(key_set_id, property_set, origin,
NULL);
sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, NULL);
if (sts != NO_ERROR) return sts;
cdm_by_session_id_[key_set_id] = cdm_engine;
}
InitializationData initialization_data(init_data_type, init_data);
sts = cdm_engine_->GenerateKeyRequest(
sts = cdm_engine->GenerateKeyRequest(
session_id, key_set_id, initialization_data, license_type, app_parameters,
key_request);
switch(license_type) {
case kLicenseTypeRelease:
if (sts != KEY_MESSAGE)
cdm_engine_->CloseKeySetSession(key_set_id);
if (sts != KEY_MESSAGE) {
cdm_engine->CloseKeySetSession(key_set_id);
cdm_by_session_id_.erase(key_set_id);
}
break;
default:
if (sts == KEY_MESSAGE)
@@ -101,16 +115,23 @@ CdmResponseType WvContentDecryptionModule::AddKey(
const CdmSessionId& session_id,
const CdmKeyResponse& key_data,
CdmKeySetId* key_set_id) {
CdmResponseType sts = cdm_engine_->AddKey(session_id, key_data, key_set_id);
if (sts == KEY_ADDED && session_id.empty()) // license type release
cdm_engine_->CloseKeySetSession(*key_set_id);
CdmEngine* cdm_engine = session_id.empty() ? GetCdmForSessionId(*key_set_id)
: GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_3;
CdmResponseType sts = cdm_engine->AddKey(session_id, key_data, key_set_id);
if (sts == KEY_ADDED && session_id.empty()) { // license type release
cdm_engine->CloseKeySetSession(*key_set_id);
cdm_by_session_id_.erase(*key_set_id);
}
return sts;
}
CdmResponseType WvContentDecryptionModule::RestoreKey(
const CdmSessionId& session_id,
const CdmKeySetId& key_set_id) {
CdmResponseType sts = cdm_engine_->RestoreKey(session_id, key_set_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_4;
CdmResponseType sts = cdm_engine->RestoreKey(session_id, key_set_id);
if (sts == KEY_ADDED)
EnablePolicyTimer();
return sts;
@@ -118,29 +139,38 @@ CdmResponseType WvContentDecryptionModule::RestoreKey(
CdmResponseType WvContentDecryptionModule::RemoveKeys(
const CdmSessionId& session_id) {
return cdm_engine_->RemoveKeys(session_id);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_5;
return cdm_engine->RemoveKeys(session_id);
}
CdmResponseType WvContentDecryptionModule::QueryStatus(
SecurityLevel security_level,
const std::string& key,
std::string* value) {
return cdm_engine_->QueryStatus(security_level, key, value);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->QueryStatus(security_level, key, value);
}
CdmResponseType WvContentDecryptionModule::QuerySessionStatus(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
return cdm_engine_->QuerySessionStatus(session_id, key_info);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_8;
return cdm_engine->QuerySessionStatus(session_id, key_info);
}
CdmResponseType WvContentDecryptionModule::QueryKeyStatus(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
return cdm_engine_->QueryKeyStatus(session_id, key_info);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_9;
return cdm_engine->QueryKeyStatus(session_id, key_info);
}
CdmResponseType WvContentDecryptionModule::QueryKeyControlInfo(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
return cdm_engine_->QueryKeyControlInfo(session_id, key_info);
CdmResponseType WvContentDecryptionModule::QueryOemCryptoSessionId(
const CdmSessionId& session_id, CdmQueryMap* response) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_10;
return cdm_engine->QueryOemCryptoSessionId(session_id, response);
}
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
@@ -149,8 +179,9 @@ CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
const std::string& origin,
CdmProvisioningRequest* request,
std::string* default_url) {
return cdm_engine_->GetProvisioningRequest(cert_type, cert_authority, origin,
request, default_url);
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
return cdm_engine->GetProvisioningRequest(cert_type, cert_authority, request,
default_url);
}
CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
@@ -158,59 +189,70 @@ CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
CdmProvisioningResponse& response,
std::string* cert,
std::string* wrapped_key) {
return cdm_engine_->HandleProvisioningResponse(origin, response, cert,
wrapped_key);
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
return cdm_engine->HandleProvisioningResponse(response, cert, wrapped_key);
}
CdmResponseType WvContentDecryptionModule::Unprovision(
CdmSecurityLevel level,
const std::string& origin) {
return cdm_engine_->Unprovision(level, origin);
CdmSecurityLevel level, const std::string& origin) {
CdmEngine* cdm_engine = EnsureCdmForOrigin(origin);
return cdm_engine->Unprovision(level);
}
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id, CdmUsageInfo* usage_info) {
return cdm_engine_->GetUsageInfo(app_id, usage_info);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->GetUsageInfo(app_id, usage_info);
}
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id,
const CdmSecureStopId& ssid,
CdmUsageInfo* usage_info) {
return cdm_engine_->GetUsageInfo(app_id, ssid, usage_info);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->GetUsageInfo(app_id, ssid, usage_info);
}
CdmResponseType WvContentDecryptionModule::ReleaseAllUsageInfo(
const std::string& app_id) {
return cdm_engine_->ReleaseAllUsageInfo(app_id);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->ReleaseAllUsageInfo(app_id);
}
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) {
return cdm_engine_->ReleaseUsageInfo(message);
CdmEngine* cdm_engine = EnsureCdmForOrigin(EMPTY_ORIGIN);
return cdm_engine->ReleaseUsageInfo(message);
}
CdmResponseType WvContentDecryptionModule::Decrypt(
const CdmSessionId& session_id,
bool validate_key_id,
const CdmDecryptionParameters& parameters) {
// First find the CdmEngine that has the given session_id. If we are using
// key sharing, the shared session will still be in the same CdmEngine.
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_FOR_DECRYPT;
CdmSessionId local_session_id = session_id;
if (validate_key_id &&
Properties::GetSessionSharingId(session_id) != 0) {
bool status = cdm_engine_->FindSessionForKey(*parameters.key_id,
bool status = cdm_engine->FindSessionForKey(*parameters.key_id,
&local_session_id);
if (!status) {
LOGE("WvContentDecryptionModule::Decrypt: unable to find session");
return NEED_KEY;
return SESSION_NOT_FOUND_FOR_DECRYPT;
}
}
return cdm_engine_->Decrypt(local_session_id, parameters);
return cdm_engine->Decrypt(local_session_id, parameters);
}
void WvContentDecryptionModule::NotifyResolution(const CdmSessionId& session_id,
uint32_t width,
uint32_t height) {
cdm_engine_->NotifyResolution(session_id, width, height);
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return;
cdm_engine->NotifyResolution(session_id, width, height);
}
bool WvContentDecryptionModule::IsValidServiceCertificate(
@@ -218,6 +260,27 @@ bool WvContentDecryptionModule::IsValidServiceCertificate(
return CdmLicense::VerifySignedServiceCertificate(certificate) == NO_ERROR;
}
WvContentDecryptionModule::CdmInfo::CdmInfo()
: cdm_engine(new CdmEngine(&file_system)) {}
CdmEngine* WvContentDecryptionModule::EnsureCdmForOrigin(
const std::string& origin) {
if (cdms_.find(origin) == cdms_.end()) {
// Will create a new instance using the default constructor.
cdms_[origin].file_system.SetOrigin(origin);
}
return cdms_[origin].cdm_engine.get();
}
CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
const std::string& session_id) {
// Use find to avoid creating empty entries when not found.
auto it = cdm_by_session_id_.find(session_id);
if (it == cdm_by_session_id_.end()) return NULL;
return it->second;
}
void WvContentDecryptionModule::EnablePolicyTimer() {
AutoLock auto_lock(policy_timer_lock_);
if (!policy_timer_.IsRunning())
@@ -226,12 +289,25 @@ void WvContentDecryptionModule::EnablePolicyTimer() {
void WvContentDecryptionModule::DisablePolicyTimer(bool force) {
AutoLock auto_lock(policy_timer_lock_);
if ((cdm_engine_->SessionSize() == 0 || force) && policy_timer_.IsRunning())
bool has_sessions = false;
for (auto it = cdms_.begin(); it != cdms_.end();) {
if (it->second.cdm_engine->SessionSize() != 0) {
has_sessions = true;
++it;
} else {
// The CDM is no longer used for this origin, delete it.
it = cdms_.erase(it);
}
}
if ((!has_sessions || force) && policy_timer_.IsRunning())
policy_timer_.Stop();
}
void WvContentDecryptionModule::OnTimerEvent() {
cdm_engine_->OnTimerEvent();
for (auto it = cdms_.begin(); it != cdms_.end(); ++it) {
it->second.cdm_engine->OnTimerEvent();
}
}
uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {