Refactor oemcrypto mock into stand alone reference code

Merge from Widevine repo of http://go/wvgerrit/46204
Refactor utility code - split the mock, step 1

Merge from Widevine repo of http://go/wvgerrit/46205
Move some OEMCrypto types to common header - split the mock, step 2

Merge from Widevine repo of http://go/wvgerrit/46206
Split mock into two -- step 3

Merge from Widevine repo of http://go/wvgerrit/47460
Split the mock into two -- step 3.5

The CL moves several files used by oemcrypto and cdm into a common
subdirectory, so that it may more easily be shared with partners.

The CORE_DISALLOW_COPY_AND_ASSIGN macro was moved to its own header in
the util/include directory.

This CL removes some references to the mock from other code, and puts
some constants and types, such as the definition of the keybox, into a
header in oemcrypto.

Test: tested as part of http://go/ag/4674759
bug: 76393338
Change-Id: I75b4bde7062ed8ee572c97ebc2f4da018f4be0c9
This commit is contained in:
Fred Gylys-Colwell
2018-06-29 16:57:19 -07:00
parent b8091eaa7d
commit 947531a6a9
109 changed files with 806 additions and 1428 deletions

View File

@@ -1,20 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Clock - implemented using the standard linux time library
#include "clock.h"
#include <sys/time.h>
namespace wvcdm {
int64_t Clock::GetCurrentTime() {
struct timeval tv;
tv.tv_sec = tv.tv_usec = 0;
gettimeofday(&tv, NULL);
return tv.tv_sec;
}
} // namespace wvcdm

View File

@@ -1,184 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// File class - provides a simple android specific file implementation
#include "file_store.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_utils.h"
#include "log.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#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 GetFileNameForIdentifier(const std::string path,
const std::string identifier) {
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 && !identifier.empty()) {
const std::string hash = GetFileNameSafeHash(identifier);
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* file, const std::string& file_path)
: file_(file), file_path_(file_path) {}
virtual ~Impl() {}
FILE* file_;
std::string file_path_;
};
File::File(Impl* impl) : impl_(impl) {}
File::~File() {
Close();
delete impl_;
}
void File::Close() {
if (impl_ && impl_->file_) {
fflush(impl_->file_);
fsync(fileno(impl_->file_));
fclose(impl_->file_);
impl_->file_ = NULL;
}
}
ssize_t File::Read(char* buffer, size_t bytes) {
if (impl_ && impl_->file_) {
size_t len = fread(buffer, sizeof(char), bytes, impl_->file_);
if (len == 0) {
LOGW("File::Read: fread failed: %d", errno);
}
return len;
}
LOGW("File::Read: file not open");
return -1;
}
ssize_t File::Write(const char* buffer, size_t bytes) {
if (impl_ && impl_->file_) {
size_t len = fwrite(buffer, sizeof(char), bytes, impl_->file_);
if (len == 0) {
LOGW("File::Write: fwrite failed: %d", errno);
}
return len;
}
LOGW("File::Write: file not open");
return -1;
}
class FileSystem::Impl {};
FileSystem::FileSystem() : FileSystem(EMPTY_ORIGIN, NULL) {}
FileSystem::FileSystem(const std::string& origin, void* /* extra_data */)
: origin_(origin) {}
FileSystem::~FileSystem() {}
File* FileSystem::Open(const std::string& in_name, int flags) {
std::string open_flags;
std::string name = GetFileNameForIdentifier(in_name, identifier_);
// 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);
}
// 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);
}
}
open_flags = (flags & FileSystem::kReadOnly) ? "rb" : "rb+";
FILE* file = fopen(name.c_str(), open_flags.c_str());
umask(old_mask);
if (!file) {
LOGW("File::Open: fopen failed: %d", errno);
return NULL;
}
return new File(new File::Impl(file, name));
}
bool FileSystem::Exists(const std::string& path) {
return FileUtils::Exists(GetFileNameForIdentifier(path, identifier_));
}
bool FileSystem::Remove(const std::string& path) {
return FileUtils::Remove(GetFileNameForIdentifier(path, identifier_));
}
ssize_t FileSystem::FileSize(const std::string& in_path) {
std::string path = GetFileNameForIdentifier(in_path, identifier_);
struct stat buf;
if (stat(path.c_str(), &buf) == 0)
return buf.st_size;
else
return -1;
}
bool FileSystem::List(const std::string& path,
std::vector<std::string>* filenames) {
return FileUtils::List(GetFileNameForIdentifier(path, origin_), filenames);
}
void FileSystem::SetOrigin(const std::string& origin) { origin_ = origin; }
void FileSystem::SetIdentifier(const std::string& identifier) {
identifier_ = identifier;
}
} // namespace wvcdm

View File

@@ -1,215 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
#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 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;
}
} // namespace wvcdm

View File

@@ -1,32 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Lock class - provides a simple android specific mutex implementation
#include "lock.h"
#include <utils/Mutex.h>
namespace wvcdm {
class Lock::Impl {
public:
android::Mutex lock_;
};
Lock::Lock() : impl_(new Lock::Impl()) {
}
Lock::~Lock() {
delete impl_;
}
void Lock::Acquire() {
impl_->lock_.lock();
}
void Lock::Release() {
impl_->lock_.unlock();
}
} // namespace wvcdm

View File

@@ -1,78 +0,0 @@
// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine Master
// License Agreement.
//
// Log - implemented using the standard Android logging mechanism
/*
* Qutoing from system/core/include/log/log.h:
* Normally we strip ALOGV (VERBOSE messages) from release builds.
* You can modify this (for example with "#define LOG_NDEBUG 0"
* at the top of your source file) to change that behavior.
*/
#ifndef LOG_NDEBUG
#ifdef NDEBUG
#define LOG_NDEBUG 1
#else
#define LOG_NDEBUG 0
#endif
#endif
#define LOG_TAG "WVCdm"
#define LOG_BUF_SIZE 1024
#include "log.h"
#include <utils/Log.h>
#include <string>
#include <stdio.h>
#include <stdarg.h>
/*
* Uncomment the line below if you want to have the LOGV messages to print
* IMPORTANT : this will affect all of CDM
*/
// #define LOG_NDEBUG 0
namespace wvcdm {
LogPriority g_cutoff = LOG_VERBOSE;
void InitLogging() {}
void Log(const char* file, const char* function, int line, LogPriority level,
const char* format, ...) {
const char* filename = strrchr(file, '/');
filename = filename == nullptr ? file : filename + 1;
char buf[LOG_BUF_SIZE];
int len = snprintf(buf, LOG_BUF_SIZE, "[%s(%d):%s] ", filename, line,
function);
if (len < 0) len = 0;
if (static_cast<unsigned int>(len) < sizeof(buf)) {
va_list ap;
va_start(ap, format);
vsnprintf(buf+len, LOG_BUF_SIZE-len, format, ap);
va_end(ap);
}
android_LogPriority prio = ANDROID_LOG_VERBOSE;
switch(level) {
case LOG_ERROR: prio = ANDROID_LOG_ERROR; break;
case LOG_WARN: prio = ANDROID_LOG_WARN; break;
case LOG_INFO: prio = ANDROID_LOG_INFO; break;
case LOG_DEBUG: prio = ANDROID_LOG_DEBUG; break;
#if LOG_NDEBUG
case LOG_VERBOSE: return;
#else
case LOG_VERBOSE: prio = ANDROID_LOG_VERBOSE; break;
#endif
}
__android_log_write(prio, LOG_TAG, buf);
}
} // namespace wvcdm