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:
@@ -34,19 +34,13 @@ using video_widevine_client::sdk::UsageInfo_ProviderSession;
|
||||
|
||||
namespace {
|
||||
|
||||
const char kCertificateFileNamePrefix[] = "cert";
|
||||
const char kCertificateFileNameExt[] = ".bin";
|
||||
const char kCertificateFileName[] = "cert.bin";
|
||||
const char kHlsAttributesFileNameExt[] = ".hal";
|
||||
const char kUsageInfoFileNamePrefix[] = "usage";
|
||||
const char kUsageInfoFileNameExt[] = ".bin";
|
||||
const char kLicenseFileNameExt[] = ".lic";
|
||||
const char kEmptyFileName[] = "";
|
||||
const char kWildcard[] = "*";
|
||||
const char kDirectoryDelimiter = '/';
|
||||
const char* kSecurityLevelPathCompatibilityExclusionList[] = {
|
||||
"ay64.dat", "ay64.dat2", "ay64.dat3"};
|
||||
size_t kSecurityLevelPathCompatibilityExclusionListSize =
|
||||
sizeof(kSecurityLevelPathCompatibilityExclusionList) /
|
||||
sizeof(*kSecurityLevelPathCompatibilityExclusionList);
|
||||
|
||||
bool Hash(const std::string& data, std::string* hash) {
|
||||
if (!hash) return false;
|
||||
@@ -66,30 +60,30 @@ namespace wvcdm {
|
||||
// static
|
||||
std::set<std::string> DeviceFiles::reserved_license_ids_;
|
||||
|
||||
DeviceFiles::DeviceFiles()
|
||||
: file_(NULL),
|
||||
DeviceFiles::DeviceFiles(FileSystem* file_system)
|
||||
: file_system_(file_system),
|
||||
security_level_(kSecurityLevelUninitialized),
|
||||
initialized_(false),
|
||||
test_file_(false) {}
|
||||
initialized_(false) {}
|
||||
|
||||
DeviceFiles::~DeviceFiles() {
|
||||
if (test_file_) file_.release();
|
||||
}
|
||||
DeviceFiles::~DeviceFiles() {}
|
||||
|
||||
bool DeviceFiles::Init(CdmSecurityLevel security_level) {
|
||||
if (!file_system_) {
|
||||
LOGD("DeviceFiles::Init: Invalid FileSystem given.");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level, &path)) {
|
||||
LOGW("DeviceFiles::Init: Unsupported security level %d", security_level);
|
||||
return false;
|
||||
}
|
||||
if (!test_file_) file_.reset(new File());
|
||||
security_level_ = security_level;
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreCertificate(const std::string& origin,
|
||||
const std::string& certificate,
|
||||
bool DeviceFiles::StoreCertificate(const std::string& certificate,
|
||||
const std::string& wrapped_private_key) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::StoreCertificate: not initialized");
|
||||
@@ -109,23 +103,18 @@ bool DeviceFiles::StoreCertificate(const std::string& origin,
|
||||
std::string serialized_file;
|
||||
file.SerializeToString(&serialized_file);
|
||||
|
||||
return StoreFileWithHash(GetCertificateFileName(origin), serialized_file);
|
||||
return StoreFileWithHash(GetCertificateFileName(), serialized_file);
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveCertificate(const std::string& origin,
|
||||
std::string* certificate,
|
||||
bool DeviceFiles::RetrieveCertificate(std::string* certificate,
|
||||
std::string* wrapped_private_key) {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RetrieveCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Properties::security_level_path_backward_compatibility_support()) {
|
||||
SecurityLevelPathBackwardCompatibility();
|
||||
}
|
||||
|
||||
video_widevine_client::sdk::File file;
|
||||
if (!RetrieveHashedFile(GetCertificateFileName(origin), &file)) {
|
||||
if (!RetrieveHashedFile(GetCertificateFileName(), &file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -151,22 +140,22 @@ bool DeviceFiles::RetrieveCertificate(const std::string& origin,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::HasCertificate(const std::string& origin) {
|
||||
bool DeviceFiles::HasCertificate() {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::HasCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return FileExists(GetCertificateFileName(origin));
|
||||
return FileExists(GetCertificateFileName());
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveCertificate(const std::string& origin) {
|
||||
bool DeviceFiles::RemoveCertificate() {
|
||||
if (!initialized_) {
|
||||
LOGW("DeviceFiles::RemoveCertificate: not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return RemoveFile(GetCertificateFileName(origin));
|
||||
return RemoveFile(GetCertificateFileName());
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreLicense(
|
||||
@@ -536,11 +525,6 @@ bool DeviceFiles::RetrieveUsageInfoByKeySetId(
|
||||
|
||||
bool DeviceFiles::StoreFileWithHash(const std::string& name,
|
||||
const std::string& serialized_file) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::StoreFileWithHash: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
// calculate SHA hash
|
||||
std::string hash;
|
||||
if (!Hash(serialized_file, &hash)) {
|
||||
@@ -561,30 +545,23 @@ bool DeviceFiles::StoreFileWithHash(const std::string& name,
|
||||
|
||||
bool DeviceFiles::StoreFileRaw(const std::string& name,
|
||||
const std::string& serialized_file) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::StoreFileRaw: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::StoreFileRaw: Unable to get base path");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file_->IsDirectory(path)) {
|
||||
if (!file_->CreateDirectory(path)) return false;
|
||||
}
|
||||
|
||||
path += name;
|
||||
|
||||
if (!file_->Open(path, File::kCreate | File::kTruncate | File::kBinary)) {
|
||||
File* file =
|
||||
file_system_->Open(path, FileSystem::kCreate | FileSystem::kTruncate);
|
||||
if (!file) {
|
||||
LOGW("DeviceFiles::StoreFileRaw: File open failed: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t bytes = file_->Write(serialized_file.data(), serialized_file.size());
|
||||
file_->Close();
|
||||
ssize_t bytes = file->Write(serialized_file.data(), serialized_file.size());
|
||||
file->Close();
|
||||
|
||||
if (bytes != static_cast<ssize_t>(serialized_file.size())) {
|
||||
LOGW(
|
||||
@@ -599,16 +576,12 @@ bool DeviceFiles::StoreFileRaw(const std::string& name,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
video_widevine_client::sdk::File* file) {
|
||||
bool DeviceFiles::RetrieveHashedFile(
|
||||
const std::string& name,
|
||||
video_widevine_client::sdk::File* deserialized_file) {
|
||||
std::string serialized_file;
|
||||
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
if (!deserialized_file) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Unspecified file parameter");
|
||||
return false;
|
||||
}
|
||||
@@ -621,29 +594,30 @@ bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
|
||||
path += name;
|
||||
|
||||
if (!file_->Exists(path)) {
|
||||
if (!file_system_->Exists(path)) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: %s does not exist", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t bytes = file_->FileSize(path);
|
||||
ssize_t bytes = file_system_->FileSize(path);
|
||||
if (bytes <= 0) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: File size invalid: %s",
|
||||
path.c_str());
|
||||
// Remove the corrupted file so the caller will not get the same error
|
||||
// when trying to access the file repeatedly, causing the system to stall.
|
||||
file_->Remove(path);
|
||||
file_system_->Remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file_->Open(path, File::kReadOnly | File::kBinary)) {
|
||||
File* file = file_system_->Open(path, FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string serialized_hash_file;
|
||||
serialized_hash_file.resize(bytes);
|
||||
bytes = file_->Read(&serialized_hash_file[0], serialized_hash_file.size());
|
||||
file_->Close();
|
||||
bytes = file->Read(&serialized_hash_file[0], serialized_hash_file.size());
|
||||
file->Close();
|
||||
|
||||
if (bytes != static_cast<ssize_t>(serialized_hash_file.size())) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: read failed");
|
||||
@@ -669,11 +643,11 @@ bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Hash mismatch");
|
||||
// Remove the corrupted file so the caller will not get the same error
|
||||
// when trying to access the file repeatedly, causing the system to stall.
|
||||
file_->Remove(path);
|
||||
file_system_->Remove(path);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!file->ParseFromString(hash_file.file())) {
|
||||
if (!deserialized_file->ParseFromString(hash_file.file())) {
|
||||
LOGW("DeviceFiles::RetrieveHashedFile: Unable to parse file");
|
||||
return false;
|
||||
}
|
||||
@@ -681,11 +655,6 @@ bool DeviceFiles::RetrieveHashedFile(const std::string& name,
|
||||
}
|
||||
|
||||
bool DeviceFiles::FileExists(const std::string& name) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::FileExists: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::FileExists: Unable to get base path");
|
||||
@@ -693,15 +662,10 @@ bool DeviceFiles::FileExists(const std::string& name) {
|
||||
}
|
||||
path += name;
|
||||
|
||||
return file_->Exists(path);
|
||||
return file_system_->Exists(path);
|
||||
}
|
||||
|
||||
bool DeviceFiles::RemoveFile(const std::string& name) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::RemoveFile: Invalid file handle");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::RemoveFile: Unable to get base path");
|
||||
@@ -709,15 +673,10 @@ bool DeviceFiles::RemoveFile(const std::string& name) {
|
||||
}
|
||||
path += name;
|
||||
|
||||
return file_->Remove(path);
|
||||
return file_system_->Remove(path);
|
||||
}
|
||||
|
||||
ssize_t DeviceFiles::GetFileSize(const std::string& name) {
|
||||
if (!file_.get()) {
|
||||
LOGW("DeviceFiles::GetFileSize: Invalid file handle");
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW("DeviceFiles::GetFileSize: Unable to get base path");
|
||||
@@ -725,79 +684,11 @@ ssize_t DeviceFiles::GetFileSize(const std::string& name) {
|
||||
}
|
||||
path += name;
|
||||
|
||||
return file_->FileSize(path);
|
||||
return file_system_->FileSize(path);
|
||||
}
|
||||
|
||||
void DeviceFiles::SecurityLevelPathBackwardCompatibility() {
|
||||
std::string path;
|
||||
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
|
||||
LOGW(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Unable to "
|
||||
"get base path");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<std::string> security_dirs;
|
||||
if (!Properties::GetSecurityLevelDirectories(&security_dirs)) {
|
||||
LOGW(
|
||||
"DeviceFiles::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(
|
||||
"DeviceFiles::SecurityLevelPathBackwardCompatibility: Security level "
|
||||
"specific path not found. Check properties?");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string from_dir(path, 0, pos);
|
||||
|
||||
std::vector<std::string> files;
|
||||
if (!file_->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 (!file_->IsRegularFile(from)) continue;
|
||||
|
||||
for (size_t j = 0; j < security_dirs.size(); ++j) {
|
||||
std::string to_dir = from_dir + security_dirs[j];
|
||||
if (!file_->Exists(to_dir)) file_->CreateDirectory(to_dir);
|
||||
std::string to = to_dir + files[i];
|
||||
file_->Copy(from, to);
|
||||
}
|
||||
file_->Remove(from);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetCertificateFileName(const std::string& origin) {
|
||||
std::string hash;
|
||||
if (origin != EMPTY_ORIGIN) {
|
||||
hash = GetFileNameSafeHash(origin);
|
||||
}
|
||||
return kCertificateFileNamePrefix + hash + kCertificateFileNameExt;
|
||||
std::string DeviceFiles::GetCertificateFileName() {
|
||||
return kCertificateFileName;
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetLicenseFileNameExtension() {
|
||||
@@ -820,9 +711,4 @@ std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) {
|
||||
return wvcdm::Base64SafeEncode(hash);
|
||||
}
|
||||
|
||||
void DeviceFiles::SetTestFile(File* file) {
|
||||
file_.reset(file);
|
||||
test_file_ = true;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
Reference in New Issue
Block a user