diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fc57ac1 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,73 @@ +# Widevine OEMCrypto, ODK, and OPK Changelog + +[TOC] + +## [Version 16.4 plus opk beta 2][v16.4+opk-beta2] + +Second beta release of the OEMCrypto Porting Kit (OPK), supporting OEMCrypto v16. + +The following changes are included with this update: +- Add makefiles to build OEMCrypto TA and host apps for OP-TEE. See + `oemcrypto/opk/ports/optee/README.md` for information on how to build with make +- Update missing and outdated files such as `odk_message.h` and + `OEMCryptoCENCCommon.h` +- Rename WTPI interface files with common WTPI prefix +- Add more WTPI unit tests for crypto functions +- Replace DER parsing code in OEMCrypto TA OPTEE port with mbedtls + implementation +- Update oemcrypto unittests + +Using the default make settings and an external OP-TEE repository setup, the +OEMCrypto TA port is now buildable for QEMU. Slight changes to environment +variables will enable STM32MP1 and NXP iMX8 targets. Keep in mind that the +performance capabilities of QEMU and the STM32MP1 platforms do not meet the +timing requirements for many oemcrypto unittests; so far we have only passed all +tests on the NXP hardware. + +This update does not include any Trusty port code. + +## [Version 16.4 plus opk beta][v16.4+opk-beta] + +Initial beta release of the OEMCrypto Porting Kit (OPK), supporting OEMCrypto v16. + +## [Version 16.4 doc updates][v16.4+doc-updates] + +Documentation updates. All headers have been updated so that documentation may +be extracted using Doxygen. Documentation can now be found at +https://developers.google.com/widevine/drm/client/oemcrypto + + +## [Version 16.4 plus extra tests][v16.4+extra-test] + +We have added several new tests to the OEMCrypto test suite in order to identify +and fix certain types of security issues that are being discovered and disclosed +by security researchers. Widevine strongly recommends these additional security +tests, in order to minimize the risk and exposure from external security +research. + +Most of the new tests are checking for buffer overflow and off-by-one +errors. They verify that OEMCrypto correctly handles the case where input +buffers are larger than output buffers; total subsamples are larger than +samples; and message buffers are much larger than required. OEMCrypto is +expected to accept bad input and fail gracefully. Failing these tests is an +indication that there might be a security risk. + +Because buffer overflow bugs might crash the device or cause a seg fault, these +tests might fail and then stop running. For this reason, you cannot assume that +your device is passing all of the tests if you don't see FAIL in the +output. Instead, you should look for a summary at the end of the test suite +output saying that all the tests passed. See the README.md in oemcrypto/test +for more details. + + +## [Version 16.4][v16.4] + +Public release for OEMCrypto API and ODK library version 16.4. + + + +[v16.4]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4 +[v16.4+extra-test]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4+extra-tests +[v16.4+doc-updates]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4+doc-updates +[v16.4+opk-beta]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4+opk-beta +[v16.4+opk-beta2]: https://widevine-partner.googlesource.com/oemcrypto/+/refs/tags/v16.4+opk-beta2 diff --git a/linux/src/file_store.cpp b/linux/src/file_store.cpp new file mode 100644 index 0000000..86f14c5 --- /dev/null +++ b/linux/src/file_store.cpp @@ -0,0 +1,296 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// File class - provides a simple file implementation + +#include "file_store.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.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; +} + +bool 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 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, %s", errno, + strerror(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, %s", errno, + strerror(errno)); + return false; + } + } + } + return true; +} +} // namespace + +namespace wvcdm { + +class FileImpl : public File { + public: + FileImpl() {} + + void FlushFile() { + fflush(file_); + fsync(fileno(file_)); + } + + ~FileImpl() override { + if (file_) { + FlushFile(); + fclose(file_); + file_ = nullptr; + } + } + + ssize_t Read(char* buffer, size_t bytes) override { + if (!buffer) { + LOGW("File::Read: buffer is empty"); + return -1; + } + if (!file_) { + LOGW("File::Read: file not open"); + return -1; + } + size_t len = fread(buffer, sizeof(char), bytes, file_); + if (len != bytes) { + LOGW("File::Read: fread failed: %d, %s", errno, strerror(errno)); + } + return len; + } + + ssize_t Write(const char* buffer, size_t bytes) override { + if (!buffer) { + LOGW("File::Write: buffer is empty"); + return -1; + } + if (!file_) { + LOGW("File::Write: file not open"); + return -1; + } + size_t len = fwrite(buffer, sizeof(char), bytes, file_); + if (len != bytes) { + LOGW("File::Write: fwrite failed: %d, %s", errno, strerror(errno)); + } + FlushFile(); + return len; + } + + FILE* file_; + std::string file_path_; +}; + +class FileSystem::Impl {}; + +FileSystem::FileSystem() {} +FileSystem::FileSystem(const std::string& origin, void*) : origin_(origin) {} +FileSystem::~FileSystem() {} + +std::unique_ptr FileSystem::Open(const std::string& name, int flags) { + std::string open_flags; + + // 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)) + 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+"; + + std::unique_ptr file_impl(new FileImpl()); + file_impl->file_ = fopen(name.c_str(), open_flags.c_str()); + umask(old_mask); + if (!file_impl->file_) { + LOGW("File::Open: fopen failed: %d, %s", errno, strerror(errno)); + return nullptr; + } + file_impl->file_path_ = name; + return file_impl; +} + +bool FileSystem::Exists(const std::string& path) { + struct stat buf; + int res = stat(path.c_str(), &buf) == 0; + if (!res) { + LOGV("File::Exists: stat failed: %d, %s", errno, strerror(errno)); + } + return res; +} + +bool FileSystem::Remove(const std::string& path) { + if (IsDirectory(path)) { + // Handle directory deletion + DIR* dir; + if ((dir = opendir(path.c_str())) != nullptr) { + // first remove files and dir within it + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + 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, %s", errno, strerror(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, %s", errno, strerror(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())) == nullptr) { + 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)) != nullptr) { + 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; + } +} + +ssize_t FileSystem::FileSize(const std::string& path) { + struct stat buf; + if (stat(path.c_str(), &buf) == 0) + return buf.st_size; + else + return -1; +} + +// Accept a directory, return all the files in that directory. +// Returns false if the directory does not exist. +bool FileSystem::List(const std::string& dirpath, + std::vector* filenames) { + if (filenames == nullptr) { + LOGE("FileSystem::List: destination not provided"); + return false; + } + if (!Exists(dirpath)) { + LOGW("FileSystem::List: path %s does not exist: %d, %s", + dirpath.c_str(), errno, strerror(errno)); + return false; + } + + DIR* dir = opendir(dirpath.c_str()); + if (dir == nullptr) { + LOGW("FileSystem::List: directory open failed %s: %d, %s", dirpath.c_str(), + errno, strerror(errno)); + return false; + } + + filenames->clear(); + struct dirent* entry; + while ((entry = readdir(dir)) != nullptr) { + if (!IsCurrentOrParentDirectory(entry->d_name)) { + filenames->push_back(entry->d_name); + } + } + closedir(dir); + + return true; +} + +void FileSystem::set_origin(const std::string& origin) { origin_ = origin; } + +void FileSystem::set_identifier(const std::string& identifier) { + identifier_ = identifier; +} + +} // namespace wvcdm diff --git a/linux/src/log.cpp b/linux/src/log.cpp new file mode 100644 index 0000000..c3bc15c --- /dev/null +++ b/linux/src/log.cpp @@ -0,0 +1,62 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Log - implemented using stdout. + +#include "log.h" + +#include +#include +#include +#include + +namespace { + +FILE* const kOutputFile = stdout; + +} // namespace + +namespace wvcdm { + +LogPriority g_cutoff = LOG_WARN; + +void InitLogging() { + // Note: The default log level is LOG_WARN, above. If you set the + // environment variable VERBOSE_LOG, you will get verbose logging. This is + // set by jenkins (http://go/wvbuild), so that we have more details when the + // build breaks. + const char* verbose_env = getenv("VERBOSE_LOG"); + if (verbose_env && !strncmp(verbose_env, "yes", 3) ) { + g_cutoff = LOG_VERBOSE; + } +} + +void Log(const char* file, const char* function, int line, LogPriority level, + const char* fmt, ...) { + const char* severities[] = { "ERROR", "WARN", "INFO", "DEBUG", "VERBOSE" }; + if (level >= + static_cast(sizeof(severities) / sizeof(*severities))) { + fprintf(kOutputFile, "[FATAL:%s(%d):%s] Invalid log priority level: %d\n", + file, line, function, level); + return; + } + if (level > g_cutoff) return; + + // Strip off the the leading "../" that clutters the logs. + const char * up_dir = "../"; + const size_t up_dir_size = strlen(up_dir); + while (strncmp(up_dir, file, up_dir_size) == 0) file += up_dir_size; + + + fprintf(kOutputFile, "[%s:%s(%d):%s] ", severities[level], file, line, + function); + + va_list ap; + va_start(ap, fmt); + vfprintf(kOutputFile, fmt, ap); + va_end(ap); + + putc('\n', kOutputFile); + fflush(kOutputFile); +} + +} // namespace wvcdm diff --git a/oem_certificate_generator/oem_certificate.py b/oem_certificate_generator/oem_certificate.py old mode 100644 new mode 100755 index 8d17c98..71e7789 --- a/oem_certificate_generator/oem_certificate.py +++ b/oem_certificate_generator/oem_certificate.py @@ -1,3 +1,4 @@ +#!/usr/bin/python3 # Copyright 2017 Google LLC. All Rights Reserved. """OEM certificate generation tool. @@ -110,7 +111,7 @@ class X509CertificateChain(object): x509_stack = pkcs7.d.sign.cert certificates = [] - for i in xrange(backend._lib.sk_X509_num(x509_stack)): + for i in range(backend._lib.sk_X509_num(x509_stack)): x509_value = backend._ffi.gc( backend._lib.X509_dup(backend._lib.sk_X509_value(x509_stack, i)), backend._lib.X509_free) @@ -134,6 +135,10 @@ class X509CertificateChain(object): return backend._read_mem_bio(bio) +# Type for argparse to accept byte buffers on the command line +def utf8_bytes(utf8_str): + return utf8_str.encode('utf-8') + def _multiple_of_1024(key_size_str): """argparse custom type function for key size.""" key_size = int(key_size_str) @@ -299,9 +304,9 @@ def generate_leaf_certificate(args): def secure_erase(args): """Subparser handler for secure erasing of a file.""" length = args.file.tell() - for _ in xrange(args.passes): + for _ in range(args.passes): args.file.seek(0) - for _ in xrange(length): + for _ in range(length): args.file.write(os.urandom(1)) args.file.close() os.remove(args.file.name) @@ -403,6 +408,7 @@ def create_parser(): '--output_private_key_file', type=argparse.FileType('wb'), required=True) parser_csr.add_argument( '--passphrase', + type=utf8_bytes, help=('specify an optional passphrase to encrypt the private key. The ' 'private key is not encrypted if omitted.')) parser_csr.set_defaults(func=generate_csr) @@ -429,7 +435,7 @@ def create_parser(): '--root_certificate_file', type=argparse.FileType('rb'), required=True) parser_intermediate_cert.add_argument( '--root_private_key_file', type=argparse.FileType('rb'), required=True) - parser_intermediate_cert.add_argument('--root_private_key_passphrase') + parser_intermediate_cert.add_argument('--root_private_key_passphrase', type=utf8_bytes) parser_intermediate_cert.add_argument( '--output_certificate_file', type=argparse.FileType('wb'), required=True) parser_intermediate_cert.set_defaults(func=generate_intermediate_certificate) @@ -460,13 +466,14 @@ def create_parser(): '--intermediate_private_key_file', type=argparse.FileType('rb'), required=True) - parser_leaf_cert.add_argument('--intermediate_private_key_passphrase') + parser_leaf_cert.add_argument('--intermediate_private_key_passphrase', type=utf8_bytes) parser_leaf_cert.add_argument( '--output_certificate_file', type=argparse.FileType('wb'), required=True) parser_leaf_cert.add_argument( '--output_private_key_file', type=argparse.FileType('wb'), required=True) parser_leaf_cert.add_argument( '--passphrase', + type=utf8_bytes, help=('specify an optional passphrase to encrypt the private key. The ' 'private key is not encrypted if omitted.')) parser_leaf_cert.set_defaults(func=generate_leaf_certificate) @@ -497,7 +504,7 @@ def main(): args = sys.argv[1:] config_file_name = 'oem_certificate.cfg' if os.path.isfile(config_file_name): - print 'Load from args default configuration file: ', config_file_name + print('Load from args default configuration file: ', config_file_name) args.append('@' + config_file_name) parser_args = create_parser().parse_args(args) parser_args.func(parser_args) diff --git a/oem_certificate_generator/oem_certificate_test_helper.py b/oem_certificate_generator/oem_certificate_test_helper.py index eccb125..75de4ae 100644 --- a/oem_certificate_generator/oem_certificate_test_helper.py +++ b/oem_certificate_generator/oem_certificate_test_helper.py @@ -1,9 +1,10 @@ +#!/usr/bin/python3 # Copyright 2017 Google LLC. All Rights Reserved. """Common test utility functions for OEM certificate generation.""" import datetime -import StringIO +import io from cryptography import x509 from cryptography.hazmat import backends @@ -24,7 +25,7 @@ _NOT_VALID_BEFORE = datetime.datetime(2001, 8, 9) _VALID_DURATION = 100 _LEAF_CERT_VALID_DURATION = 8000 _SYSTEM_ID = 2001 -_ROOT_PRIVATE_KEY_PASSPHRASE = 'root_passphrase' +_ROOT_PRIVATE_KEY_PASSPHRASE = b'root_passphrase' class ArgParseObject(object): @@ -67,11 +68,11 @@ def setup_csr_args(country_name=_COUNTRY_NAME, if output_csr_file: args.output_csr_file = output_csr_file else: - args.output_csr_file = StringIO.StringIO() + args.output_csr_file = io.BytesIO() if output_private_key_file: args.output_private_key_file = output_private_key_file else: - args.output_private_key_file = StringIO.StringIO() + args.output_private_key_file = io.BytesIO() args.passphrase = passphrase return args @@ -86,12 +87,12 @@ def setup_intermediate_cert_args( args.not_valid_before = not_valid_before args.valid_duration = valid_duration args.system_id = system_id - args.csr_file = StringIO.StringIO(csr_bytes) + args.csr_file = io.BytesIO(csr_bytes) args.root_private_key_passphrase = root_private_key_passphrase if output_certificate_file: args.output_certificate_file = output_certificate_file else: - args.output_certificate_file = StringIO.StringIO() + args.output_certificate_file = io.BytesIO() serialized_private_key = root_key.private_bytes( serialization.Encoding.DER, @@ -100,8 +101,8 @@ def setup_intermediate_cert_args( args.root_private_key_passphrase)) serialized_certificate = root_certificate.public_bytes( serialization.Encoding.DER) - args.root_certificate_file = StringIO.StringIO(serialized_certificate) - args.root_private_key_file = StringIO.StringIO(serialized_private_key) + args.root_certificate_file = io.BytesIO(serialized_certificate) + args.root_private_key_file = io.BytesIO(serialized_private_key) return args @@ -122,16 +123,16 @@ def setup_leaf_cert_args(intermediate_key_bytes, if output_certificate_file: args.output_certificate_file = output_certificate_file else: - args.output_certificate_file = StringIO.StringIO() + args.output_certificate_file = io.BytesIO() if output_private_key_file: args.output_private_key_file = output_private_key_file else: - args.output_private_key_file = StringIO.StringIO() + args.output_private_key_file = io.BytesIO() args.passphrase = passphrase - args.intermediate_private_key_file = StringIO.StringIO( + args.intermediate_private_key_file = io.BytesIO( intermediate_key_bytes) - args.intermediate_certificate_file = StringIO.StringIO( + args.intermediate_certificate_file = io.BytesIO( intermediate_certificate_bytes) return args diff --git a/oemcrypto/include/oemcrypto_types.h b/oemcrypto/include/oemcrypto_types.h index 4a5728c..9a4ce19 100644 --- a/oemcrypto/include/oemcrypto_types.h +++ b/oemcrypto/include/oemcrypto_types.h @@ -23,6 +23,14 @@ typedef struct WidevineKeybox { // 128 bytes total. uint8_t crc_[4]; } WidevineKeybox; +// This is the format for a key control block. +typedef struct { + uint8_t verification[4]; + uint32_t duration; + uint32_t nonce; + uint32_t control_bits; +} KeyControlBlock; + /* * SRM_Restriction_Data * diff --git a/oemcrypto/odk/Android.bp b/oemcrypto/odk/Android.bp index 66cf0f0..45ec660 100644 --- a/oemcrypto/odk/Android.bp +++ b/oemcrypto/odk/Android.bp @@ -5,6 +5,18 @@ // ---------------------------------------------------------------- // Builds libwv_odk.a, The ODK Library (libwv_odk) is used by // the CDM and by oemcrypto implementations. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_library_static { name: "libwv_odk", include_dirs: [ @@ -15,6 +27,7 @@ cc_library_static { srcs: [ "src/odk.c", + "src/odk_message.c", "src/odk_overflow.c", "src/odk_serialize.c", "src/odk_timer.c", diff --git a/oemcrypto/odk/README b/oemcrypto/odk/README index ba8c8c7..408fc44 100644 --- a/oemcrypto/odk/README +++ b/oemcrypto/odk/README @@ -1,8 +1,6 @@ This ODK Library is used to generate and parse core OEMCrypto messages for -OEMCrypto v16 and above. - -This library is used by both OEMCrypto on a device, and by Widevine license and -provisioning servers. +OEMCrypto v16 and above. This library is used by both OEMCrypto on a device +and by Widevine license and provisioning servers. The source of truth for these files is in the server code base on piper. Do not edit these files in the Android directory tree or in the Widevine Git diff --git a/oemcrypto/odk/include/OEMCryptoCENCCommon.h b/oemcrypto/odk/include/OEMCryptoCENCCommon.h index 7a2a529..7dac3ae 100644 --- a/oemcrypto/odk/include/OEMCryptoCENCCommon.h +++ b/oemcrypto/odk/include/OEMCryptoCENCCommon.h @@ -61,7 +61,7 @@ typedef enum OEMCryptoResult { OEMCrypto_ERROR_INVALID_NONCE = 32, OEMCrypto_ERROR_TOO_MANY_KEYS = 33, OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED = 34, - OEMCrypto_ERROR_INVALID_RSA_KEY = 35, + OEMCrypto_ERROR_INVALID_RSA_KEY = 35, /* deprecated */ OEMCrypto_ERROR_KEY_EXPIRED = 36, OEMCrypto_ERROR_INSUFFICIENT_RESOURCES = 37, OEMCrypto_ERROR_INSUFFICIENT_HDCP = 38, @@ -87,6 +87,9 @@ typedef enum OEMCryptoResult { OEMCrypto_ERROR_LICENSE_RELOAD = 57, OEMCrypto_ERROR_MULTIPLE_USAGE_ENTRIES = 58, OEMCrypto_WARNING_MIXED_OUTPUT_PROTECTION = 59, + OEMCrypto_ERROR_INVALID_ENTITLED_KEY_SESSION = 60, + OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING = 61, + OEMCrypto_ERROR_INVALID_KEY = 65, /* ODK return values */ ODK_ERROR_BASE = 1000, ODK_ERROR_CORE_MESSAGE = ODK_ERROR_BASE, @@ -95,6 +98,11 @@ typedef enum OEMCryptoResult { ODK_TIMER_EXPIRED = ODK_ERROR_BASE + 3, ODK_UNSUPPORTED_API = ODK_ERROR_BASE + 4, ODK_STALE_RENEWAL = ODK_ERROR_BASE + 5, + /* OPK return values */ + OPK_ERROR_BASE = 2000, + OPK_ERROR_REMOTE_CALL = OPK_ERROR_BASE, + OPK_ERROR_INCOMPATIBLE_VERSION = OPK_ERROR_BASE + 1, + OPK_ERROR_NO_PERSISTENT_DATA = OPK_ERROR_BASE + 2, } OEMCryptoResult; /* clang-format on */ diff --git a/oemcrypto/odk/include/odk_attributes.h b/oemcrypto/odk/include/odk_attributes.h index bbb81d8..72321b1 100644 --- a/oemcrypto/odk/include/odk_attributes.h +++ b/oemcrypto/odk/include/odk_attributes.h @@ -6,9 +6,9 @@ #define WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_ #if defined(__GNUC__) || defined(__clang__) -# define UNUSED __attribute__((__unused__)) +#define UNUSED __attribute__((__unused__)) #else -# define UNUSED +#define UNUSED #endif #endif // WIDEVINE_ODK_INCLUDE_ODK_ATTRIBUTES_H_ diff --git a/oemcrypto/odk/include/odk_message.h b/oemcrypto/odk/include/odk_message.h new file mode 100644 index 0000000..07abebb --- /dev/null +++ b/oemcrypto/odk/include/odk_message.h @@ -0,0 +1,143 @@ +/* + * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ +#define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +/* + * ODK_Message is the structure that defines the serialized messages passed + * between the REE and TEE. ODK_Message is an abstract data type that represents + * the concept of a message without disclosing the implementation details. By + * hiding the internal structure, modification of the message fields by code + * that is not privy to the message definition can be prevented. If the message + * definition was exposed, there could be serious yet subtle errors in message + * manipulation anywhere in the code base. By restricting message modification + * it is possible to enforce validity and integrity with a small set of + * primitives that can be carefully reviewed. Checks can be added to verify that + * a message's fields are internally consistent before every operation. As an + * example, it can be guaranteed that the message status will be checked prior + * to accessing any field so parsing will be stopped when the message status is + * set after any parse error is detected. This also makes development easier + * since any access to the message structure can be tracked through a single + * point so, for example, it becomes possible to add trace statements globally + * to all message operations by only changing the field accessors. Finally it + * simplifies maintenance by localizing changes to the message structure to a + * few files. + */ + +#if defined(__GNUC__) || defined(__clang__) +# define ALIGNED __attribute__((aligned)) +#else +# define ALIGNED +# error ODK_Message must be aligned to the maximum useful alignment of the \ + machine you are compiling for. Define the ALIGNED macro accordingly. +#endif + +typedef struct { +#define SIZE_OF_ODK_MESSAGE_IMPL 64 + uint8_t opaque_data[SIZE_OF_ODK_MESSAGE_IMPL]; +} ALIGNED ODK_Message; + +typedef enum { + MESSAGE_STATUS_OK = 0xe937fcf7, + MESSAGE_STATUS_UNKNOWN_ERROR = 0xe06c1190, + MESSAGE_STATUS_OVERFLOW_ERROR = 0xc43ae4bc, + MESSAGE_STATUS_UNDERFLOW_ERROR = 0x7123cd0b, + MESSAGE_STATUS_PARSE_ERROR = 0x0b9f6189, + MESSAGE_STATUS_NULL_POINTER_ERROR = 0x2d66837a, + MESSAGE_STATUS_API_VALUE_ERROR = 0x6ba34f47, + MESSAGE_STATUS_END_OF_MESSAGE_ERROR = 0x998db72a, + MESSAGE_STATUS_INVALID_ENUM_VALUE = 0xedb88197, + MESSAGE_STATUS_INVALID_TAG_ERROR = 0x14dce06a, + MESSAGE_STATUS_NOT_INITIALIZED = 0x2990b6c6, + MESSAGE_STATUS_OUT_OF_MEMORY = 0xfc5c64cc, + MESSAGE_STATUS_MAP_SHARED_MEMORY_FAILED = 0xfafecacf, + MESSAGE_STATUS_SECURE_BUFFER_ERROR = 0x78f0e873 +} ODK_MessageStatus; + +/* + * Create a message structure that references a separate data buffer. An + * initialized message is returned. The caller is responsible for ensuring that + * the buffer remains allocated for the lifetime of the message. If |buffer| + * is NULL or |capacity| is zero, the message is invalid and the status + * will be set to MESSAGE_STATUS_NOT_INITIALIZED. + */ +ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity); + +/* + * Erase the contents of the message, set it to an empty state by setting the + * message size and read offset to 0, effectively erasing the contents of the + * message. The message data buffer pointer remains unchanged, i.e. the message + * retains ownership of the buffer. The message status is reset to + * MESSAGE_STATUS_OK. + */ +void ODK_Message_Clear(ODK_Message* message); + +/* + * Reset read pointer to the beginning of the message and clear status + * so that parsing of the message will restart at the beginning of the + * message. The message status is reset to MESSAGE_STATUS_OK. + */ +void ODK_Message_Reset(ODK_Message* message); + +/* + * Return a pointer to the message data buffer, i.e. the message payload. + * This is the buffer address that was passed into ODK_Message_Create. + */ +uint8_t* ODK_Message_GetBase(ODK_Message* message); + +/* + * Get the maximum number of bytes the message can hold. + */ +size_t ODK_Message_GetCapacity(ODK_Message* message); + +/* + * Get the number of bytes currently in the message + */ +size_t ODK_Message_GetSize(ODK_Message* message); + +/* + * Get the offset of where the next bytes will be read from the message data + * buffer. + */ +size_t ODK_Message_GetOffset(ODK_Message* message); + +/* + * Return the status of the message + */ +ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message); + +/* + * Set the message status to a specific value + */ +void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status); + +/* + * Set the size of the message to a value. This may be needed after writing data + * into the message data buffer. + */ +void ODK_Message_SetSize(ODK_Message* message, size_t size); + +/* + * Test if the integrity of a message. This means that the status must be + * MESSAGE_STATUS_OK and that the internal fields of the message are + * within the range of valid values. + */ +bool ODK_Message_IsValid(ODK_Message* message); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_H_ diff --git a/oemcrypto/odk/include/odk_structs.h b/oemcrypto/odk/include/odk_structs.h index 34eb332..291194e 100644 --- a/oemcrypto/odk/include/odk_structs.h +++ b/oemcrypto/odk/include/odk_structs.h @@ -15,7 +15,7 @@ #define ODK_MINOR_VERSION 4 /* ODK Version string. Date changed automatically on each release. */ -#define ODK_RELEASE_DATE "ODK v16.4 2020-10-07" +#define ODK_RELEASE_DATE "ODK v16.4 2020-10-23" /* The lowest version number for an ODK message. */ #define ODK_FIRST_VERSION 16 diff --git a/oemcrypto/odk/src/core_message_deserialize.cpp b/oemcrypto/odk/src/core_message_deserialize.cpp index ebf0add..e5c1bd3 100644 --- a/oemcrypto/odk/src/core_message_deserialize.cpp +++ b/oemcrypto/odk/src/core_message_deserialize.cpp @@ -39,13 +39,11 @@ bool ParseRequest(uint32_t message_type, reinterpret_cast(oemcrypto_core_message.c_str()); const size_t buf_length = oemcrypto_core_message.size(); - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = reinterpret_cast(blk); - InitMessage(msg, const_cast(buf), buf_length); - SetSize(msg, buf_length); + ODK_Message msg = ODK_Message_Create(const_cast(buf), buf_length); + ODK_Message_SetSize(&msg, buf_length); - unpacker(msg, prepared); - if (!ValidMessage(msg)) { + unpacker(&msg, prepared); + if (!ODK_Message_IsValid(&msg)) { return false; } @@ -80,7 +78,7 @@ bool ParseRequest(uint32_t message_type, // than the total message size. We allow the total message size to be larger // for forward compatibility because future messages might have extra fields // that we can ignore. - if (core_message.message_length < GetOffset(msg)) return false; + if (core_message.message_length < ODK_Message_GetOffset(&msg)) return false; return true; } diff --git a/oemcrypto/odk/src/core_message_serialize.cpp b/oemcrypto/odk/src/core_message_serialize.cpp index 6003d71..c55b8f6 100644 --- a/oemcrypto/odk/src/core_message_serialize.cpp +++ b/oemcrypto/odk/src/core_message_serialize.cpp @@ -50,18 +50,16 @@ bool CreateResponse(uint32_t message_type, const S& core_request, static constexpr size_t BUF_CAPACITY = 2048; std::vector buf(BUF_CAPACITY, 0); - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = reinterpret_cast(blk); - InitMessage(msg, buf.data(), buf.capacity()); - packer(msg, &response); - if (!ValidMessage(msg)) { + ODK_Message msg = ODK_Message_Create(buf.data(), buf.capacity()); + packer(&msg, &response); + if (!ODK_Message_IsValid(&msg)) { return false; } - uint32_t message_length = GetSize(msg); - InitMessage(msg, buf.data() + sizeof(header->message_type), - sizeof(header->message_length)); - Pack_uint32_t(msg, &message_length); + uint32_t message_length = static_cast(ODK_Message_GetSize(&msg)); + msg = ODK_Message_Create(buf.data() + sizeof(header->message_type), + sizeof(header->message_length)); + Pack_uint32_t(&msg, &message_length); oemcrypto_core_message->assign(reinterpret_cast(buf.data()), message_length); return true; @@ -74,7 +72,7 @@ bool CopyDeviceId(const ODK_ProvisioningRequest& src, if (request.device_id_length > sizeof(request.device_id)) { return false; } - request.device_id_length = device_id.size(); + request.device_id_length = static_cast(device_id.size()); memset(request.device_id, 0, sizeof(request.device_id)); memcpy(request.device_id, device_id.data(), request.device_id_length); return true; diff --git a/oemcrypto/odk/src/odk.c b/oemcrypto/odk/src/odk.c index b404d48..f674fb7 100644 --- a/oemcrypto/odk/src/odk.c +++ b/oemcrypto/odk/src/odk.c @@ -27,9 +27,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = (Message*)blk; - InitMessage(msg, message, *core_message_length); + ODK_Message msg = ODK_Message_Create(message, *core_message_length); /* The core message should be at the beginning of the buffer, and with a * shorter length. */ @@ -52,7 +50,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } Pack_ODK_PreparedLicenseRequest( - msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer); + &msg, (ODK_PreparedLicenseRequest*)prepared_request_buffer); break; } case ODK_Renewal_Request_Type: { @@ -61,7 +59,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } Pack_ODK_PreparedRenewalRequest( - msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer); + &msg, (ODK_PreparedRenewalRequest*)prepared_request_buffer); break; } case ODK_Provisioning_Request_Type: { @@ -71,7 +69,7 @@ static OEMCryptoResult ODK_PrepareRequest( return ODK_ERROR_CORE_MESSAGE; } Pack_ODK_PreparedProvisioningRequest( - msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer); + &msg, (ODK_PreparedProvisioningRequest*)prepared_request_buffer); break; } default: { @@ -80,13 +78,13 @@ static OEMCryptoResult ODK_PrepareRequest( } *core_message_length = core_message->message_length; - if (GetStatus(msg) != MESSAGE_STATUS_OK) { + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK) { /* This is to indicate the caller that the core_message_length has been * appropriately set, but the message buffer is either empty or too small, * which needs to be initialized and filled in the subsequent call. */ return OEMCrypto_ERROR_SHORT_BUFFER; } - if (GetSize(msg) != *core_message_length) { + if (ODK_Message_GetSize(&msg) != *core_message_length) { /* This should not happen. Something is wrong. */ return ODK_ERROR_CORE_MESSAGE; } @@ -102,20 +100,11 @@ static OEMCryptoResult ODK_ParseResponse( return ODK_ERROR_CORE_MESSAGE; } - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = (Message*)blk; - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" - /* We initialize the message buffer with a size of the entire message - * length. */ - /* TODO(b/164486737): Fix the cast-qual warning */ - InitMessage(msg, (uint8_t*)message, message_length); -#pragma GCC diagnostic pop + ODK_Message msg = ODK_Message_Create((uint8_t*)message, message_length); /* The core message should be at the beginning of the buffer, and with a * shorter length. The core message is the part we are parsing. */ - SetSize(msg, core_message_length); + ODK_Message_SetSize(&msg, core_message_length); /* Parse message and unpack it into response buffer. */ switch (message_type) { @@ -123,14 +112,14 @@ static OEMCryptoResult ODK_ParseResponse( if (sizeof(ODK_LicenseResponse) > response_buffer_length) { return ODK_ERROR_CORE_MESSAGE; } - Unpack_ODK_LicenseResponse(msg, (ODK_LicenseResponse*)response_buffer); + Unpack_ODK_LicenseResponse(&msg, (ODK_LicenseResponse*)response_buffer); break; } case ODK_Renewal_Response_Type: { if (sizeof(ODK_RenewalResponse) > response_buffer_length) { return ODK_ERROR_CORE_MESSAGE; } - Unpack_ODK_RenewalResponse(msg, (ODK_RenewalResponse*)response_buffer); + Unpack_ODK_RenewalResponse(&msg, (ODK_RenewalResponse*)response_buffer); break; } case ODK_Provisioning_Response_Type: { @@ -138,7 +127,7 @@ static OEMCryptoResult ODK_ParseResponse( return ODK_ERROR_CORE_MESSAGE; } Unpack_ODK_ProvisioningResponse( - msg, (ODK_ProvisioningResponse*)response_buffer); + &msg, (ODK_ProvisioningResponse*)response_buffer); break; } default: { @@ -147,9 +136,9 @@ static OEMCryptoResult ODK_ParseResponse( } ODK_CoreMessage* core_message = (ODK_CoreMessage*)response_buffer; - if (GetStatus(msg) != MESSAGE_STATUS_OK || + if (ODK_Message_GetStatus(&msg) != MESSAGE_STATUS_OK || message_type != core_message->message_type || - GetOffset(msg) != core_message->message_length) { + ODK_Message_GetOffset(&msg) != core_message->message_length) { return ODK_ERROR_CORE_MESSAGE; } @@ -174,7 +163,7 @@ OEMCryptoResult ODK_PrepareCoreLicenseRequest( return ODK_ERROR_CORE_MESSAGE; } ODK_PreparedLicenseRequest license_request = { - {0, 0, {}}, + {0, 0, {0}}, }; return ODK_PrepareRequest( message, message_length, core_message_length, ODK_License_Request_Type, @@ -203,7 +192,7 @@ OEMCryptoResult ODK_PrepareCoreRenewalRequest(uint8_t* message, return OEMCrypto_SUCCESS; } - ODK_PreparedRenewalRequest renewal_request = {{0, 0, {}}, 0}; + ODK_PreparedRenewalRequest renewal_request = {{0, 0, {0}}, 0}; /* First, we compute the time this request was made relative to the playback * clock. */ if (clock_values->time_of_first_decrypt == 0) { @@ -237,7 +226,7 @@ OEMCryptoResult ODK_PrepareCoreProvisioningRequest( return ODK_ERROR_CORE_MESSAGE; } ODK_PreparedProvisioningRequest provisioning_request = { - {0, 0, {}}, + {0, 0, {0}}, 0, {0}, }; @@ -267,7 +256,7 @@ OEMCryptoResult ODK_ParseLicense( return ODK_ERROR_CORE_MESSAGE; } - ODK_LicenseResponse license_response = {{{0, 0, {}}}, NULL, {0}}; + ODK_LicenseResponse license_response = {{{0, 0, {0}}}, NULL, {0}}; license_response.parsed_license = parsed_license; const OEMCryptoResult err = ODK_ParseResponse( @@ -354,7 +343,7 @@ OEMCryptoResult ODK_ParseRenewal(const uint8_t* message, size_t message_length, } ODK_RenewalResponse renewal_response = { - {{0, 0, {}}, 0}, + {{0, 0, {0}}, 0}, 0, }; const OEMCryptoResult err = ODK_ParseResponse( @@ -393,7 +382,7 @@ OEMCryptoResult ODK_ParseProvisioning( return ODK_ERROR_CORE_MESSAGE; } - ODK_ProvisioningResponse provisioning_response = {{{0, 0, {}}, 0, {0}}, NULL}; + ODK_ProvisioningResponse provisioning_response = {{{0, 0, {0}}, 0, {0}}, NULL}; provisioning_response.parsed_provisioning = parsed_response; if (device_id_length > ODK_DEVICE_ID_LEN_MAX) { diff --git a/oemcrypto/odk/src/odk.gyp b/oemcrypto/odk/src/odk.gyp index d1c5a19..f7ec03c 100644 --- a/oemcrypto/odk/src/odk.gyp +++ b/oemcrypto/odk/src/odk.gyp @@ -5,8 +5,10 @@ { 'targets': [ { + 'toolsets' : [ 'target' ], 'target_name': 'odk', 'type': 'static_library', + 'standalone_static_library': 1, 'include_dirs': [ '../include', '../../include', @@ -14,9 +16,27 @@ 'includes' : [ 'odk.gypi', ], + 'cflags': [ + # TODO(b/172518513): Remove this + '-Wno-error=cast-qual', + ], + 'cflags_c': [ + # TODO(b/159354894): Remove this + '-Wno-error=bad-function-cast', + ], + 'defines': [ + # Needed for to work. + '_DEFAULT_SOURCE', + ], 'direct_dependent_settings': { + 'defines': [ + # Needed for to work. + '_DEFAULT_SOURCE', + ], 'include_dirs': [ + '.', '../include', + '../../include', ], } }, diff --git a/oemcrypto/odk/src/odk.gypi b/oemcrypto/odk/src/odk.gypi index 7c33d95..1867605 100644 --- a/oemcrypto/odk/src/odk.gypi +++ b/oemcrypto/odk/src/odk.gypi @@ -7,6 +7,7 @@ { 'sources': [ 'odk.c', + 'odk_message.c', 'odk_overflow.c', 'odk_serialize.c', 'odk_timer.c', diff --git a/oemcrypto/odk/src/odk_endian.h b/oemcrypto/odk/src/odk_endian.h index 459a095..1e9f50d 100644 --- a/oemcrypto/odk/src/odk_endian.h +++ b/oemcrypto/odk/src/odk_endian.h @@ -11,11 +11,23 @@ extern "C" { #if defined(__linux__) || defined(__ANDROID__) #include +#define oemcrypto_htobe16 htobe16 +#define oemcrypto_be16toh be16toh #define oemcrypto_htobe32 htobe32 #define oemcrypto_be32toh be32toh #define oemcrypto_htobe64 htobe64 #define oemcrypto_be64toh be64toh -#else /* defined(__linux__) || defined(__ANDROID__) */ +#elif defined(__APPLE__) +#include +#define oemcrypto_htobe16 OSSwapHostToBigInt16 +#define oemcrypto_be16toh OSSwapBigToHostInt16 +#define oemcrypto_htobe32 OSSwapHostToBigInt32 +#define oemcrypto_be32toh OSSwapBigToHostInt32 +#define oemcrypto_htobe64 OSSwapHostToBigInt64 +#define oemcrypto_be64toh OSSwapBigToHostInt64 +#else /* defined(__linux__) || defined(__ANDROID__) */ +uint32_t oemcrypto_htobe16(uint16_t u16); +uint32_t oemcrypto_be16toh(uint16_t u16); uint32_t oemcrypto_htobe32(uint32_t u32); uint32_t oemcrypto_be32toh(uint32_t u32); uint64_t oemcrypto_htobe64(uint64_t u64); diff --git a/oemcrypto/odk/src/odk_message.c b/oemcrypto/odk/src/odk_message.c new file mode 100644 index 0000000..ea0f9e4 --- /dev/null +++ b/oemcrypto/odk/src/odk_message.c @@ -0,0 +1,171 @@ +/* + * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#include "odk_message.h" +#include "odk_message_priv.h" + +#include +#include +#include + +/* + * C11 defines static_assert in assert.h. If it is available, force a compile + * time error if the abstract ODK_Message struct size does not match its + * implementation. If static_assert is not available, the runtime assert in + * InitMessage will catch the mismatch at the time a message is initialized. + */ +#ifdef static_assert +static_assert( + sizeof(ODK_Message) >= sizeof(ODK_Message_Impl), + "sizeof(ODK_Message) is too small. You can increase " + "SIZE_OF_ODK_MESSAGE_IMPL in odk_message.h to make it large enough."); +#endif + +/* + * Create a message structure that references a separate data buffer. An + * initialized message is returned. The caller is responsible for ensuring that + * the buffer remains allocated for the lifetime of the message. |buffer| may be + * NULL. Serialization into a message with a NULL buffer will cause the message + * size to be incremented, but no data will be written into the message + * buffer. This is useful for calculating the amount of space a message will + * need, prior to doing the actual serialization. The buffer contents are + * unchanged by this function. + */ +ODK_Message ODK_Message_Create(uint8_t* buffer, size_t capacity) { + assert(sizeof(ODK_Message) >= sizeof(ODK_Message_Impl)); + ODK_Message message; + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)&message; + message_impl->base = buffer; + message_impl->capacity = capacity; + message_impl->size = 0; + message_impl->read_offset = 0; + message_impl->status = MESSAGE_STATUS_OK; + return message; +} + +/* + * Erase the contents of the message, set it to an empty state by setting the + * message size and read offset to 0, effectively erasing the contents of the + * message. The message data buffer pointer remains unchanged, i.e. the message + * retains ownership of the buffer. The message buffer is zero-filled. The + * message status is reset to MESSAGE_STATUS_OK. + */ +void ODK_Message_Clear(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + message_impl->read_offset = 0; + message_impl->size = 0; + message_impl->status = MESSAGE_STATUS_OK; + if (message_impl->base) { + memset(message_impl->base, 0, message_impl->capacity); + } +} + +/* + * Reset read pointer to the beginning of the message and clear status + * so that parsing of the message will restart at the beginning of the + * message. The message status is reset to MESSAGE_STATUS_OK. + */ +void ODK_Message_Reset(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + message_impl->read_offset = 0; + message_impl->status = MESSAGE_STATUS_OK; +} + +/* + * Return a pointer to the message data buffer, i.e. the message payload. + * This is the buffer address that was passed into ODK_Message_Create. + */ +uint8_t* ODK_Message_GetBase(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->base; +} + +/* + * Get the maximum number of bytes the message can hold. + */ +size_t ODK_Message_GetCapacity(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->capacity; +} + +/* + * Get the number of bytes currently in the message + */ +size_t ODK_Message_GetSize(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->size; +} + +/* + * Get the offset of where the next bytes will be read from the message data + * buffer. + */ +size_t ODK_Message_GetOffset(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->read_offset; +} + +/* + * Return the status of the message + */ +ODK_MessageStatus ODK_Message_GetStatus(ODK_Message* message) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + return message_impl->status; +} + +/* + * Set the message status to a specific value + */ +void ODK_Message_SetStatus(ODK_Message* message, ODK_MessageStatus status) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + /* preserve the first error */ + if (message_impl->status == MESSAGE_STATUS_OK) { + message_impl->status = status; + } +} + +/* + * Set the size of the message to a value. This may be needed after writing data + * into the message data buffer. + */ +void ODK_Message_SetSize(ODK_Message* message, size_t size) { + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + assert(message_impl != NULL); + assert(size <= message_impl->capacity); + message_impl->size = size; +} + +/* + * Test if the integrity of a message. This means that the status must be + * MESSAGE_STATUS_OK and that the base, read_offset, size and capacity of the + * message are within the range of valid values. The message's base pointer + * may be NULL if the buffer has not been assigned yet, that is not invalid. + */ +bool ODK_Message_IsValid(ODK_Message* message) { + assert(message); + ODK_Message_Impl* message_impl = (ODK_Message_Impl*)message; + if (message_impl == NULL) { + return false; + } + if (message_impl->status != MESSAGE_STATUS_OK) { + return false; + } + if (message_impl->read_offset > message_impl->capacity || + message_impl->size > message_impl->capacity || + message_impl->read_offset > message_impl->size) { + message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; + return false; + } + return true; +} diff --git a/oemcrypto/odk/src/odk_message_priv.h b/oemcrypto/odk/src/odk_message_priv.h new file mode 100644 index 0000000..4a91164 --- /dev/null +++ b/oemcrypto/odk/src/odk_message_priv.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary + * source code may only be used and distributed under the Widevine + * License Agreement. + */ + +#ifndef WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_ +#define WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This file must only be included by odk_message.c and serialization_base.c. + */ + +#include +#include + +/* + * This is the implementation of a message. This structure is private, i.e. it + * should only be included by files that are allowed to modify the internals of + * a message, that being odk_message.c and serialization_base.c. To ensure + * proper alignment and message size, an ODK_Message_Impl should never be + * allocated directly, instead allocate ODK_Message and cast to ODK_Message_Impl + * because ODK_Message_Impl may be smaller than ODK_Message. + */ +typedef struct { + uint8_t* base; + size_t capacity; + size_t size; + size_t read_offset; + ODK_MessageStatus status; +} ODK_Message_Impl; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // WIDEVINE_ODK_INCLUDE_ODK_MESSAGE_PRIV_H_ diff --git a/oemcrypto/odk/src/odk_overflow.c b/oemcrypto/odk/src/odk_overflow.c index b679e01..0ebc084 100644 --- a/oemcrypto/odk/src/odk_overflow.c +++ b/oemcrypto/odk/src/odk_overflow.c @@ -34,3 +34,13 @@ int odk_add_overflow_ux(size_t a, size_t b, size_t* c) { } return 1; } + +int odk_mul_overflow_ux(size_t a, size_t b, size_t* c) { + if (b > 0 && a > SIZE_MAX / b) { + return 1; + } + if (c) { + *c = a * b; + } + return 0; +} diff --git a/oemcrypto/odk/src/odk_overflow.h b/oemcrypto/odk/src/odk_overflow.h index 75cd52b..e725705 100644 --- a/oemcrypto/odk/src/odk_overflow.h +++ b/oemcrypto/odk/src/odk_overflow.h @@ -15,6 +15,7 @@ extern "C" { int odk_sub_overflow_u64(uint64_t a, uint64_t b, uint64_t* c); int odk_add_overflow_u64(uint64_t a, uint64_t b, uint64_t* c); int odk_add_overflow_ux(size_t a, size_t b, size_t* c); +int odk_mul_overflow_ux(size_t a, size_t b, size_t* c); #ifdef __cplusplus } diff --git a/oemcrypto/odk/src/odk_serialize.c b/oemcrypto/odk/src/odk_serialize.c index c35e9b5..35a5539 100644 --- a/oemcrypto/odk/src/odk_serialize.c +++ b/oemcrypto/odk/src/odk_serialize.c @@ -13,20 +13,20 @@ /* @@ private serialize */ -static void Pack_ODK_NonceValues(Message* msg, ODK_NonceValues const* obj) { +static void Pack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues const* obj) { Pack_uint16_t(msg, &obj->api_minor_version); Pack_uint16_t(msg, &obj->api_major_version); Pack_uint32_t(msg, &obj->nonce); Pack_uint32_t(msg, &obj->session_id); } -static void Pack_ODK_CoreMessage(Message* msg, ODK_CoreMessage const* obj) { +static void Pack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage const* obj) { Pack_uint32_t(msg, &obj->message_type); Pack_uint32_t(msg, &obj->message_length); Pack_ODK_NonceValues(msg, &obj->nonce_values); } -static void Pack_OEMCrypto_KeyObject(Message* msg, +static void Pack_OEMCrypto_KeyObject(ODK_Message* msg, OEMCrypto_KeyObject const* obj) { Pack_OEMCrypto_Substring(msg, &obj->key_id); Pack_OEMCrypto_Substring(msg, &obj->key_data_iv); @@ -35,7 +35,7 @@ static void Pack_OEMCrypto_KeyObject(Message* msg, Pack_OEMCrypto_Substring(msg, &obj->key_control); } -static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) { +static void Pack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits const* obj) { Pack_bool(msg, &obj->soft_enforce_rental_duration); Pack_bool(msg, &obj->soft_enforce_playback_duration); Pack_uint64_t(msg, &obj->earliest_playback_start_seconds); @@ -44,10 +44,11 @@ static void Pack_ODK_TimerLimits(Message* msg, ODK_TimerLimits const* obj) { Pack_uint64_t(msg, &obj->initial_renewal_duration_seconds); } -static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) { +static void Pack_ODK_ParsedLicense(ODK_Message* msg, + ODK_ParsedLicense const* obj) { /* hand-coded */ if (obj->key_array_length > ODK_MAX_NUM_KEYS) { - SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); return; } Pack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); @@ -64,7 +65,7 @@ static void Pack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense const* obj) { } } -static void Pack_ODK_ParsedProvisioning(Message* msg, +static void Pack_ODK_ParsedProvisioning(ODK_Message* msg, ODK_ParsedProvisioning const* obj) { Pack_enum(msg, obj->key_type); Pack_OEMCrypto_Substring(msg, &obj->enc_private_key); @@ -74,19 +75,19 @@ static void Pack_ODK_ParsedProvisioning(Message* msg, /* @@ odk serialize */ -void Pack_ODK_PreparedLicenseRequest(Message* msg, +void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest const* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); } -void Pack_ODK_PreparedRenewalRequest(Message* msg, +void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest const* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_uint64_t(msg, &obj->playback_time); } void Pack_ODK_PreparedProvisioningRequest( - Message* msg, ODK_PreparedProvisioningRequest const* obj) { + ODK_Message* msg, ODK_PreparedProvisioningRequest const* obj) { Pack_ODK_CoreMessage(msg, &obj->core_message); Pack_uint32_t(msg, &obj->device_id_length); PackArray(msg, &obj->device_id[0], sizeof(obj->device_id)); @@ -94,18 +95,20 @@ void Pack_ODK_PreparedProvisioningRequest( /* @@ kdo serialize */ -void Pack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse const* obj) { +void Pack_ODK_LicenseResponse(ODK_Message* msg, + ODK_LicenseResponse const* obj) { Pack_ODK_PreparedLicenseRequest(msg, &obj->request); Pack_ODK_ParsedLicense(msg, (const ODK_ParsedLicense*)obj->parsed_license); PackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); } -void Pack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse const* obj) { +void Pack_ODK_RenewalResponse(ODK_Message* msg, + ODK_RenewalResponse const* obj) { Pack_ODK_PreparedRenewalRequest(msg, &obj->request); Pack_uint64_t(msg, &obj->renewal_duration_seconds); } -void Pack_ODK_ProvisioningResponse(Message* msg, +void Pack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse const* obj) { Pack_ODK_PreparedProvisioningRequest(msg, &obj->request); Pack_ODK_ParsedProvisioning( @@ -116,20 +119,21 @@ void Pack_ODK_ProvisioningResponse(Message* msg, /* @@ private deserialize */ -static void Unpack_ODK_NonceValues(Message* msg, ODK_NonceValues* obj) { +static void Unpack_ODK_NonceValues(ODK_Message* msg, ODK_NonceValues* obj) { Unpack_uint16_t(msg, &obj->api_minor_version); Unpack_uint16_t(msg, &obj->api_major_version); Unpack_uint32_t(msg, &obj->nonce); Unpack_uint32_t(msg, &obj->session_id); } -static void Unpack_ODK_CoreMessage(Message* msg, ODK_CoreMessage* obj) { +static void Unpack_ODK_CoreMessage(ODK_Message* msg, ODK_CoreMessage* obj) { Unpack_uint32_t(msg, &obj->message_type); Unpack_uint32_t(msg, &obj->message_length); Unpack_ODK_NonceValues(msg, &obj->nonce_values); } -static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) { +static void Unpack_OEMCrypto_KeyObject(ODK_Message* msg, + OEMCrypto_KeyObject* obj) { Unpack_OEMCrypto_Substring(msg, &obj->key_id); Unpack_OEMCrypto_Substring(msg, &obj->key_data_iv); Unpack_OEMCrypto_Substring(msg, &obj->key_data); @@ -137,7 +141,7 @@ static void Unpack_OEMCrypto_KeyObject(Message* msg, OEMCrypto_KeyObject* obj) { Unpack_OEMCrypto_Substring(msg, &obj->key_control); } -static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) { +static void Unpack_ODK_TimerLimits(ODK_Message* msg, ODK_TimerLimits* obj) { Unpack_bool(msg, &obj->soft_enforce_rental_duration); Unpack_bool(msg, &obj->soft_enforce_playback_duration); Unpack_uint64_t(msg, &obj->earliest_playback_start_seconds); @@ -146,7 +150,7 @@ static void Unpack_ODK_TimerLimits(Message* msg, ODK_TimerLimits* obj) { Unpack_uint64_t(msg, &obj->initial_renewal_duration_seconds); } -static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) { +static void Unpack_ODK_ParsedLicense(ODK_Message* msg, ODK_ParsedLicense* obj) { Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys_iv); Unpack_OEMCrypto_Substring(msg, &obj->enc_mac_keys); Unpack_OEMCrypto_Substring(msg, &obj->pst); @@ -156,7 +160,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) { Unpack_ODK_TimerLimits(msg, &obj->timer_limits); Unpack_uint32_t(msg, &obj->key_array_length); if (obj->key_array_length > ODK_MAX_NUM_KEYS) { - SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); + ODK_Message_SetStatus(msg, MESSAGE_STATUS_OVERFLOW_ERROR); return; } uint32_t i; @@ -165,7 +169,7 @@ static void Unpack_ODK_ParsedLicense(Message* msg, ODK_ParsedLicense* obj) { } } -static void Unpack_ODK_ParsedProvisioning(Message* msg, +static void Unpack_ODK_ParsedProvisioning(ODK_Message* msg, ODK_ParsedProvisioning* obj) { obj->key_type = (OEMCrypto_PrivateKeyType)Unpack_enum(msg); Unpack_OEMCrypto_Substring(msg, &obj->enc_private_key); @@ -175,42 +179,42 @@ static void Unpack_ODK_ParsedProvisioning(Message* msg, /* @ kdo deserialize */ -void Unpack_ODK_PreparedLicenseRequest(Message* msg, +void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); } -void Unpack_ODK_PreparedRenewalRequest(Message* msg, +void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); Unpack_uint64_t(msg, &obj->playback_time); } void Unpack_ODK_PreparedProvisioningRequest( - Message* msg, ODK_PreparedProvisioningRequest* obj) { + ODK_Message* msg, ODK_PreparedProvisioningRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); Unpack_uint32_t(msg, &obj->device_id_length); UnpackArray(msg, &obj->device_id[0], sizeof(obj->device_id)); } -void Unpack_ODK_PreparedCommonRequest(Message* msg, +void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, ODK_PreparedCommonRequest* obj) { Unpack_ODK_CoreMessage(msg, &obj->core_message); } /* @@ odk deserialize */ -void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj) { +void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj) { Unpack_ODK_PreparedLicenseRequest(msg, &obj->request); Unpack_ODK_ParsedLicense(msg, obj->parsed_license); UnpackArray(msg, &obj->request_hash[0], sizeof(obj->request_hash)); } -void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj) { +void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj) { Unpack_ODK_PreparedRenewalRequest(msg, &obj->request); Unpack_uint64_t(msg, &obj->renewal_duration_seconds); } -void Unpack_ODK_ProvisioningResponse(Message* msg, +void Unpack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse* obj) { Unpack_ODK_PreparedProvisioningRequest(msg, &obj->request); Unpack_ODK_ParsedProvisioning(msg, obj->parsed_provisioning); diff --git a/oemcrypto/odk/src/odk_serialize.h b/oemcrypto/odk/src/odk_serialize.h index 0816bf7..ca5b540 100644 --- a/oemcrypto/odk/src/odk_serialize.h +++ b/oemcrypto/odk/src/odk_serialize.h @@ -16,34 +16,34 @@ extern "C" { #endif /* odk pack */ -void Pack_ODK_PreparedLicenseRequest(Message* msg, +void Pack_ODK_PreparedLicenseRequest(ODK_Message* msg, const ODK_PreparedLicenseRequest* obj); -void Pack_ODK_PreparedRenewalRequest(Message* msg, +void Pack_ODK_PreparedRenewalRequest(ODK_Message* msg, const ODK_PreparedRenewalRequest* obj); void Pack_ODK_PreparedProvisioningRequest( - Message* msg, const ODK_PreparedProvisioningRequest* obj); + ODK_Message* msg, const ODK_PreparedProvisioningRequest* obj); /* odk unpack */ -void Unpack_ODK_LicenseResponse(Message* msg, ODK_LicenseResponse* obj); -void Unpack_ODK_RenewalResponse(Message* msg, ODK_RenewalResponse* obj); -void Unpack_ODK_ProvisioningResponse(Message* msg, +void Unpack_ODK_LicenseResponse(ODK_Message* msg, ODK_LicenseResponse* obj); +void Unpack_ODK_RenewalResponse(ODK_Message* msg, ODK_RenewalResponse* obj); +void Unpack_ODK_ProvisioningResponse(ODK_Message* msg, ODK_ProvisioningResponse* obj); /* kdo pack */ -void Pack_ODK_LicenseResponse(Message* msg, const ODK_LicenseResponse* obj); -void Pack_ODK_RenewalResponse(Message* msg, const ODK_RenewalResponse* obj); -void Pack_ODK_ProvisioningResponse(Message* msg, +void Pack_ODK_LicenseResponse(ODK_Message* msg, const ODK_LicenseResponse* obj); +void Pack_ODK_RenewalResponse(ODK_Message* msg, const ODK_RenewalResponse* obj); +void Pack_ODK_ProvisioningResponse(ODK_Message* msg, const ODK_ProvisioningResponse* obj); /* kdo unpack */ -void Unpack_ODK_PreparedLicenseRequest(Message* msg, +void Unpack_ODK_PreparedLicenseRequest(ODK_Message* msg, ODK_PreparedLicenseRequest* obj); -void Unpack_ODK_PreparedRenewalRequest(Message* msg, +void Unpack_ODK_PreparedRenewalRequest(ODK_Message* msg, ODK_PreparedRenewalRequest* obj); void Unpack_ODK_PreparedProvisioningRequest( - Message* msg, ODK_PreparedProvisioningRequest* obj); + ODK_Message* msg, ODK_PreparedProvisioningRequest* obj); -void Unpack_ODK_PreparedCommonRequest(Message* msg, +void Unpack_ODK_PreparedCommonRequest(ODK_Message* msg, ODK_PreparedCommonRequest* obj); #ifdef __cplusplus diff --git a/oemcrypto/odk/src/odk_structs_priv.h b/oemcrypto/odk/src/odk_structs_priv.h index 6b138f4..dd9eb20 100644 --- a/oemcrypto/odk/src/odk_structs_priv.h +++ b/oemcrypto/odk/src/odk_structs_priv.h @@ -74,26 +74,26 @@ typedef struct { // without any padding added by the compiler. Make sure they get updated when // request structs change. Refer to test suite OdkSizeTest in // ../test/odk_test.cpp for validations of each of the defined request sizes. -#define ODK_LICENSE_REQUEST_SIZE 20 -#define ODK_RENEWAL_REQUEST_SIZE 28 -#define ODK_PROVISIONING_REQUEST_SIZE 88 +#define ODK_LICENSE_REQUEST_SIZE 20u +#define ODK_RENEWAL_REQUEST_SIZE 28u +#define ODK_PROVISIONING_REQUEST_SIZE 88u // These are the possible timer status values. -#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0 // Should not happen. +#define ODK_CLOCK_TIMER_STATUS_UNDEFINED 0u // Should not happen. // When the structure has been initialized, but no license is loaded. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_NOT_LOADED 1u // After the license is loaded, before a successful decrypt. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_LOADED 2u // After the license is loaded, if a renewal has also been loaded. -#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3 +#define ODK_CLOCK_TIMER_STATUS_RENEWAL_LOADED 3u // The first decrypt has occurred and the timer is active. -#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4 +#define ODK_CLOCK_TIMER_STATUS_ACTIVE 4u // The first decrypt has occurred and the timer is unlimited. -#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5 +#define ODK_CLOCK_TIMER_STATUS_UNLIMITED 5u // The timer has transitioned from active to expired. -#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6 +#define ODK_CLOCK_TIMER_STATUS_EXPIRED 6u // The license has been marked as inactive. -#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7 +#define ODK_CLOCK_TIMER_STATUS_LICENSE_INACTIVE 7u // A helper function for computing timer limits when a renewal is loaded. OEMCryptoResult ODK_ComputeRenewalDuration(const ODK_TimerLimits* timer_limits, diff --git a/oemcrypto/odk/src/serialization_base.c b/oemcrypto/odk/src/serialization_base.c index 6e6674c..1ee6201 100644 --- a/oemcrypto/odk/src/serialization_base.c +++ b/oemcrypto/odk/src/serialization_base.c @@ -4,233 +4,175 @@ #include "serialization_base.h" +#include #include #include #include #include "OEMCryptoCENCCommon.h" +#include "odk_message.h" +#include "odk_message_priv.h" #include "odk_overflow.h" -struct _Message { - uint8_t* base; - size_t capacity; - size_t size; /* bytes written */ - size_t read_offset; /* bytes read */ - MessageStatus status; -}; - -bool ValidMessage(Message* message) { - if (message == NULL) { - return false; - } - if (message->status != MESSAGE_STATUS_OK) { - return false; - } - if (message->base == NULL) { - message->status = MESSAGE_STATUS_NULL_POINTER_ERROR; - return false; - } - if (message->size > message->capacity || - message->read_offset > message->size) { - message->status = MESSAGE_STATUS_OVERFLOW_ERROR; - return false; - } - return true; +/* + * An ODK_Message_Impl pointer must only be obtained by calling GetMessageImpl. + * This forces any message to pass the validity check before being operated on, + * which means that no function can modify or access the internals of a message + * without having it be validated first. + */ +static ODK_Message_Impl* GetMessageImpl(ODK_Message* message) { + if (!ODK_Message_IsValid(message)) return NULL; + return (ODK_Message_Impl*)message; } -static void PackBytes(Message* message, const uint8_t* ptr, size_t count) { - if (count <= message->capacity - message->size) { - memcpy((void*)(message->base + message->size), (void*)ptr, count); - message->size += count; +static void PackBytes(ODK_Message* message, const uint8_t* ptr, size_t count) { + ODK_Message_Impl* message_impl = GetMessageImpl(message); + if (!message_impl) return; + if (count <= message_impl->capacity - message_impl->size) { + memcpy((void*)(message_impl->base + message_impl->size), (const void*)ptr, + count); + message_impl->size += count; } else { - message->status = MESSAGE_STATUS_OVERFLOW_ERROR; + message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; } } -void Pack_enum(Message* message, int value) { +void Pack_enum(ODK_Message* message, int value) { uint32_t v32 = value; Pack_uint32_t(message, &v32); } -void Pack_bool(Message* message, const bool* value) { - if (!ValidMessage(message)) return; +void Pack_bool(ODK_Message* message, const bool* value) { + assert(value); uint8_t data[4] = {0}; data[3] = *value ? 1 : 0; PackBytes(message, data, sizeof(data)); } -void Pack_uint16_t(Message* message, const uint16_t* value) { - if (!ValidMessage(message)) return; +void Pack_uint16_t(ODK_Message* message, const uint16_t* value) { + assert(value); uint8_t data[2] = {0}; - data[0] = *value >> 8; - data[1] = *value >> 0; + data[0] = (uint8_t)(*value >> 8); + data[1] = (uint8_t)(*value >> 0); PackBytes(message, data, sizeof(data)); } -void Pack_uint32_t(Message* message, const uint32_t* value) { - if (!ValidMessage(message)) return; +void Pack_uint32_t(ODK_Message* message, const uint32_t* value) { + assert(value); uint8_t data[4] = {0}; - data[0] = *value >> 24; - data[1] = *value >> 16; - data[2] = *value >> 8; - data[3] = *value >> 0; + data[0] = (uint8_t)(*value >> 24); + data[1] = (uint8_t)(*value >> 16); + data[2] = (uint8_t)(*value >> 8); + data[3] = (uint8_t)(*value >> 0); PackBytes(message, data, sizeof(data)); } -void Pack_uint64_t(Message* message, const uint64_t* value) { - if (!ValidMessage(message)) return; - uint32_t hi = *value >> 32; - uint32_t lo = *value; +void Pack_uint64_t(ODK_Message* message, const uint64_t* value) { + assert(value); + uint32_t hi = (uint32_t)(*value >> 32); + uint32_t lo = (uint32_t)(*value); Pack_uint32_t(message, &hi); Pack_uint32_t(message, &lo); } -void PackArray(Message* message, const uint8_t* base, size_t size) { - if (!ValidMessage(message)) return; +void PackArray(ODK_Message* message, const uint8_t* base, size_t size) { PackBytes(message, base, size); } -void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj) { +void Pack_OEMCrypto_Substring(ODK_Message* message, + const OEMCrypto_Substring* obj) { + assert(obj); uint32_t offset = (uint32_t)obj->offset; uint32_t length = (uint32_t)obj->length; - Pack_uint32_t(msg, &offset); - Pack_uint32_t(msg, &length); + Pack_uint32_t(message, &offset); + Pack_uint32_t(message, &length); } -static void UnpackBytes(Message* message, uint8_t* ptr, size_t count) { - if (count <= message->size - message->read_offset) { - memcpy((void*)ptr, (void*)(message->base + message->read_offset), count); - message->read_offset += count; +static void UnpackBytes(ODK_Message* message, uint8_t* ptr, size_t count) { + assert(ptr); + ODK_Message_Impl* message_impl = GetMessageImpl(message); + if (!message_impl) return; + if (count <= message_impl->size - message_impl->read_offset) { + memcpy((void*)ptr, (void*)(message_impl->base + message_impl->read_offset), + count); + message_impl->read_offset += count; } else { - message->status = MESSAGE_STATUS_UNDERFLOW_ERROR; + message_impl->status = MESSAGE_STATUS_UNDERFLOW_ERROR; } } -int Unpack_enum(Message* message) { +int Unpack_enum(ODK_Message* message) { uint32_t v32; Unpack_uint32_t(message, &v32); - return v32; + return (int)v32; } -void Unpack_bool(Message* message, bool* value) { - if (!ValidMessage(message)) return; +void Unpack_bool(ODK_Message* message, bool* value) { uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); + assert(value); *value = (0 != data[3]); } -void Unpack_uint16_t(Message* message, uint16_t* value) { - if (!ValidMessage(message)) return; +void Unpack_uint16_t(ODK_Message* message, uint16_t* value) { + assert(value); uint8_t data[2] = {0}; UnpackBytes(message, data, sizeof(data)); *value = data[0]; *value = *value << 8 | data[1]; } -void Unpack_uint32_t(Message* message, uint32_t* value) { - if (!ValidMessage(message)) return; +void Unpack_uint32_t(ODK_Message* message, uint32_t* value) { + ODK_Message_Impl* message_impl = GetMessageImpl(message); + if (!message_impl) return; uint8_t data[4] = {0}; UnpackBytes(message, data, sizeof(data)); + assert(value); *value = data[0]; *value = *value << 8 | data[1]; *value = *value << 8 | data[2]; *value = *value << 8 | data[3]; } -void Unpack_uint64_t(Message* message, uint64_t* value) { - if (!ValidMessage(message)) return; +void Unpack_uint64_t(ODK_Message* message, uint64_t* value) { uint32_t hi = 0; uint32_t lo = 0; Unpack_uint32_t(message, &hi); Unpack_uint32_t(message, &lo); + assert(value); *value = hi; *value = *value << 32 | lo; } -void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj) { +void Unpack_OEMCrypto_Substring(ODK_Message* message, + OEMCrypto_Substring* obj) { uint32_t offset = 0, length = 0; - Unpack_uint32_t(msg, &offset); - Unpack_uint32_t(msg, &length); - if (!ValidMessage(msg)) return; + Unpack_uint32_t(message, &offset); + Unpack_uint32_t(message, &length); + ODK_Message_Impl* message_impl = GetMessageImpl(message); + if (!message_impl) return; + /* Each substring should be contained within the message body, which is in the * total message, just after the core message. The offset of a substring is * relative to the message body. So we need to verify: - * 0 < offset and offset + length < message->capacity - message->size - * or offset + length + message->size < message->capacity + * 0 < offset and offset + length < message_impl->capacity - + * message_impl->size or offset + length + message_impl->size < + * message_impl->capacity */ size_t substring_end = 0; /* = offset + length; */ - size_t end = 0; /* = substring_end + message->size; */ + size_t end = 0; /* = substring_end + message_impl->size; */ if (odk_add_overflow_ux(offset, length, &substring_end) || - odk_add_overflow_ux(substring_end, msg->size, &end) || - end > msg->capacity) { - msg->status = MESSAGE_STATUS_OVERFLOW_ERROR; + odk_add_overflow_ux(substring_end, message_impl->size, &end) || + end > message_impl->capacity) { + message_impl->status = MESSAGE_STATUS_OVERFLOW_ERROR; return; } + assert(obj); obj->offset = offset; obj->length = length; } /* copy out */ -void UnpackArray(Message* message, uint8_t* address, size_t size) { - if (!ValidMessage(message)) return; +void UnpackArray(ODK_Message* message, uint8_t* address, size_t size) { UnpackBytes(message, address, size); } - -/* - * The message structure, which is separate from the buffer, - * is initialized to reference the buffer - */ -void InitMessage(Message* message, uint8_t* buffer, size_t capacity) { - if (message == NULL) return; - memset(message, 0, sizeof(Message)); - message->base = buffer; - message->capacity = capacity; - message->size = 0; - message->read_offset = 0; - message->status = MESSAGE_STATUS_OK; -} - -/* - * Set the message to an empty state - */ -void ResetMessage(Message* message) { - message->size = 0; - message->read_offset = 0; - message->status = MESSAGE_STATUS_OK; -} - -uint8_t* GetBase(Message* message) { - if (message == NULL) return NULL; - return message->base; -} - -size_t GetCapacity(Message* message) { - if (message == NULL) return 0; - return message->capacity; -} - -size_t GetSize(Message* message) { - if (message == NULL) return 0; - return message->size; -} - -void SetSize(Message* message, size_t size) { - if (message == NULL) return; - if (size > message->capacity) - message->status = MESSAGE_STATUS_OVERFLOW_ERROR; - else - message->size = size; -} - -MessageStatus GetStatus(Message* message) { return message->status; } - -void SetStatus(Message* message, MessageStatus status) { - message->status = status; -} - -size_t GetOffset(Message* message) { - if (message == NULL) return 0; - return message->read_offset; -} - -size_t SizeOfMessageStruct() { return sizeof(Message); } diff --git a/oemcrypto/odk/src/serialization_base.h b/oemcrypto/odk/src/serialization_base.h index e1f3969..0a8b2e2 100644 --- a/oemcrypto/odk/src/serialization_base.h +++ b/oemcrypto/odk/src/serialization_base.h @@ -13,74 +13,24 @@ extern "C" { #include #include "OEMCryptoCENCCommon.h" +#include "odk_message.h" -#define SIZE_OF_MESSAGE_STRUCT 64 +void Pack_enum(ODK_Message* message, int value); +void Pack_bool(ODK_Message* message, const bool* value); +void Pack_uint16_t(ODK_Message* message, const uint16_t* value); +void Pack_uint32_t(ODK_Message* message, const uint32_t* value); +void Pack_uint64_t(ODK_Message* message, const uint64_t* value); +void PackArray(ODK_Message* message, const uint8_t* base, size_t size); +void Pack_OEMCrypto_Substring(ODK_Message* msg, const OEMCrypto_Substring* obj); -/* - * Description: - * Point |msg| to stack-array |blk|. - * |blk| is guaranteed large enough to hold a |Message| struct. - * |blk| cannot be used in the same scope as a variable name. - * |msg| points to valid memory in the same scope |AllocateMessage| is used. - * Parameters: - * msg: pointer to pointer to |Message| struct - * blk: variable name for stack-array - */ -#define AllocateMessage(msg, blk) \ - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; \ - *(msg) = (Message*)(blk) - -typedef struct _Message Message; - -typedef enum { - MESSAGE_STATUS_OK, - MESSAGE_STATUS_UNKNOWN_ERROR, - MESSAGE_STATUS_OVERFLOW_ERROR, - MESSAGE_STATUS_UNDERFLOW_ERROR, - MESSAGE_STATUS_PARSE_ERROR, - MESSAGE_STATUS_NULL_POINTER_ERROR, - MESSAGE_STATUS_API_VALUE_ERROR -} MessageStatus; - -bool ValidMessage(Message* message); - -void Pack_enum(Message* message, int value); -void Pack_bool(Message* message, const bool* value); -void Pack_uint16_t(Message* message, const uint16_t* value); -void Pack_uint32_t(Message* message, const uint32_t* value); -void Pack_uint64_t(Message* message, const uint64_t* value); -void PackArray(Message* message, const uint8_t* base, size_t size); -void Pack_OEMCrypto_Substring(Message* msg, const OEMCrypto_Substring* obj); - -int Unpack_enum(Message* message); -void Unpack_bool(Message* message, bool* value); -void Unpack_uint16_t(Message* message, uint16_t* value); -void Unpack_uint32_t(Message* message, uint32_t* value); -void Unpack_uint64_t(Message* message, uint64_t* value); -void UnpackArray(Message* message, uint8_t* address, +int Unpack_enum(ODK_Message* message); +void Unpack_bool(ODK_Message* message, bool* value); +void Unpack_uint16_t(ODK_Message* message, uint16_t* value); +void Unpack_uint32_t(ODK_Message* message, uint32_t* value); +void Unpack_uint64_t(ODK_Message* message, uint64_t* value); +void UnpackArray(ODK_Message* message, uint8_t* address, size_t size); /* copy out */ -void Unpack_OEMCrypto_Substring(Message* msg, OEMCrypto_Substring* obj); - -/* - * Initialize a message structure to reference a separate buffer. The caller - * is responsible for ensuring that the buffer remains allocated for the - * lifetime of the message. - */ -void InitMessage(Message* message, uint8_t* buffer, size_t capacity); - -/* - * Reset an existing the message to an empty state - */ -void ResetMessage(Message* message); -uint8_t* GetBase(Message* message); -size_t GetCapacity(Message* message); -size_t GetSize(Message* message); -void SetSize(Message* message, size_t size); -MessageStatus GetStatus(Message* message); -void SetStatus(Message* message, MessageStatus status); -size_t GetOffset(Message* message); - -size_t SizeOfMessageStruct(); +void Unpack_OEMCrypto_Substring(ODK_Message* msg, OEMCrypto_Substring* obj); #ifdef __cplusplus } // extern "C" diff --git a/oemcrypto/odk/test/fuzzing/Android.bp b/oemcrypto/odk/test/fuzzing/Android.bp index d7390f9..3b8fe6d 100644 --- a/oemcrypto/odk/test/fuzzing/Android.bp +++ b/oemcrypto/odk/test/fuzzing/Android.bp @@ -2,6 +2,18 @@ // source code may only be used and distributed under the Widevine // License Agreement. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_defaults { name: "odk_fuzz_library_defaults", srcs: [ @@ -165,4 +177,4 @@ cc_fuzz { ], defaults: ["odk_fuzz_library_defaults"], proprietary: true, -} \ No newline at end of file +} diff --git a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp index 522c2b8..78519cb 100644 --- a/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp +++ b/oemcrypto/odk/test/fuzzing/corpus_generator/Android.bp @@ -9,6 +9,18 @@ // ---------------------------------------------------------------- // Builds libwv_odk.so, The ODK shared Library (libwv_odk) is used // by the OEMCrypto unit tests to generate corpus for ODK fuzz scrips. +// *** THIS PACKAGE HAS SPECIAL LICENSING CONDITIONS. PLEASE +// CONSULT THE OWNERS AND opensource-licensing@google.com BEFORE +// DEPENDING ON IT IN YOUR PROJECT. *** +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "vendor_widevine_license" + // to get the below license kinds: + // legacy_by_exception_only (by exception only) + default_applicable_licenses: ["vendor_widevine_license"], +} + cc_library_shared { name: "libwv_odk_corpus_generator", include_dirs: [ diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp index 548d38a..c17b5d1 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz.gyp @@ -18,16 +18,34 @@ '../src', '../kdo/include', ], - 'cflags_cc': [ - '-std=c++11', + 'cflags': [ '-g3', '-O0', - '-fsanitize=fuzzer,address,undefined', '-fno-omit-frame-pointer', + '-U_FORTIFY_SOURCE', + '-fsanitize=fuzzer,address,undefined', + '-fno-sanitize-recover=address,undefined', + '-fPIC', + # TODO(b/172518513): Remove this + '-Wno-error=cast-qual', + ], + 'cflags_c': [ + '-std=c99', + '-D_POSIX_C_SOURCE=200809L', + # TODO(b/159354894): Remove this + '-Wno-error=bad-function-cast', + ], + 'cflags_cc': [ + '-std=c++11', + '-frtti', ], 'ldflags': [ '-fPIC', - '-fsanitize=fuzzer,address,undefined', + # Sanitizers with link-time components must be repeated here. + '-fsanitize=fuzzer,address', + ], + 'libraries': [ + '-lpthread', ], 'sources': [ 'odk_fuzz.cpp', diff --git a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp index 7f6187c..ef90a00 100644 --- a/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_fuzz_helper.cpp @@ -99,11 +99,9 @@ OEMCryptoResult odk_deserialize_RenewalResponse( // odk_kdo method, we call Unpack_ODK_PreparedRenewalRequest private method. // playback_time cannot be captured from publicly exposed API // ODK_ParseRenewal. - uint8_t blk[SIZE_OF_MESSAGE_STRUCT]; - Message* msg = reinterpret_cast(blk); - InitMessage(msg, const_cast(buf), len); - SetSize(msg, len); - Unpack_ODK_PreparedRenewalRequest(msg, renewal_msg); + ODK_Message msg = ODK_Message_Create(const_cast(buf), len); + ODK_Message_SetSize(&msg, len); + Unpack_ODK_PreparedRenewalRequest(&msg, renewal_msg); return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp index 5249253..4ad8ca4 100644 --- a/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_provisioning_response_fuzz_with_mutator.cpp @@ -6,13 +6,15 @@ #include #include "fuzzing/odk_fuzz_helper.h" +#include "odk_attributes.h" namespace oemcrypto_core_message { // The custom mutator: Ensure that each input can be deserialized properly // by ODK function after mutation. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, - size_t max_size, unsigned int seed) { + size_t max_size, + unsigned int seed UNUSED) { const size_t kProvisioningResponseArgsSize = sizeof(ODK_ParseProvisioning_Args); if (size < kProvisioningResponseArgsSize) { diff --git a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp index d6a9dd4..2502ab8 100644 --- a/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp +++ b/oemcrypto/odk/test/fuzzing/odk_renewal_response_fuzz_with_mutator.cpp @@ -6,13 +6,15 @@ #include #include "fuzzing/odk_fuzz_helper.h" +#include "odk_attributes.h" namespace oemcrypto_core_message { // The custom mutator: Ensure that each input can be deserialized properly // by ODK function after mutation. extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, - size_t max_size, unsigned int seed) { + size_t max_size, + unsigned int seed UNUSED) { const size_t kRenewalResponseArgsSize = sizeof(ODK_ParseRenewal_Args); if (size < kRenewalResponseArgsSize) { return 0; diff --git a/oemcrypto/odk/test/odk_test.cpp b/oemcrypto/odk/test/odk_test.cpp index 93e9230..1111343 100644 --- a/oemcrypto/odk/test/odk_test.cpp +++ b/oemcrypto/odk/test/odk_test.cpp @@ -4,8 +4,6 @@ #include "odk.h" -#include // TODO(b/147944591): use this one? Or odk_endian.h? - #include #include @@ -178,15 +176,15 @@ TEST(OdkTest, SerializeFieldsStress) { std::srand(0); size_t total_size = 0; for (int i = 0; i < n; i++) { - fields[i].type = static_cast(std::rand() % - static_cast(ODK_NUMTYPES)); + fields[i].type = static_cast( + std::rand() % static_cast(ODK_LAST_STRESSABLE_TYPE)); fields[i].value = malloc(ODK_AllocSize(fields[i].type)); fields[i].name = "stress"; total_size += ODK_FieldLength(fields[i].type); } uint8_t* buf = new uint8_t[total_size]{}; - for (int i = 0; i < total_size; i++) { + for (size_t i = 0; i < total_size; i++) { buf[i] = std::rand() & 0xff; } @@ -703,7 +701,7 @@ TEST(OdkSizeTest, ReleaseRequest) { &core_message_length, &nonce_values, &clock_values, system_time_seconds)); // Release requests do not have a core message. - EXPECT_GE(core_message_length, 0); + EXPECT_GE(core_message_length, 0u); } TEST(OdkSizeTest, ProvisioningRequest) { diff --git a/oemcrypto/odk/test/odk_test_helper.cpp b/oemcrypto/odk/test/odk_test_helper.cpp index 50f3a1a..5a4be16 100644 --- a/oemcrypto/odk/test/odk_test_helper.cpp +++ b/oemcrypto/odk/test/odk_test_helper.cpp @@ -4,8 +4,6 @@ #include "odk_test_helper.h" -#include - #include #include #include @@ -15,6 +13,7 @@ #include "OEMCryptoCENCCommon.h" #include "gtest/gtest.h" +#include "odk_endian.h" #include "odk_structs.h" #include "odk_structs_priv.h" @@ -87,10 +86,10 @@ void ODK_SetDefaultLicenseResponseParams(ODK_LicenseResponseParams* params) { ".srm_restriction_data"}, {ODK_UINT32, &(params->parsed_license.license_type), ".license_type"}, {ODK_UINT32, &(params->parsed_license.nonce_required), ".nonce_required"}, - {ODK_UINT32, + {ODK_BOOL, &(params->parsed_license.timer_limits.soft_enforce_rental_duration), ".soft_enforce_rental_duration"}, - {ODK_UINT32, + {ODK_BOOL, &(params->parsed_license.timer_limits.soft_enforce_playback_duration), ".soft_enforce_playback_duration"}, {ODK_UINT64, @@ -203,6 +202,8 @@ size_t ODK_FieldLength(ODK_FieldType type) { return sizeof(uint32_t); case ODK_UINT64: return sizeof(uint64_t); + case ODK_BOOL: // Booleans are stored in the message as 32 bit ints. + return sizeof(uint32_t); case ODK_SUBSTRING: return sizeof(uint32_t) + sizeof(uint32_t); case ODK_DEVICEID: @@ -227,24 +228,33 @@ OEMCryptoResult ODK_WriteSingleField(uint8_t* buf, const ODK_Field* field) { } switch (field->type) { case ODK_UINT16: { - const uint16_t u16 = htobe16(*static_cast(field->value)); + const uint16_t u16 = + oemcrypto_htobe16(*static_cast(field->value)); memcpy(buf, &u16, sizeof(u16)); break; } case ODK_UINT32: { - const uint32_t u32 = htobe32(*static_cast(field->value)); + const uint32_t u32 = + oemcrypto_htobe32(*static_cast(field->value)); memcpy(buf, &u32, sizeof(u32)); break; } case ODK_UINT64: { - const uint64_t u64 = htobe64(*static_cast(field->value)); + const uint64_t u64 = + oemcrypto_htobe64(*static_cast(field->value)); memcpy(buf, &u64, sizeof(u64)); break; } + case ODK_BOOL: { + const bool value = *static_cast(field->value); + const uint32_t u32 = oemcrypto_htobe32(value ? 1 : 0); + memcpy(buf, &u32, sizeof(u32)); + break; + } case ODK_SUBSTRING: { OEMCrypto_Substring* s = static_cast(field->value); - const uint32_t off = htobe32(s->offset); - const uint32_t len = htobe32(s->length); + const uint32_t off = oemcrypto_htobe32(s->offset); + const uint32_t len = oemcrypto_htobe32(s->length); memcpy(buf, &off, sizeof(off)); memcpy(buf + sizeof(off), &len, sizeof(len)); break; @@ -272,19 +282,26 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, case ODK_UINT16: { memcpy(field->value, buf, sizeof(uint16_t)); uint16_t* u16p = static_cast(field->value); - *u16p = be16toh(*u16p); + *u16p = oemcrypto_be16toh(*u16p); break; } case ODK_UINT32: { memcpy(field->value, buf, sizeof(uint32_t)); uint32_t* u32p = static_cast(field->value); - *u32p = be32toh(*u32p); + *u32p = oemcrypto_be32toh(*u32p); break; } case ODK_UINT64: { memcpy(field->value, buf, sizeof(uint64_t)); uint64_t* u64p = static_cast(field->value); - *u64p = be64toh(*u64p); + *u64p = oemcrypto_be64toh(*u64p); + break; + } + case ODK_BOOL: { + uint32_t value; + memcpy(&value, buf, sizeof(uint32_t)); + value = oemcrypto_be32toh(value); + *static_cast(field->value) = (value != 0); break; } case ODK_SUBSTRING: { @@ -293,8 +310,8 @@ OEMCryptoResult ODK_ReadSingleField(const uint8_t* buf, uint32_t len = 0; memcpy(&off, buf, sizeof(off)); memcpy(&len, buf + sizeof(off), sizeof(len)); - s->offset = be32toh(off); - s->length = be32toh(len); + s->offset = oemcrypto_be32toh(off); + s->length = oemcrypto_be32toh(len); break; } case ODK_DEVICEID: @@ -319,15 +336,16 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, case ODK_UINT16: { uint16_t val; memcpy(&val, buf, sizeof(uint16_t)); - val = be16toh(val); + val = oemcrypto_be16toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; } + case ODK_BOOL: case ODK_UINT32: { uint32_t val; memcpy(&val, buf, sizeof(uint32_t)); - val = be32toh(val); + val = oemcrypto_be32toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; @@ -335,7 +353,7 @@ OEMCryptoResult ODK_DumpSingleField(const uint8_t* buf, case ODK_UINT64: { uint64_t val; memcpy(&val, buf, sizeof(uint64_t)); - val = be64toh(val); + val = oemcrypto_be64toh(val); std::cerr << field->name << ": " << val << " = 0x" << std::hex << val << "\n"; break; @@ -465,11 +483,6 @@ void ODK_BuildMessageBuffer(ODK_CoreMessage* core_message, {ODK_UINT32, &(core_message->nonce_values.session_id), "session_id"}, }; - uint32_t header_size = 0; - for (auto& field : total_fields) { - header_size += ODK_FieldLength(field.type); - } - total_fields.insert(total_fields.end(), extra_fields.begin(), extra_fields.end()); for (auto& field : total_fields) { diff --git a/oemcrypto/odk/test/odk_test_helper.h b/oemcrypto/odk/test/odk_test_helper.h index c32318e..f29c9b8 100644 --- a/oemcrypto/odk/test/odk_test_helper.h +++ b/oemcrypto/odk/test/odk_test_helper.h @@ -21,7 +21,12 @@ enum ODK_FieldType { ODK_SUBSTRING, ODK_DEVICEID, ODK_HASH, - ODK_NUMTYPES, + // The "stressable" types are the ones we can put in a stress test that packs + // and unpacks random data and can expect to get back the same thing. + ODK_LAST_STRESSABLE_TYPE, + // Put boolean after ODK_LAST_STRESSABLE_TYPE, so that we skip boolean type in + // SerializeFieldsStress because we unpack any nonzero to 'true'. + ODK_BOOL, }; enum ODK_FieldMode { diff --git a/oemcrypto/odk/test/odk_timer_test.cpp b/oemcrypto/odk/test/odk_timer_test.cpp index 9bb0b54..8fdaa44 100644 --- a/oemcrypto/odk/test/odk_timer_test.cpp +++ b/oemcrypto/odk/test/odk_timer_test.cpp @@ -1133,8 +1133,8 @@ TEST_P(ODKUseCase_LicenseWithRenewal, NullPointerTest) { timer_value_pointer); } -INSTANTIATE_TEST_CASE_P(RestrictRenewal, ODKUseCase_LicenseWithRenewal, - ::testing::Values(0, 1)); +INSTANTIATE_TEST_SUITE_P(RestrictRenewal, ODKUseCase_LicenseWithRenewal, + ::testing::Values(0, 1)); // Limited Duration License. (See above for notes on Use Case tests). The user // has 15 minutes to begin watching the movie. If a renewal is not received, diff --git a/oemcrypto/oemcrypto_unittests.gyp b/oemcrypto/oemcrypto_unittests.gyp index 6d66e97..3773358 100644 --- a/oemcrypto/oemcrypto_unittests.gyp +++ b/oemcrypto/oemcrypto_unittests.gyp @@ -8,9 +8,9 @@ 'privacy_crypto_impl%': 'boringssl', 'boringssl_libcrypto_path%': '> $(depfile) +# Add extra rules as in (2). +# We remove slashes and replace spaces with new lines; +# remove blank lines; +# delete the first line and append a colon to the remaining lines. +sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\ + grep -v '^$$' |\ + sed -e 1d -e 's|$$|:|' \ + >> $(depfile) +rm $(depfile).raw +endef + +# Command definitions: +# - cmd_foo is the actual command to run; +# - quiet_cmd_foo is the brief-output summary of the command. + +quiet_cmd_cc = CC($(TOOLSET)) $@ +cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_cxx = CXX($(TOOLSET)) $@ +cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $< + +quiet_cmd_touch = TOUCH $@ +cmd_touch = touch $@ + +quiet_cmd_copy = COPY $@ +# send stderr to /dev/null to ignore messages when linking directories. +cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@") + +quiet_cmd_alink = AR($(TOOLSET)) $@ +cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^) + +quiet_cmd_alink_thin = AR($(TOOLSET)) $@ +cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^) + +# Due to circular dependencies between libraries :(, we wrap the +# special "figure out circular dependencies" flags around the entire +# input list during linking. +quiet_cmd_link = LINK($(TOOLSET)) $@ +cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS) + +# We support two kinds of shared objects (.so): +# 1) shared_library, which is just bundling together many dependent libraries +# into a link line. +# 2) loadable_module, which is generating a module intended for dlopen(). +# +# They differ only slightly: +# In the former case, we want to package all dependent code into the .so. +# In the latter case, we want to package just the API exposed by the +# outermost module. +# This means shared_library uses --whole-archive, while loadable_module doesn't. +# (Note that --whole-archive is incompatible with the --start-group used in +# normal linking.) + +# Other shared-object link notes: +# - Set SONAME to the library filename so our binaries don't reference +# the local, absolute paths used on the link command-line. +quiet_cmd_solink = SOLINK($(TOOLSET)) $@ +cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS) + +quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@ +cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS) + + +# Define an escape_quotes function to escape single quotes. +# This allows us to handle quotes properly as long as we always use +# use single quotes and escape_quotes. +escape_quotes = $(subst ','\'',$(1)) +# This comment is here just to include a ' to unconfuse syntax highlighting. +# Define an escape_vars function to escape '$' variable syntax. +# This allows us to read/write command lines with shell variables (e.g. +# $LD_LIBRARY_PATH), without triggering make substitution. +escape_vars = $(subst $$,$$$$,$(1)) +# Helper that expands to a shell command to echo a string exactly as it is in +# make. This uses printf instead of echo because printf's behaviour with respect +# to escape sequences is more portable than echo's across different shells +# (e.g., dash, bash). +exact_echo = printf '%s\n' '$(call escape_quotes,$(1))' + +# Helper to compare the command we're about to run against the command +# we logged the last time we ran the command. Produces an empty +# string (false) when the commands match. +# Tricky point: Make has no string-equality test function. +# The kernel uses the following, but it seems like it would have false +# positives, where one string reordered its arguments. +# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ +# $(filter-out $(cmd_$@), $(cmd_$(1)))) +# We instead substitute each for the empty string into the other, and +# say they're equal if both substitutions produce the empty string. +# .d files contain ? instead of spaces, take that into account. +command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\ + $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1)))) + +# Helper that is non-empty when a prerequisite changes. +# Normally make does this implicitly, but we force rules to always run +# so we can check their command lines. +# $? -- new prerequisites +# $| -- order-only dependencies +prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?)) + +# Helper that executes all postbuilds until one fails. +define do_postbuilds + @E=0;\ + for p in $(POSTBUILDS); do\ + eval $$p;\ + E=$$?;\ + if [ $$E -ne 0 ]; then\ + break;\ + fi;\ + done;\ + if [ $$E -ne 0 ]; then\ + rm -rf "$@";\ + exit $$E;\ + fi +endef + +# do_cmd: run a command via the above cmd_foo names, if necessary. +# Should always run for a given target to handle command-line changes. +# Second argument, if non-zero, makes it do asm/C/C++ dependency munging. +# Third argument, if non-zero, makes it do POSTBUILDS processing. +# Note: We intentionally do NOT call dirx for depfile, since it contains ? for +# spaces already and dirx strips the ? characters. +define do_cmd +$(if $(or $(command_changed),$(prereq_changed)), + @$(call exact_echo, $($(quiet)cmd_$(1))) + @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))" + $(if $(findstring flock,$(word 1,$(cmd_$1))), + @$(cmd_$(1)) + @echo " $(quiet_cmd_$(1)): Finished", + @$(cmd_$(1)) + ) + @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile) + @$(if $(2),$(fixup_dep)) + $(if $(and $(3), $(POSTBUILDS)), + $(call do_postbuilds) + ) +) +endef + +# Declare the "all" target first so it is the default, +# even though we don't have the deps yet. +.PHONY: all +all: + +# make looks for ways to re-generate included makefiles, but in our case, we +# don't have a direct way. Explicitly telling make that it has nothing to do +# for them makes it go faster. +%.d: ; + +# Use FORCE_DO_CMD to force a target to run. Should be coupled with +# do_cmd. +.PHONY: FORCE_DO_CMD +FORCE_DO_CMD: + +TOOLSET := target +# Suffix rules, putting all outputs into $(obj). +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD + @$(call do_cmd,cxx,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD + @$(call do_cmd,cc,1) +$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD + @$(call do_cmd,cc,1) + + +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/odk/src/odk.target.mk)))),) + include oemcrypto/odk/src/odk.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/opk/build/ta.target.mk)))),) + include oemcrypto/opk/build/ta.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.target.mk)))),) + include oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_clock.target.mk)))),) + include oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_clock.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_crypto.target.mk)))),) + include oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_crypto.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_root_of_trust.target.mk)))),) + include oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_root_of_trust.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,oemcrypto/opk/serialization/tee/opk_tee.target.mk)))),) + include oemcrypto/opk/serialization/tee/opk_tee.target.mk +endif +ifeq ($(strip $(foreach prefix,$(NO_LOAD),\ + $(findstring $(join ^,$(prefix)),\ + $(join ^,third_party/boringssl/crypto.target.mk)))),) + include third_party/boringssl/crypto.target.mk +endif + +# "all" is a concatenation of the "all" targets from all the included +# sub-makefiles. This is just here to clarify. +all: + +# Add in dependency-tracking rules. $(all_deps) is the list of every single +# target in our tree. Only consider the ones with .d (dependency) info: +d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d)) +ifneq ($(d_files),) + include $(d_files) +endif diff --git a/oemcrypto/opk/build/oemcrypto/odk/src/odk.target.mk b/oemcrypto/opk/build/oemcrypto/odk/src/odk.target.mk new file mode 100644 index 0000000..ad3e81d --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/odk/src/odk.target.mk @@ -0,0 +1,139 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := odk +DEFS_debug := \ + '-D_DEFAULT_SOURCE' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error=cast-qual \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L \ + -Wno-error=bad-function-cast + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/include + +DEFS_release := \ + '-D_DEFAULT_SOURCE' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error=cast-qual \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L \ + -Wno-error=bad-function-cast + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_message.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_overflow.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_serialize.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_timer.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_util.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/serialization_base.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/odk/src/libodk.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/odk/src/libodk.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/odk/src/libodk.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/odk/src/libodk.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/odk/src/libodk.a +# Add target alias +.PHONY: odk +odk: $(obj).target/oemcrypto/odk/src/libodk.a + +# Add target alias to "all" target. +.PHONY: all +all: odk + +# Add target alias +.PHONY: odk +odk: $(builddir)/libodk.a + +# Copy this to the static library output path. +$(builddir)/libodk.a: TOOLSET := $(TOOLSET) +$(builddir)/libodk.a: $(obj).target/oemcrypto/odk/src/libodk.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libodk.a +# Short alias for building this static library. +.PHONY: libodk.a +libodk.a: $(obj).target/oemcrypto/odk/src/libodk.a $(builddir)/libodk.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libodk.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/build/liboemcrypto.target.mk b/oemcrypto/opk/build/oemcrypto/opk/build/liboemcrypto.target.mk new file mode 100644 index 0000000..90fee0a --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/build/liboemcrypto.target.mk @@ -0,0 +1,43 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := liboemcrypto +### Rules for final target. +LDFLAGS_debug := \ + $(LIBOEMCRYPTO_LDFLAGS) + +LDFLAGS_release := \ + $(LIBOEMCRYPTO_LDFLAGS) \ + -O2 \ + -Wl,--strip-debug + +LIBS := \ + $(TRUSTED_OS_SDK_LIBS) \ + $(builddir)/libree_tos.a + +$(obj).target/oemcrypto/opk/build/liboemcrypto.so: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/build/liboemcrypto.so: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/build/liboemcrypto.so: LD_INPUTS := $(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a +$(obj).target/oemcrypto/opk/build/liboemcrypto.so: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/build/liboemcrypto.so: $(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a FORCE_DO_CMD + $(call do_cmd,solink) + +all_deps += $(obj).target/oemcrypto/opk/build/liboemcrypto.so +# Add target alias +.PHONY: liboemcrypto +liboemcrypto: $(builddir)/lib.target/liboemcrypto.so + +# Copy this to the shared library output path. +$(builddir)/lib.target/liboemcrypto.so: TOOLSET := $(TOOLSET) +$(builddir)/lib.target/liboemcrypto.so: $(obj).target/oemcrypto/opk/build/liboemcrypto.so FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/lib.target/liboemcrypto.so +# Short alias for building this shared library. +.PHONY: liboemcrypto.so +liboemcrypto.so: $(obj).target/oemcrypto/opk/build/liboemcrypto.so $(builddir)/lib.target/liboemcrypto.so + +# Add shared library to "all" target. +.PHONY: all +all: $(builddir)/lib.target/liboemcrypto.so + diff --git a/oemcrypto/opk/build/oemcrypto/opk/build/ta.target.mk b/oemcrypto/opk/build/oemcrypto/opk/build/ta.target.mk new file mode 100644 index 0000000..8727e91 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/build/ta.target.mk @@ -0,0 +1,46 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := ta +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/build/libta.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/build/libta.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/build/libta.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/build/libta.a: FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/build/libta.a +# Add target alias +.PHONY: ta +ta: $(obj).target/oemcrypto/opk/build/libta.a + +# Add target alias to "all" target. +.PHONY: all +all: ta + +# Add target alias +.PHONY: ta +ta: $(builddir)/libta.a + +# Copy this to the static library output path. +$(builddir)/libta.a: TOOLSET := $(TOOLSET) +$(builddir)/libta.a: $(obj).target/oemcrypto/opk/build/libta.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libta.a +# Short alias for building this static library. +.PHONY: libta.a +libta.a: $(obj).target/oemcrypto/opk/build/libta.a $(builddir)/libta.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libta.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.target.mk new file mode 100644 index 0000000..ad00f79 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.target.mk @@ -0,0 +1,156 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := oemcrypto_ta +DEFS_debug := \ + '-D_DEFAULT_SOURCE' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -D_POSIX_C_SOURCE=200809L \ + -std=c99 + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include + +DEFS_release := \ + '-D_DEFAULT_SOURCE' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -D_POSIX_C_SOURCE=200809L \ + -std=c99 + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_asymmetric_key_table.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_key.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_key_control_block.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_key_table.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_object_table.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_output.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_overflow.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_serialized_usage_table.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_session.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_key_table.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_session_table.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_usage_table.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/oemcrypto_wall_clock.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a +# Add target alias +.PHONY: oemcrypto_ta +oemcrypto_ta: $(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a + +# Add target alias to "all" target. +.PHONY: all +all: oemcrypto_ta + +# Add target alias +.PHONY: oemcrypto_ta +oemcrypto_ta: $(builddir)/liboemcrypto_ta.a + +# Copy this to the static library output path. +$(builddir)/liboemcrypto_ta.a: TOOLSET := $(TOOLSET) +$(builddir)/liboemcrypto_ta.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/liboemcrypto_ta.a +# Short alias for building this static library. +.PHONY: liboemcrypto_ta.a +liboemcrypto_ta.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/liboemcrypto_ta.a $(builddir)/liboemcrypto_ta.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/liboemcrypto_ta.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_clock.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_clock.target.mk new file mode 100644 index 0000000..c356619 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_clock.target.mk @@ -0,0 +1,143 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := oemcrypto_ta_reference_clock +DEFS_debug := \ + '-D_DEFAULT_SOURCE' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -D_POSIX_C_SOURCE=200809L \ + -std=c99 + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include + +DEFS_release := \ + '-D_DEFAULT_SOURCE' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -D_POSIX_C_SOURCE=200809L \ + -std=c99 + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a +# Add target alias +.PHONY: oemcrypto_ta_reference_clock +oemcrypto_ta_reference_clock: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a + +# Add target alias to "all" target. +.PHONY: all +all: oemcrypto_ta_reference_clock + +# Add target alias +.PHONY: oemcrypto_ta_reference_clock +oemcrypto_ta_reference_clock: $(builddir)/liboemcrypto_ta_reference_clock.a + +# Copy this to the static library output path. +$(builddir)/liboemcrypto_ta_reference_clock.a: TOOLSET := $(TOOLSET) +$(builddir)/liboemcrypto_ta_reference_clock.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/liboemcrypto_ta_reference_clock.a +# Short alias for building this static library. +.PHONY: liboemcrypto_ta_reference_clock.a +liboemcrypto_ta_reference_clock.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_clock.a $(builddir)/liboemcrypto_ta_reference_clock.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/liboemcrypto_ta_reference_clock.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_crypto.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_crypto.target.mk new file mode 100644 index 0000000..2c30aa0 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_crypto.target.mk @@ -0,0 +1,155 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := oemcrypto_ta_reference_crypto +DEFS_debug := \ + '-D_DEFAULT_SOURCE' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L \ + -std=c11 + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_reference \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +DEFS_release := \ + '-D_DEFAULT_SOURCE' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L \ + -std=c11 + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_reference \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_util.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/ecc_util.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/rsa_util.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crc32.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_decrypt_sample.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a +# Add target alias +.PHONY: oemcrypto_ta_reference_crypto +oemcrypto_ta_reference_crypto: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a + +# Add target alias to "all" target. +.PHONY: all +all: oemcrypto_ta_reference_crypto + +# Add target alias +.PHONY: oemcrypto_ta_reference_crypto +oemcrypto_ta_reference_crypto: $(builddir)/liboemcrypto_ta_reference_crypto.a + +# Copy this to the static library output path. +$(builddir)/liboemcrypto_ta_reference_crypto.a: TOOLSET := $(TOOLSET) +$(builddir)/liboemcrypto_ta_reference_crypto.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/liboemcrypto_ta_reference_crypto.a +# Short alias for building this static library. +.PHONY: liboemcrypto_ta_reference_crypto.a +liboemcrypto_ta_reference_crypto.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_crypto.a $(builddir)/liboemcrypto_ta_reference_crypto.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/liboemcrypto_ta_reference_crypto.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_root_of_trust.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_root_of_trust.target.mk new file mode 100644 index 0000000..ddc4551 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_reference/oemcrypto_ta_reference_root_of_trust.target.mk @@ -0,0 +1,145 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := oemcrypto_ta_reference_root_of_trust +DEFS_debug := \ + '-D_DEFAULT_SOURCE' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -D_POSIX_C_SOURCE=200809L \ + -std=c99 + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include + +DEFS_release := \ + '-D_DEFAULT_SOURCE' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -pedantic \ + -pedantic-errors \ + -Werror=pedantic \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -D_POSIX_C_SOURCE=200809L \ + -std=c99 + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(WTPI_CONFIG_MACRO_DIR) \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_wrap_asymmetric.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a +# Add target alias +.PHONY: oemcrypto_ta_reference_root_of_trust +oemcrypto_ta_reference_root_of_trust: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a + +# Add target alias to "all" target. +.PHONY: all +all: oemcrypto_ta_reference_root_of_trust + +# Add target alias +.PHONY: oemcrypto_ta_reference_root_of_trust +oemcrypto_ta_reference_root_of_trust: $(builddir)/liboemcrypto_ta_reference_root_of_trust.a + +# Copy this to the static library output path. +$(builddir)/liboemcrypto_ta_reference_root_of_trust.a: TOOLSET := $(TOOLSET) +$(builddir)/liboemcrypto_ta_reference_root_of_trust.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/liboemcrypto_ta_reference_root_of_trust.a +# Short alias for building this static library. +.PHONY: liboemcrypto_ta_reference_root_of_trust.a +liboemcrypto_ta_reference_root_of_trust.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_reference/liboemcrypto_ta_reference_root_of_trust.a $(builddir)/liboemcrypto_ta_reference_root_of_trust.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/liboemcrypto_ta_reference_root_of_trust.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/opk_ree_api.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/opk_ree_api.target.mk new file mode 100644 index 0000000..7ef96e2 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/opk_ree_api.target.mk @@ -0,0 +1,151 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := opk_ree_api +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/ree_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_message.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_overflow.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/bump_allocator.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/log_macros.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/length_types.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/marshaller_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_init.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_serialization_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/shared_buffer_allocator.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/api_support.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink_thin) + +all_deps += $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a +# Add target alias +.PHONY: opk_ree_api +opk_ree_api: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a + +# Add target alias to "all" target. +.PHONY: all +all: opk_ree_api + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/opk_tee_wtpi_test.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/opk_tee_wtpi_test.target.mk new file mode 100644 index 0000000..b3142fc --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/opk_tee_wtpi_test.target.mk @@ -0,0 +1,154 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := opk_tee_wtpi_test +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator \ + -I$(srcdir)/oemcrypto/opk/serialization/tee/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/generator + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator \ + -I$(srcdir)/oemcrypto/opk/serialization/tee/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/generator + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/GEN_common_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_message.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_overflow.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/bump_allocator.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/length_types.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/log_macros.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/marshaller_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_init.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_serialization_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/shared_buffer_allocator.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/libopk_tee_wtpi_test.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/libopk_tee_wtpi_test.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/libopk_tee_wtpi_test.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/libopk_tee_wtpi_test.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink_thin) + +all_deps += $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/libopk_tee_wtpi_test.a +# Add target alias +.PHONY: opk_tee_wtpi_test +opk_tee_wtpi_test: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/libopk_tee_wtpi_test.a + +# Add target alias to "all" target. +.PHONY: all +all: opk_tee_wtpi_test + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.target.mk new file mode 100644 index 0000000..1524f88 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.target.mk @@ -0,0 +1,158 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := wtpi_test +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/third_party/googletest/googletest/include \ + -I$(srcdir)/util/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator \ + -I$(srcdir)/third_party/googletest/googlemock/include + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/third_party/googletest/googletest/include \ + -I$(srcdir)/util/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator \ + -I$(srcdir)/third_party/googletest/googlemock/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_main.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# Make sure our dependencies are built before any of us. +$(OBJS): | $(obj).target/third_party/libgtest.a $(builddir)/libwtpi_test_lib.a $(builddir)/libcrypto.a $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a $(obj).target/third_party/boringssl/libcrypto.a + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := \ + -Wl,--whole-archive \ + libwtpi_test_lib.a \ + -Wl,--no-whole-archive + +LDFLAGS_release := \ + -Wl,--whole-archive \ + libwtpi_test_lib.a \ + -Wl,--no-whole-archive \ + -O2 \ + -Wl,--strip-debug + +LIBS := \ + -lrt \ + -lpthread \ + -ldl + +$(builddir)/wtpi_test: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/wtpi_test: LIBS := $(LIBS) +$(builddir)/wtpi_test: LD_INPUTS := $(OBJS) $(obj).target/third_party/libgtest.a $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a $(obj).target/third_party/boringssl/libcrypto.a +$(builddir)/wtpi_test: TOOLSET := $(TOOLSET) +$(builddir)/wtpi_test: $(OBJS) $(obj).target/third_party/libgtest.a $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a $(obj).target/third_party/boringssl/libcrypto.a FORCE_DO_CMD + $(call do_cmd,link) + +all_deps += $(builddir)/wtpi_test +# Add target alias +.PHONY: wtpi_test +wtpi_test: $(builddir)/wtpi_test + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/wtpi_test + diff --git a/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_lib.target.mk b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_lib.target.mk new file mode 100644 index 0000000..f48f93a --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_lib.target.mk @@ -0,0 +1,168 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := wtpi_test_lib +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/third_party/googletest/googletest/include \ + -I$(srcdir)/util/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DMIN_LOG_LEVEL=LOG_LEVEL_DEBUG' \ + '-DENABLE_ANSI_COLORS=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/third_party/googletest/googletest/include \ + -I$(srcdir)/util/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi_test/common \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/oemcrypto/opk/serialization/generator \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/clock_interface_test.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/generation_number_interface_test.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/test_rsa_key.o \ + $(obj).target/$(TARGET)/linux/src/log.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a +# Add target alias +.PHONY: wtpi_test_lib +wtpi_test_lib: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a + +# Add target alias to "all" target. +.PHONY: all +all: wtpi_test_lib + +# Add target alias +.PHONY: wtpi_test_lib +wtpi_test_lib: $(builddir)/libwtpi_test_lib.a + +# Copy this to the static library output path. +$(builddir)/libwtpi_test_lib.a: TOOLSET := $(TOOLSET) +$(builddir)/libwtpi_test_lib.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libwtpi_test_lib.a +# Short alias for building this static library. +.PHONY: libwtpi_test_lib.a +libwtpi_test_lib.a: $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a $(builddir)/libwtpi_test_lib.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libwtpi_test_lib.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/ports/optee/build/README.md b/oemcrypto/opk/build/oemcrypto/opk/ports/optee/build/README.md new file mode 100644 index 0000000..e9bcfb2 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/ports/optee/build/README.md @@ -0,0 +1,15 @@ +Port-specific makefiles for OP-TEE will be placed here after running +jenkins/opk_makefiles with optee-specific gen_makefiles scripts executed. The +generated port-specific makefiles include: + * oemcrypto_helloworld.target.mk + * ree_tos.target.mk + * ree_tos_wtpi_target.mk + * wtpi_impl.target.mk + +as well as the unit test makefiles under `oemcrypto/opk/build/oemcrypto/opk/build/`: + * oemcrypto_unittests.target.mk + * wtpi_unittests.target.mk + +Examples of how these are referenced can be found in the include rules in the +top level file `Makefile.opk`. Examples of how these are defined for the OP-TEE +port can be found in file `Makefile.optee`. \ No newline at end of file diff --git a/oemcrypto/opk/build/oemcrypto/opk/serialization/ree/opk_ree.target.mk b/oemcrypto/opk/build/oemcrypto/opk/serialization/ree/opk_ree.target.mk new file mode 100644 index 0000000..f15829a --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/serialization/ree/opk_ree.target.mk @@ -0,0 +1,167 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := opk_ree +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/api_support.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/GEN_ree_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/GEN_oemcrypto_api.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/ree_os_type.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/ree_version.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/ree_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/ree/special_case_apis.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/bump_allocator.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/common_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/GEN_common_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/log_macros.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/length_types.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/marshaller_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/message_debug.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_init.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_serialization_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/shared_buffer_allocator.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_message.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_overflow.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a +# Add target alias +.PHONY: opk_ree +opk_ree: $(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a + +# Add target alias to "all" target. +.PHONY: all +all: opk_ree + +# Add target alias +.PHONY: opk_ree +opk_ree: $(builddir)/libopk_ree.a + +# Copy this to the static library output path. +$(builddir)/libopk_ree.a: TOOLSET := $(TOOLSET) +$(builddir)/libopk_ree.a: $(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libopk_ree.a +# Short alias for building this static library. +.PHONY: libopk_ree.a +libopk_ree.a: $(obj).target/oemcrypto/opk/serialization/ree/libopk_ree.a $(builddir)/libopk_ree.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libopk_ree.a + diff --git a/oemcrypto/opk/build/oemcrypto/opk/serialization/tee/opk_tee.target.mk b/oemcrypto/opk/build/oemcrypto/opk/serialization/tee/opk_tee.target.mk new file mode 100644 index 0000000..fee9202 --- /dev/null +++ b/oemcrypto/opk/build/oemcrypto/opk/serialization/tee/opk_tee.target.mk @@ -0,0 +1,168 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := opk_tee +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/tee/include + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/serialization/tee/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/tee/GEN_dispatcher.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/tee/GEN_tee_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/tee/tee_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/tee/tee_os_type.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/tee/tee_version.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/tee/tee_tos_stubs.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/bump_allocator.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/common_special_cases.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/GEN_common_serializer.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/length_types.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/log_macros.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/marshaller_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/message_debug.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_init.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/opk_serialization_base.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/serialization/common/shared_buffer_allocator.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_message.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/odk_overflow.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a +# Add target alias +.PHONY: opk_tee +opk_tee: $(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a + +# Add target alias to "all" target. +.PHONY: all +all: opk_tee + +# Add target alias +.PHONY: opk_tee +opk_tee: $(builddir)/libopk_tee.a + +# Copy this to the static library output path. +$(builddir)/libopk_tee.a: TOOLSET := $(TOOLSET) +$(builddir)/libopk_tee.a: $(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libopk_tee.a +# Short alias for building this static library. +.PHONY: libopk_tee.a +libopk_tee.a: $(obj).target/oemcrypto/opk/serialization/tee/libopk_tee.a $(builddir)/libopk_tee.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libopk_tee.a + diff --git a/oemcrypto/opk/build/ta.gyp b/oemcrypto/opk/build/ta.gyp index 4eada98..e7e9ff5 100644 --- a/oemcrypto/opk/build/ta.gyp +++ b/oemcrypto/opk/build/ta.gyp @@ -6,10 +6,6 @@ 'includes' : [ '../serialization/settings.gypi', ], - 'variables': { - # Path to a gyp file with a wtpi_impl target for the TA - 'wtpi_impl_dir': '<(oemcrypto_dir)/opk/ports/optee/build', - }, 'targets' : [ { 'target_name' : 'ta', @@ -19,11 +15,10 @@ 'dependencies' : [ '<(odk_dir)/src/odk.gyp:odk', '<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta', - '<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_reference_root_of_trust', - '<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_reference_clock', - '<(oemcrypto_ta_dir)/oemcrypto_ta.gyp:oemcrypto_ta_reference_crypto', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_root_of_trust', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_clock', + '<(oemcrypto_ta_dir)/wtpi_reference/wtpi_reference.gyp:oemcrypto_ta_reference_crypto', '<(tee_dir)/tee.gyp:opk_tee', - '<(wtpi_impl_dir)/ta.gyp:wtpi_impl', ], }, ], diff --git a/oemcrypto/opk/build/third_party/boringssl/crypto.target.mk b/oemcrypto/opk/build/third_party/boringssl/crypto.target.mk new file mode 100644 index 0000000..8da64f4 --- /dev/null +++ b/oemcrypto/opk/build/third_party/boringssl/crypto.target.mk @@ -0,0 +1,362 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := crypto +DEFS_debug := \ + '-DOPENSSL_NO_ASM' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fvisibility=hidden \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +DEFS_release := \ + '-DOPENSSL_NO_ASM' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fvisibility=hidden \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +OBJS := \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/err_data.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_bitstr.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_bool.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_d2i_fp.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_dup.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_enum.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_gentm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_i2d_fp.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_int.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_mbstr.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_object.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_octet.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_print.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_strex.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_strnid.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_time.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_type.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_utctm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/a_utf8.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/asn1_lib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/asn1_par.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/asn_pack.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/f_int.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/f_string.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/tasn_dec.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/tasn_enc.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/tasn_fre.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/tasn_new.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/tasn_typ.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/tasn_utl.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/asn1/time_support.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/base64/base64.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/bio.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/bio_mem.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/connect.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/fd.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/file.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/hexdump.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/pair.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/printf.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/socket.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bio/socket_helper.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/blake2/blake2.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bn_extra/bn_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bn_extra/convert.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/buf/buf.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bytestring/asn1_compat.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bytestring/ber.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bytestring/cbb.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bytestring/cbs.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/bytestring/unicode.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/chacha/chacha.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/cipher_extra.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/derive_key.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_aesccm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_aesctrhmac.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_aesgcmsiv.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_chacha20poly1305.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_null.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_rc2.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_rc4.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/e_tls.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cipher_extra/tls_cbc.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cmac/cmac.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/conf/conf.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cpu-aarch64-fuchsia.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cpu-aarch64-linux.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cpu-aarch64-win.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cpu-arm-linux.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cpu-arm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cpu-intel.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/cpu-ppc64le.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/crypto.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/curve25519/curve25519.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/curve25519/spake25519.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/dh_extra/dh_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/dh_extra/params.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/digest_extra/digest_extra.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/dsa/dsa.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/dsa/dsa_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/ec_extra/ec_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/ec_extra/ec_derive.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/ec_extra/hash_to_curve.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/ecdh_extra/ecdh_extra.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/ecdsa_extra/ecdsa_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/engine/engine.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/err/err.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/digestsign.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/evp.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/evp_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/evp_ctx.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_dsa_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_ec.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_ec_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_ed25519.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_ed25519_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_rsa.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_rsa_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_x25519.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/p_x25519_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/pbkdf.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/print.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/scrypt.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/evp/sign.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/ex_data.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/fipsmodule/bcm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/fipsmodule/fips_shared_support.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/hkdf/hkdf.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/hpke/hpke.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/hrss/hrss.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/lhash/lhash.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/mem.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/obj/obj.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/obj/obj_xref.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_all.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_info.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_lib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_oth.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_pk8.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_pkey.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_x509.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pem/pem_xaux.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pkcs7/pkcs7.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pkcs7/pkcs7_x509.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pkcs8/p5_pbev2.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pkcs8/pkcs8.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pkcs8/pkcs8_x509.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/poly1305/poly1305.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/poly1305/poly1305_arm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/poly1305/poly1305_vec.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/pool/pool.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rand_extra/deterministic.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rand_extra/forkunsafe.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rand_extra/fuchsia.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rand_extra/passive.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rand_extra/rand_extra.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rand_extra/windows.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rc4/rc4.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/refcount_c11.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/refcount_lock.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rsa_extra/rsa_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/rsa_extra/rsa_print.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/siphash/siphash.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/stack/stack.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/thread.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/thread_none.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/thread_pthread.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/thread_win.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/trust_token/pmbtoken.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/trust_token/trust_token.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/trust_token/voprf.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/a_digest.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/a_sign.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/a_verify.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/algorithm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/asn1_gen.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/by_dir.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/by_file.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/i2d_pr.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/name_print.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/rsa_pss.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/t_crl.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/t_req.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/t_x509.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/t_x509a.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_att.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_cmp.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_d2.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_def.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_ext.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_lu.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_obj.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_req.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_set.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_trs.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_txt.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_v3.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_vfy.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509_vpm.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509cset.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509name.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509rset.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x509spki.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_algor.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_all.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_attrib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_crl.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_exten.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_info.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_name.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_pkey.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_pubkey.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_req.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_sig.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_spki.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_val.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_x509.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509/x_x509a.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/pcy_cache.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/pcy_data.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/pcy_lib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/pcy_map.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/pcy_node.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/pcy_tree.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_akey.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_akeya.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_alt.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_bcons.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_bitst.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_conf.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_cpols.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_crld.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_enum.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_extku.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_genn.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_ia5.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_info.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_int.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_lib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_ncons.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_ocsp.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_pci.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_pcia.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_pcons.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_pmaps.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_prn.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_purp.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_skey.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/crypto/x509v3/v3_utl.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/third_party/boringssl/libcrypto.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/third_party/boringssl/libcrypto.a: LIBS := $(LIBS) +$(obj).target/third_party/boringssl/libcrypto.a: TOOLSET := $(TOOLSET) +$(obj).target/third_party/boringssl/libcrypto.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/third_party/boringssl/libcrypto.a +# Add target alias +.PHONY: crypto +crypto: $(obj).target/third_party/boringssl/libcrypto.a + +# Add target alias to "all" target. +.PHONY: all +all: crypto + +# Add target alias +.PHONY: crypto +crypto: $(builddir)/libcrypto.a + +# Copy this to the static library output path. +$(builddir)/libcrypto.a: TOOLSET := $(TOOLSET) +$(builddir)/libcrypto.a: $(obj).target/third_party/boringssl/libcrypto.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libcrypto.a +# Short alias for building this static library. +.PHONY: libcrypto.a +libcrypto.a: $(obj).target/third_party/boringssl/libcrypto.a $(builddir)/libcrypto.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libcrypto.a + diff --git a/oemcrypto/opk/build/third_party/boringssl/ssl.target.mk b/oemcrypto/opk/build/third_party/boringssl/ssl.target.mk new file mode 100644 index 0000000..2ae05ec --- /dev/null +++ b/oemcrypto/opk/build/third_party/boringssl/ssl.target.mk @@ -0,0 +1,167 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := ssl +DEFS_debug := \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fvisibility=hidden \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +DEFS_release := \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fvisibility=hidden \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +OBJS := \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/bio_ssl.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/d1_both.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/d1_lib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/d1_pkt.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/d1_srtp.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/dtls_method.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/dtls_record.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/encrypted_client_hello.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/extensions.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/handoff.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/handshake.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/handshake_client.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/handshake_server.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/s3_both.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/s3_lib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/s3_pkt.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_aead_ctx.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_asn1.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_buffer.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_cert.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_cipher.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_file.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_key_share.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_lib.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_privkey.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_session.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_stat.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_transcript.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_versions.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/ssl_x509.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/t1_enc.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/tls13_both.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/tls13_client.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/tls13_enc.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/tls13_server.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/tls_method.o \ + $(obj).target/$(TARGET)/third_party/boringssl/kit/src/ssl/tls_record.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/third_party/boringssl/libssl.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/third_party/boringssl/libssl.a: LIBS := $(LIBS) +$(obj).target/third_party/boringssl/libssl.a: TOOLSET := $(TOOLSET) +$(obj).target/third_party/boringssl/libssl.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/third_party/boringssl/libssl.a +# Add target alias +.PHONY: ssl +ssl: $(obj).target/third_party/boringssl/libssl.a + +# Add target alias to "all" target. +.PHONY: all +all: ssl + +# Add target alias +.PHONY: ssl +ssl: $(builddir)/libssl.a + +# Copy this to the static library output path. +$(builddir)/libssl.a: TOOLSET := $(TOOLSET) +$(builddir)/libssl.a: $(obj).target/third_party/boringssl/libssl.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libssl.a +# Short alias for building this static library. +.PHONY: libssl.a +libssl.a: $(obj).target/third_party/boringssl/libssl.a $(builddir)/libssl.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libssl.a + diff --git a/oemcrypto/opk/build/third_party/gmock.target.mk b/oemcrypto/opk/build/third_party/gmock.target.mk new file mode 100644 index 0000000..25eeedc --- /dev/null +++ b/oemcrypto/opk/build/third_party/gmock.target.mk @@ -0,0 +1,117 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := gmock +DEFS_debug := \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/third_party/googletest/googlemock \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest \ + -I$(srcdir)/third_party/googletest/googletest/include + +DEFS_release := \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/third_party/googletest/googlemock \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest \ + -I$(srcdir)/third_party/googletest/googletest/include + +OBJS := \ + $(obj).target/$(TARGET)/third_party/googletest/googlemock/src/gmock-all.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/third_party/libgmock.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/third_party/libgmock.a: LIBS := $(LIBS) +$(obj).target/third_party/libgmock.a: TOOLSET := $(TOOLSET) +$(obj).target/third_party/libgmock.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink_thin) + +all_deps += $(obj).target/third_party/libgmock.a +# Add target alias +.PHONY: gmock +gmock: $(obj).target/third_party/libgmock.a + +# Add target alias to "all" target. +.PHONY: all +all: gmock + diff --git a/oemcrypto/opk/build/third_party/gtest.target.mk b/oemcrypto/opk/build/third_party/gtest.target.mk new file mode 100644 index 0000000..61cc019 --- /dev/null +++ b/oemcrypto/opk/build/third_party/gtest.target.mk @@ -0,0 +1,117 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := gtest +DEFS_debug := \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/third_party/googletest/googlemock \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest \ + -I$(srcdir)/third_party/googletest/googletest/include + +DEFS_release := \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -Wno-error \ + -w \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/third_party/googletest/googlemock \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest \ + -I$(srcdir)/third_party/googletest/googletest/include + +OBJS := \ + $(obj).target/$(TARGET)/third_party/googletest/googletest/src/gtest-all.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/third_party/libgtest.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/third_party/libgtest.a: LIBS := $(LIBS) +$(obj).target/third_party/libgtest.a: TOOLSET := $(TOOLSET) +$(obj).target/third_party/libgtest.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink_thin) + +all_deps += $(obj).target/third_party/libgtest.a +# Add target alias +.PHONY: gtest +gtest: $(obj).target/third_party/libgtest.a + +# Add target alias to "all" target. +.PHONY: all +all: gtest + diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c index c026213..444622a 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto.c +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto.c @@ -700,7 +700,7 @@ OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, /* last_nonce_time should only be initialized once. */ static uint64_t last_nonce_time = 0; static int nonce_count = 0; - const int nonce_flood_count = 20; + const int nonce_flood_count = 200; if (last_nonce_time == now) { nonce_count++; if (nonce_count > nonce_flood_count) { diff --git a/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp b/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp index 8b3e078..e91c3fc 100644 --- a/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp +++ b/oemcrypto/opk/oemcrypto_ta/oemcrypto_ta.gyp @@ -6,32 +6,10 @@ 'variables': { # Include directory that contains wtpi_config_macros.h. 'config_macros_header_dir%': 'wtpi_reference', - 'wtpi_test_impl_dir': '../ports/linux/wtpi_test_impl', - # TODO(b/207176111): add test scripts to cover both reference crypto impl - 'reference_crypto_impl%': 'software', - }, - 'target_defaults': { - # OPK is written in pure C99. ...Aside from a few places where we use - # the preprocessor to include compiler-specific features only on supporting - # compilers. ...And aside from the reference crypto porting layer, which has - # to be C11. But the core OPK code will compile on the most pure, - # pedantic C99 compiler, and to check this, we turn on flags to keep - # ourselves honest by using the maximum compiler pedantry. - 'cflags': [ - '-pedantic', - '-pedantic-errors', - '-Werror=pedantic', - ], - 'cflags_c': [ - '-std=c99', - ], - # To make sure no other GYP file can override our C version, we filter out - # all other langauge standards here. - 'cflags_c/': [ - ['exclude', '-std=*'], - ['include', '-std=c99'], - ], }, + 'includes': [ + '../strict_compiler_flags.gypi', + ], 'targets': [ { 'target_name': 'oemcrypto_ta', @@ -71,90 +49,5 @@ ], }, }, - { - 'target_name': 'oemcrypto_ta_reference_root_of_trust', - 'type': 'static_library', - 'standalone_static_library' : 1, - 'sources': [ - 'wtpi_reference/crypto_wrap_asymmetric.c', - 'wtpi_reference/device_key.c', - 'wtpi_reference/root_of_trust_layer1.c', - ], - 'dependencies': [ - '../../odk/src/odk.gyp:odk', - 'oemcrypto_ta', - ], - }, - { - 'target_name': 'oemcrypto_ta_reference_clock', - 'type': 'static_library', - 'standalone_static_library' : 1, - 'sources': [ - 'wtpi_reference/clock_and_gn_layer1.c', - ], - 'dependencies': [ - '../../odk/src/odk.gyp:odk', - 'oemcrypto_ta', - ], - }, - { - 'target_name': 'oemcrypto_ta_reference_crypto', - 'type': 'static_library', - 'standalone_static_library' : 1, - 'include_dirs': [ - '<(config_macros_header_dir)', - 'wtpi_reference', - ], - # The reference implementation of the crypto interface uses - # BoringSSL/OpenSSL, which requires C11. These flags effectively do the - # opposite of the default flags, filtering out the C99 flag and - # un-filtering-out the C11 flag. - 'cflags_c': [ - '-std=c11', - ], - 'cflags_c/': [ - ['exclude', '-std=*'], - ['include', '-std=c11'], - ], - 'sources': [ - 'wtpi_reference/crc32.c', - 'wtpi_reference/crypto_asymmetric.c', - 'wtpi_reference/crypto_util.c', - 'wtpi_reference/decrypt_sample.c', - 'wtpi_reference/ecc_util.c', - 'wtpi_reference/rsa_util.c', - '<(wtpi_test_impl_dir)/device_key_access.c', - '<(wtpi_test_impl_dir)/secure_buffer_access.c', - ], - 'conditions': [ - ['reference_crypto_impl=="hardware"', { - 'sources': [ - 'wtpi_reference/crypto_and_key_management_layer1_hw.c', - '<(wtpi_test_impl_dir)/crypto_and_key_management_layer2_hw.c', - '<(wtpi_test_impl_dir)/layer2_crypto_key_table.c', - ], - }, { # else - 'sources': [ - 'wtpi_reference/crypto_and_key_management_layer1_openssl.c', - ], - }], # end else - ], - 'variables': { - # Needed for BoringSSL dependency build files. These SHOULD already be - # defined by a higher-level configuration, but sometimes the OPK TA - # gets included in targets that don't define them, so we define them - # again here defensively. - - 'privacy_crypto_impl%': 'boringssl', - 'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto', - }, - 'includes': [ - '../../../util/libcrypto_dependency.gypi', - ], - 'dependencies': [ - '../../odk/src/odk.gyp:odk', - 'oemcrypto_ta', - ], - }, ], } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer1.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer1.h index 00d6aac..6e7aa88 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer1.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer1.h @@ -16,13 +16,14 @@ extern "C" { /** @defgroup secure-clock Monotonic Secure Clock * Partners implementing a porting layer may either - * 1. Implement persistent_storage_layer2.h and clock_interface_layer2.h, - * and then use the reference implementation clock_and_gn_layer1.c for the - * clock and generation interfaces. This is preferred if the hardware secure - * timer resets to 0 whenever the device is inactive. + * 1. Implement wtpi_persistent_storage_layer2.h and + * wtpi_clock_interface_layer2.h, and then use the reference implementation + * wtpi_clock_and_gn_layer1.c for the clock and generation interfaces. This + * is preferred if the hardware secure timer resets to 0 whenever the device + * is inactive. * or - * 2. Implement both this clock_interface_layer1.h and - * generation_number_interface.h. This is preferred if the system has a + * 2. Implement both this wtpi_clock_interface_layer1.h and + * wtpi_generation_number_interface.h. This is preferred if the system has a * hardware secure wall clock. * * @{ @@ -44,7 +45,7 @@ extern "C" { * * @param[out] time_in_s: pointer to trusted time, in seconds. * - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if time_in_s is a null pointer + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if time_in_s is a null pointer * @retval OEMCrypto_SUCCESS on success */ OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer2.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer2.h index 31463db..8de99b5 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer2.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_clock_interface_layer2.h @@ -16,13 +16,14 @@ extern "C" { /** @defgroup secure-timer Non-monotonic Secure Clock * * Partners implementing a porting layer may either - * 1. Implement persistent_storage_layer2.h and this clock_interface_layer2.h, - * and then use the reference implementation clock_and_gn_layer1.c for the - * clock and generation interfaces. This is preferred if the hardware secure - * timer resets to 0 whenever the device is inactive. + * 1. Implement wtpi_persistent_storage_layer2.h and this + * wtpi_clock_interface_layer2.h, and then use the reference implementation + * wtpi_clock_and_gn_layer1.c for the clock and generation interfaces. This + * is preferred if the hardware secure timer resets to 0 whenever the device + * is inactive. * or - * 2. Implement both clock_interface_layer1.h and - * generation_number_interface.h. This is preferred if the system has a + * 2. Implement both wtpi_clock_interface_layer1.h and + * wtpi_generation_number_interface.h. This is preferred if the system has a * hardware secure wall clock. * * @{ @@ -38,7 +39,7 @@ extern "C" { * * @param[out] time_in_s: pointer to system time, in seconds. * - * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE if time_in_s is a null pointer + * @retval OEMCrypto_ERROR_INVALID_CONTEXT if time_in_s is a null pointer * @retval OEMCrypto_SUCCESS on success */ OEMCryptoResult WTPI_GetSecureTimer(uint64_t* time_in_s); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h index 7b37ef3..2a9bb16 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer1.h @@ -53,12 +53,13 @@ extern "C" { * Partners implementing the Crypto and Key Management porting layer may either * 1. Implement wtpi_crypto_and_key_management_interface_layer2.h and * key_mapping_interface.h, and then use the reference implementation - * crypto_and_key_management_layer1_hw.c. This is preferred if there's a + * wtpi_crypto_and_key_management_layer1_hw.c. This is preferred if there's a * hardware-backed crypto. * or * 2. Implement their own wtpi_crypto_and_key_management_interface_layer1.h, or - * use the reference implementation crypto_and_key_management_layer1_openssl.c - * and implement wtpi_device_key_access_interface.h and + * use the reference implementation + * wtpi_crypto_and_key_management_layer1_openssl.c and + * implement wtpi_device_key_access_interface.h and * wtpi_secure_buffer_access_interface.h. This is preferred if a software-based * crypto is used. */ @@ -410,9 +411,18 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( /** * Derives a layer 1 key handle from input |key_handle| with the specified - * context. + * context. The function derives either 128-bit key or 256-bit key. * - * The derivation process: + * The derivation process for 128-bit key output: + * 1. Using the input key handle |key_handle|, prepare an AES_CMAC 128-bit + * operation. + * 2. Feed |counter| into the CMAC. + * 3. Feed |context_length| bytes from |context| into the CMAC. + * 4. Create |out_key_handle| with the same process as + * WTPI_K1_CreateKeyHandle(), using the result of the CMAC as the new input key + * data. + * + * The derivation process for 256-bit key output: * 1. Using the input key handle |key_handle|, prepare an AES_CMAC 128-bit * operation. * 2. Feed |counter| into the CMAC. @@ -431,8 +441,8 @@ OEMCryptoResult WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( * called multiple times to derive different keys from the same context, this * counter should be incremented +2 each time. * @param[in] context: input data for AES CMAC - * @param[in] context_length: length of context data in bytesr - * @param[in] out_key_type: desired type of output keyr + * @param[in] context_length: length of context data in bytes + * @param[in] out_key_type: desired type of output key * @param[in] out_key_size: desired size of output key * @param[out] out_key_handle: output key handle * @@ -462,8 +472,7 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( * @param[in] wrapped_key_length: length of output buffer * * @retval OEMCrypto_SUCCESS success - * @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL, - * |wrapped_key_length| is not same as the size of the key to be wrapped, or + * @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the parameters are NULL, or * |key_handle| is invalid * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE any other failures */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h index 5e07ed1..8767f00 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_and_key_management_interface_layer2.h @@ -20,17 +20,19 @@ extern "C" { * * Crypto and Key Management layer 2 defines the interfaces between the * REFERENCE implementation of Crypto and Key Management layer 1 - * (crypto_and_key_management_layer2_hw.c) and the hardware-backed cryptography. + * (wtpi_crypto_and_key_management_layer2_hw.c) and the hardware-backed + * cryptography. * * Partners implementing the Crypto and Key Management porting layer may either * 1. Implement wtpi_crypto_and_key_management_interface_layer2.h and * key_mapping_interface.h, and then use the reference implementation - * crypto_and_key_management_layer1_hw.c. This is preferred if there's a + * wtpi_crypto_and_key_management_layer1_hw.c. This is preferred if there's a * hardware-backed crypto. * or * 2. Implement their own wtpi_crypto_and_key_management_interface_layer1.h, or - * use the reference implementation crypto_and_key_management_layer1_openssl.c - * and implement wtpi_device_key_access_interface.h and + * use the reference implementation + * wtpi_crypto_and_key_management_layer1_openssl.c and + * implement wtpi_device_key_access_interface.h and * wtpi_secure_buffer_access_interface.h. This is preferred if a software-based * crypto is used. * diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h index a84b419..58fdbd8 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_crypto_asymmetric_interface.h @@ -115,6 +115,8 @@ OEMCryptoResult WTPI_GetWrappedAsymmetricKeySize(size_t enc_private_key_length, AsymmetricKeyType key_type, size_t* buffer_size); +// TODO(b/185149406): Consider using WTPI_AsymmetricKey_Handle instead to avoid +// passing clear keys around. /** * Wraps the key data into a buffer that can be saved to the file system. The * wrapping must be device unique. @@ -126,15 +128,19 @@ OEMCryptoResult WTPI_GetWrappedAsymmetricKeySize(size_t enc_private_key_length, * This is given the clear, PKCS8-padded key and the key may be prefixed with * "SIGN" and a 4-byte code for the padding schemes. * + * @retval OEMCrypto_SUCCESS success + * @retval OEMCrypto_ERROR_INVALID_CONTEXT any of the pointers are NULL, + * |clear_key_length| is 0 + * @retval OEMCrypto_ERROR_SHORT_BUFFER output_length is too small + * @retval OEMCrypto_ERROR_UNKNOWN_FAILURE otherwise + * * @param[out] output: destination buffer that will contain the wrapped key data - * @param[out] output_length: length of destination buffer + * @param[in] output_length: length of destination buffer * @param[in] key_type: type of asymmetric key * @param[in] clear_key: DER-encoded PKCS8 RSA private key data with 8 bytes of * prefix data or PKCS8 ECPrivateKey (no prefix data). * @param[in] clear_key_length: length of input data */ -// TODO(b/185149406): Consider using WTPI_AsymmetricKey_Handle instead to avoid -// passing clear keys around. OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* output, size_t output_length, AsymmetricKeyType key_type, const uint8_t* clear_key, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_decrypt_sample_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_decrypt_sample_interface.h index 9b63ac9..d9c1abf 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_decrypt_sample_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_decrypt_sample_interface.h @@ -43,8 +43,8 @@ extern "C" { * Partners implementing the Decrypt Sample porting layer may either * 1. Implement their own wtpi_decrypt_sample_interface.h. This is preferred if * the device has hardware support for full-sample decryption, or - * 2. Use the reference implementation decrypt_sample.c. This is preferred when - * there is no hardware support for full-sample decryption. The reference + * 2. Use the reference implementation wtpi_decrypt_sample.c. This is preferred + * when there is no hardware support for full-sample decryption. The reference * implementation will split the subsamples and decrypt them individually using * the crypto_and_key_management_interface_layer1 component. */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_access_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_access_interface.h index 0ca35f4..e7a9d4c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_access_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_access_interface.h @@ -19,7 +19,7 @@ extern "C" { * directly call functions in this API. Partners have the option to implement * this API and use Widevine's reference implementation of the layer 1 interface * which wraps around the functions in this API, or instead implement all of the - * [Device Key layer 1](dev-key) functions. + * [Device Keys](@ref dev-key) functions. * * @{ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_interface.h index efd2c54..ac470c9 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_device_key_interface.h @@ -45,12 +45,6 @@ extern "C" { */ #define DEVICE_KEY_WRAP_INTERNAL_KEY 0x604e77a1 -/** A device unique key for signing the wrapped internal key used by the - * implementation of the key management layer. This should be used as a key - * derivation context in WTPI_K1_DeriveDeviceKeyIntoHandle(). - */ -#define DEVICE_KEY_SIGN_INTERNAL_KEY 0x90b4a189 - /** A device unique key for encrypting the mac keys in usage entry. */ #define DEVICE_KEY_WRAP_MAC_KEY 0x125cc98d diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_generation_number_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_generation_number_interface.h index 04db04e..f2febff 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_generation_number_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_generation_number_interface.h @@ -21,9 +21,9 @@ extern "C" { * * Partners implementing a porting layer may either * 1. Implement wtpi_persistent_storage.h and wtpi_clock_interface_layer2.h, - * and then use the reference implementation clock_and_gn_layer1.c for the - * clock and generation interfaces. This is preferred if the hardware secure - * timer resets to 0 whenever the device is inactive. + * and then use the reference implementation wtpi_clock_and_gn_layer1.c for + * the clock and generation interfaces. This is preferred if the hardware + * secure timer resets to 0 whenever the device is inactive. * or * 2. Implement both wtpi_clock_interface_layer1.h and * this wtpi_generation_number_interface.h. This is preferred if the system diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_persistent_storage.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_persistent_storage.h index bb52fa2..2cdece4 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_persistent_storage.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_persistent_storage.h @@ -18,9 +18,9 @@ extern "C" { * Partners implementing a porting layer may either * 1. Implement this wtpi_persistent_storage.h and * wtpi_clock_interface_layer2.h, and then use the reference implementation - * clock_and_gn_layer1.c for the clock and generation interfaces. This is - * preferred if the hardware secure timer resets to 0 whenever the device is - * inactive. + * wtpi_clock_and_gn_layer1.c for the clock and generation interfaces. This + * is preferred if the hardware secure timer resets to 0 whenever the device + * is inactive. * or * 2. Implement both wtpi_clock_interface_layer1.h and * wtpi_generation_number_interface.h. This is preferred if the system has a diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_secure_buffer_access_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_secure_buffer_access_interface.h index f59cba0..ea6ca19 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_secure_buffer_access_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi/wtpi_secure_buffer_access_interface.h @@ -13,8 +13,8 @@ extern "C" { /** @defgroup secure-buffer Secure Buffer Access * - * Interface used by the reference [sample decryption - * interface])(decrypt-sample) to access secure buffers. + * Interface used by the reference + * [sample decryption interface](@ref decrypt-sample) to access secure buffers. * * @{ */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/key_mapping_interface.h b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/key_mapping_interface.h index 2a7535d..2daf9fb 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/key_mapping_interface.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/key_mapping_interface.h @@ -23,12 +23,12 @@ extern "C" { * WTPI_K1_SymmetricKey_Handle defined in Crypto and Key Management layer 1, * with a WTPI_K2_SymmetricKey_Handle defined in Crypto and Key Management layer * 2. This is used by both the REFERENCE implementation of hardware-backed - * Crypto and Key Management layer 1 (crypto_and_key_management_layer1_hw.c) and - * the TEST implementation of hardware-backed Crypto and Key Management layer 2 - * (crypto_and_key_management_layer2_hw.c). + * Crypto and Key Management layer 1(wtpi_crypto_and_key_management_layer1_hw.c) + * and the TEST implementation of hardware-backed Crypto and Key Management + * layer 2(wtpi_crypto_and_key_management_layer2_hw.c). * * Partners using the reference implementation - * crypto_and_key_management_layer1_hw.c and implementing their own + * wtpi_crypto_and_key_management_layer1_hw.c and implementing their own * wtpi_crypto_and_key_management_interface_layer2.h may need to implement this * interface as well. */ diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_abort.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_abort.c new file mode 100644 index 0000000..6881016 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_abort.c @@ -0,0 +1,9 @@ +/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_abort_interface.h" + +#include + +void WTPI_Abort(void) { abort(); } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/clock_and_gn_layer1.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c similarity index 99% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/clock_and_gn_layer1.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c index 8a54765..4169d2c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/clock_and_gn_layer1.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.c @@ -9,6 +9,7 @@ #include #include "OEMCryptoCENC.h" +#include "oemcrypto_check_macros.h" #include "oemcrypto_wall_clock.h" #include "wtpi_clock_interface_layer2.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" @@ -179,6 +180,7 @@ OEMCryptoResult WTPI_TerminateClock(void) { OEMCrypto_Clock_Security_Level WTPI_GetClockType(void) { return kSecureTimer; } OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { + RETURN_INVALID_CONTEXT_IF_NULL(time_in_s); OEMCryptoResult status = OEMCrypto_SUCCESS; if (!gInitialized) { LOGD("Clock needs to initialize."); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crc32.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crc32.c similarity index 100% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/crc32.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crc32.c diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_and_key_management_layer1_hw.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c similarity index 99% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_and_key_management_layer1_hw.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c index 51cecd1..869f524 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_and_key_management_layer1_hw.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_hw.c @@ -88,7 +88,7 @@ static OEMCryptoResult EncryptAndSignKey(WTPI_K2_SymmetricKey_Handle key_handle, // Compute the signature of the data past the signature block and store it // at the start of the output buffer. WTPI_K2_SymmetricKey_Handle signing_key_handle = NULL; - result = WTPI_K2_DeriveDeviceKeyIntoHandle(DEVICE_KEY_SIGN_INTERNAL_KEY, + result = WTPI_K2_DeriveDeviceKeyIntoHandle(DEVICE_KEY_WRAP_INTERNAL_KEY, MAC_KEY_CLIENT, &signing_key_handle, KEY_SIZE_256); if (result != OEMCrypto_SUCCESS) return result; @@ -111,11 +111,11 @@ static OEMCryptoResult VerifyAndDecryptKey( // Verify the signature first, before decrypting. WTPI_K2_SymmetricKey_Handle signing_key_handle = NULL; OEMCryptoResult result = WTPI_K2_DeriveDeviceKeyIntoHandle( - DEVICE_KEY_SIGN_INTERNAL_KEY, MAC_KEY_SERVER, &signing_key_handle, + DEVICE_KEY_WRAP_INTERNAL_KEY, MAC_KEY_SERVER, &signing_key_handle, KEY_SIZE_256); if (result != OEMCrypto_SUCCESS) return result; result = WTPI_C2_HMAC_SHA256_Verify( - signing_key_handle, (uint8_t*)(&wrapped->wrapped_key_data), + signing_key_handle, (const uint8_t*)(&wrapped->wrapped_key_data), sizeof(wrapped->wrapped_key_data), wrapped->signature); WTPI_K2_FreeKeyHandle(signing_key_handle); if (result != OEMCrypto_SUCCESS) return result; @@ -741,6 +741,7 @@ OEMCryptoResult WTPI_C1_CopyToOutputBuffer( } OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) { + if (out == NULL || size == 0) return OEMCrypto_ERROR_INVALID_CONTEXT; if (RAND_bytes(out, size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_and_key_management_layer1_openssl.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c similarity index 93% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_and_key_management_layer1_openssl.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c index 5fa62b3..ab8e50c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_and_key_management_layer1_openssl.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_and_key_management_layer1_openssl.c @@ -93,7 +93,9 @@ static OEMCryptoResult GetKeyType(WTPI_K1_SymmetricKey_Handle key_handle, return OEMCrypto_SUCCESS; } -static OEMCryptoResult DeriveFromDeviceKey(uint32_t context, uint8_t* out_key, +static OEMCryptoResult DeriveFromDeviceKey(uint32_t context, + SymmetricKeyType out_key_type, + uint8_t* out_key, KeySize out_key_size) { ABORT_IF(out_key == NULL, "Parameters are NULL or 0"); ABORT_IF(out_key_size != KEY_SIZE_128 && out_key_size != KEY_SIZE_256, @@ -101,11 +103,21 @@ static OEMCryptoResult DeriveFromDeviceKey(uint32_t context, uint8_t* out_key, const uint8_t* device_key = WTPI_GetDeviceKey(); KeySize device_key_size = WTPI_GetDeviceKeySize(); - uint8_t full_context[16] = {'.', '.', '.', '.', 'W', 'i', 'd', 'e', - 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'}; + // Prepare full context for key derivation + // Server and client MAC keys must derive to the same key. + const SymmetricKeyType type_temp = + out_key_type == MAC_KEY_SERVER ? MAC_KEY_CLIENT : out_key_type; + // Cast the type into 32 bits so it is the same size as the gap left for it in + // full_context. This will be a no-op on most architectures. + const uint32_t type_32 = (uint32_t)type_temp; + // Build a full context that is unique to this starting context / key type + // combination. We start with a context template with blanks at the beginning + // and fill the blanks with the starting context and key type. + uint8_t full_context[20] = {'.', '.', '.', '.', '.', '.', '.', '.', 'W', 'i', + 'd', 'e', 'v', 'i', 'n', 'e', ' ', 'O', 'P', 'K'}; const size_t context_length = sizeof(full_context); - // Set the first four bytes to the specific use for this key. memcpy(full_context, &context, 4); + memcpy(full_context + 4, &type_32, 4); const uint8_t counter = 1; if (!OPKI_DeriveKeyWithCMAC(device_key, device_key_size, counter, full_context, context_length, out_key_size, @@ -130,7 +142,8 @@ static OEMCryptoResult EncryptAndSignKey(const uint8_t* key, size_t key_size, // Encrypt the key uint8_t encryption_key[KEY_SIZE_128]; - result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, encryption_key, + result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, ENCRYPTION_KEY, + encryption_key, OPK_LengthToKeySize(sizeof(encryption_key))); if (result != OEMCrypto_SUCCESS) return result; if (!OPKI_AESCBCEncrypt(key, key_size, wrapped->wrapped_key_data.iv, @@ -140,7 +153,8 @@ static OEMCryptoResult EncryptAndSignKey(const uint8_t* key, size_t key_size, } // Compute the signature of the wrapped key and store it uint8_t signing_key[KEY_SIZE_256]; - result = DeriveFromDeviceKey(DEVICE_KEY_SIGN_INTERNAL_KEY, signing_key, + result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, MAC_KEY_CLIENT, + signing_key, OPK_LengthToKeySize(sizeof(signing_key))); if (result != OEMCrypto_SUCCESS) return result; const uint8_t* wrapped_key_data = @@ -169,9 +183,9 @@ static OEMCryptoResult VerifyAndDecryptKey( // Verify the signature first, before decrypting uint8_t signing_key[KEY_SIZE_256]; - OEMCryptoResult result = - DeriveFromDeviceKey(DEVICE_KEY_SIGN_INTERNAL_KEY, signing_key, - OPK_LengthToKeySize(sizeof(signing_key))); + OEMCryptoResult result = DeriveFromDeviceKey( + DEVICE_KEY_WRAP_INTERNAL_KEY, MAC_KEY_SERVER, signing_key, + OPK_LengthToKeySize(sizeof(signing_key))); if (result != OEMCrypto_SUCCESS) return result; const uint8_t* wrapped_key_data = (const uint8_t*)(&wrapped->wrapped_key_data); @@ -188,7 +202,8 @@ static OEMCryptoResult VerifyAndDecryptKey( // Decrypt the key uint8_t decryption_key[KEY_SIZE_128]; - result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, decryption_key, + result = DeriveFromDeviceKey(DEVICE_KEY_WRAP_INTERNAL_KEY, ENCRYPTION_KEY, + decryption_key, OPK_LengthToKeySize(sizeof(decryption_key))); if (result != OEMCrypto_SUCCESS) return result; if (!OPKI_AESCBCDecrypt(wrapped->wrapped_key_data.wrapped_key, @@ -419,7 +434,7 @@ OEMCryptoResult WTPI_K1_DeriveDeviceKeyIntoHandle( if (out_key_handle == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; uint8_t derived_key[KEY_SIZE_256]; OEMCryptoResult result = - DeriveFromDeviceKey(context, derived_key, out_key_size); + DeriveFromDeviceKey(context, out_key_type, derived_key, out_key_size); if (result != OEMCrypto_SUCCESS) return result; return WTPI_K1_CreateKeyHandle(derived_key, (size_t)out_key_size, @@ -530,6 +545,7 @@ OEMCryptoResult WTPI_K1_DeriveKeyFromKeyHandle( out_key_size, derived_key)) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + return WTPI_K1_CreateKeyHandle(derived_key, (size_t)out_key_size, out_key_type, out_key_handle); } @@ -615,6 +631,7 @@ OEMCryptoResult WTPI_C1_CopyToOutputBuffer( } OEMCryptoResult WTPI_C1_RandomBytes(uint8_t* out, size_t size) { + if (out == NULL || size == 0) return OEMCrypto_ERROR_INVALID_CONTEXT; if (RAND_bytes(out, size) != 1) return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_asymmetric.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c similarity index 100% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_asymmetric.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_asymmetric.c diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_wrap_asymmetric.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_wrap_asymmetric.c similarity index 100% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/crypto_wrap_asymmetric.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_wrap_asymmetric.c diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/decrypt_sample.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_decrypt_sample.c similarity index 100% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/decrypt_sample.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_decrypt_sample.c diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c similarity index 100% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/device_key.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.c diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_logging.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_logging.c new file mode 100644 index 0000000..d4c3ac6 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_logging.c @@ -0,0 +1,60 @@ +/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_logging_interface.h" + +#include +#include +#include +#include +#include + +#include "wtpi_abort_interface.h" + +#if !defined(OPK_LOG_LEVEL) +# define OPK_LOG_LEVEL LOG_DEBUG +#endif + +static size_t LogPriorityToOrdering(LogPriority priority) { + switch (priority) { + case LOG_NONE: + return 0; + case LOG_ERROR: + return 1; + case LOG_DEBUG: + return 2; + } + ABORT("invalid log priority"); +} + +static const char* LogPriorityToName(LogPriority priority) { + static const char* const kPriorityNames[] = {"NONE", "ERROR", "DEBUG"}; + return kPriorityNames[LogPriorityToOrdering(priority)]; +} + +/* A test implementation for logging. Outputs logs to stdout. */ +void WTPI_Log(const char* file, const char* function, int line, + LogPriority level, const char* fmt, ...) { + if (level == LOG_NONE) { + fprintf(stderr, "[FATAL:%s(%d)] Cannot log at LOG_NONE level.\n", file, + line); + fflush(stderr); + return; + } + if (LogPriorityToOrdering(level) > LogPriorityToOrdering(OPK_LOG_LEVEL)) { + // Log message is below the threshold for logging. + return; + } + + fprintf(stderr, "[%s:%s(%d):%s] ", LogPriorityToName(level), file, line, + function); + + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fputc('\n', stderr); + fflush(stderr); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp new file mode 100644 index 0000000..a6081c7 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_reference.gyp @@ -0,0 +1,109 @@ +# Copyright 2019 Google LLC.All Rights Reserved.This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. + +{ + 'variables': { + # Include directory that contains wtpi_config_macros.h. + 'config_macros_header_dir%': '.', + # TODO(b/207176111): add test scripts to cover both reference crypto impl + 'reference_crypto_impl%': 'software', + }, + 'includes': [ + '../../strict_compiler_flags.gypi', + ], + 'target_defaults': { + 'type': 'static_library', + 'standalone_static_library': 1, + 'dependencies': [ + '../oemcrypto_ta.gyp:oemcrypto_ta', + ], + }, + 'targets': [ + { + 'target_name': 'oemcrypto_ta_reference_root_of_trust', + 'sources': [ + 'wtpi_crypto_wrap_asymmetric.c', + 'wtpi_device_key.c', + 'wtpi_root_of_trust_layer1.c', + ], + 'dependencies': [ + '../../../odk/src/odk.gyp:odk', + ], + }, + { + 'target_name': 'oemcrypto_ta_reference_clock', + 'sources': [ + 'wtpi_clock_and_gn_layer1.c', + ], + 'dependencies': [ + '../../../odk/src/odk.gyp:odk', + ], + }, + { + 'target_name': 'oemcrypto_ta_reference_abort', + 'sources': [ + 'wtpi_abort.c', + ], + }, + { + 'target_name': 'oemcrypto_ta_reference_logging', + 'sources': [ + 'wtpi_logging.c', + ], + }, + { + 'target_name': 'oemcrypto_ta_reference_crypto', + 'include_dirs': [ + '<(config_macros_header_dir)', + '.', + ], + # The reference implementation of the crypto interface uses + # BoringSSL/OpenSSL, which requires C11. These flags effectively do the + # opposite of the default flags, filtering out the C99 flag and + # un-filtering-out the C11 flag. + 'cflags_c': [ + '-std=c11', + ], + 'cflags_c/': [ + ['exclude', '-std=*'], + ['include', '-std=c11'], + ], + 'sources': [ + 'crypto_util.c', + 'ecc_util.c', + 'rsa_util.c', + 'wtpi_crc32.c', + 'wtpi_crypto_asymmetric.c', + 'wtpi_decrypt_sample.c', + ], + 'conditions': [ + ['reference_crypto_impl=="hardware"', { + 'sources': [ + 'wtpi_crypto_and_key_management_layer1_hw.c', + ], + }], + ['reference_crypto_impl=="software"', { + 'sources': [ + 'wtpi_crypto_and_key_management_layer1_openssl.c', + ], + }], + ], + 'variables': { + # Needed for BoringSSL dependency build files. These SHOULD already be + # defined by a higher-level configuration, but sometimes the OPK TA + # gets included in targets that don't define them, so we define them + # again here defensively. + + 'privacy_crypto_impl%': 'boringssl', + 'boringssl_libcrypto_path%': '<(DEPTH)/third_party/boringssl/boringssl.gyp:crypto', + }, + 'includes': [ + '../../../../util/libcrypto_dependency.gypi', + ], + 'dependencies': [ + '../../../odk/src/odk.gyp:odk', + ], + }, + ], +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_reference/root_of_trust_layer1.c b/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c similarity index 100% rename from oemcrypto/opk/oemcrypto_ta/wtpi_reference/root_of_trust_layer1.c rename to oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.c diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/clock_interface_test.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/clock_interface_test.cpp new file mode 100644 index 0000000..5847d78 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/clock_interface_test.cpp @@ -0,0 +1,112 @@ +// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "opk_init.h" +#include "wtpi_clock_interface_layer1.h" + +namespace { + +constexpr uint32_t kSecondsElapsed = 5; +constexpr uint32_t kSecondsTolerance = 1; + +// temporary file to store the trusted time before reboot +const char* kSavedTrustedTime = "saved_trusted_time"; + +template +std::ostream& binary_write(std::ostream& stream, const T& value) { + return stream.write(reinterpret_cast(&value), sizeof(T)); +} + +template +std::istream& binary_read(std::istream& stream, T& value) { + return stream.read(reinterpret_cast(&value), sizeof(T)); +} + +void SaveTrustedTime(uint64_t time) { + std::ofstream stream(kSavedTrustedTime, std::ios::binary); + binary_write(stream, time); +} + +uint64_t LoadTrustedTime() { + uint64_t time = ULLONG_MAX; + std::ifstream stream(kSavedTrustedTime, std::ios::binary); + binary_read(stream, time); + return time; +} + +bool IsTrustedTimeSaved() { + std::ifstream stream(kSavedTrustedTime); + return stream.good(); +} + +}; // namespace + +class ClockInterfaceTest : public ::testing::Test { + protected: + ClockInterfaceTest() {} + + void SetUp() override { + ::testing::Test::SetUp(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + ASSERT_TRUE(OPK_Initialize()); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_InitializeClock()); + } + + void TearDown() override { + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_TerminateClock()); + OPK_Terminate(); + ::testing::Test::TearDown(); + } +}; + +TEST_F(ClockInterfaceTest, TrustedTimeNULL) { + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_GetTrustedTime(NULL)); +} + +TEST_F(ClockInterfaceTest, ClockBasic) { + uint64_t time_in_s; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_GetTrustedTime(&time_in_s)); + printf("Sleep %us before validating the trusted time...\n", + kSecondsElapsed + kSecondsTolerance); + sleep(kSecondsElapsed + kSecondsTolerance); + uint64_t new_time_in_s; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_GetTrustedTime(&new_time_in_s)); + ASSERT_TRUE(new_time_in_s > time_in_s + kSecondsElapsed); +} + +class ClockRebootTest : public ClockInterfaceTest {}; + +// The reboot tests verify that the trusted time returned by +// WTPI_GetTrustedTime() never goes backward after a device reboot +TEST_F(ClockRebootTest, SaveClockBeforeReboot) { + printf("Sleep %us before saving the trusted time...\n", kSecondsElapsed); + sleep(kSecondsElapsed); + // This is to simulate that the device is up for at least kSecondsElapsed + // before reboot. The test CheckClockAfterReboot below will validate the + // trusted time immediately after reboot. If WTPI_GetTrustedTime() is + // implemented on top of a timer which gets reset to 0 after every reboot, the + // trusted time could potentially go backward compared with the last recorded + // trusted time before reboot in a problematic implementation. This test is to + // make sure the trusted stays monotonic. + uint64_t current_time; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_GetTrustedTime(¤t_time)); + SaveTrustedTime(current_time); +} + +TEST_F(ClockRebootTest, CheckClockAfterReboot) { + ASSERT_EQ(true, IsTrustedTimeSaved()); + uint64_t current_time; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_GetTrustedTime(¤t_time)); + uint64_t saved_time = LoadTrustedTime(); + ASSERT_TRUE(current_time >= saved_time); + remove(kSavedTrustedTime); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c index a0bb9db..d53728e 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.c @@ -109,7 +109,7 @@ void OPK_Pack_SymmetricKeyType(ODK_Message* message, return; } - OPK_Pack_uint32_t(message, (const uint32_t*)value); + OPK_Pack_int(message, (const int*)value); } void OPK_Unpack_SymmetricKeyType(ODK_Message* message, @@ -119,7 +119,7 @@ void OPK_Unpack_SymmetricKeyType(ODK_Message* message, return; } - OPK_Unpack_uint32_t(message, (uint32_t*)value); + OPK_Unpack_int(message, (int*)value); } void OPK_Pack_AsymmetricKeyType(ODK_Message* message, @@ -129,7 +129,7 @@ void OPK_Pack_AsymmetricKeyType(ODK_Message* message, return; } - OPK_Pack_uint32_t(message, (const uint32_t*)value); + OPK_Pack_int(message, (const int*)value); } void OPK_Unpack_AsymmetricKeyType(ODK_Message* message, @@ -139,7 +139,7 @@ void OPK_Unpack_AsymmetricKeyType(ODK_Message* message, return; } - OPK_Unpack_uint32_t(message, (uint32_t*)value); + OPK_Unpack_int(message, (int*)value); } void OPK_Pack_RSA_Padding_Scheme(ODK_Message* message, @@ -168,7 +168,7 @@ void OPK_Pack_KeySize(ODK_Message* message, const KeySize* value) { return; } - OPK_Pack_size_t(message, (const size_t*)value); + OPK_Pack_int(message, (const int*)value); } void OPK_Unpack_KeySize(ODK_Message* message, KeySize* value) { @@ -177,7 +177,7 @@ void OPK_Unpack_KeySize(ODK_Message* message, KeySize* value) { return; } - OPK_Unpack_size_t(message, (size_t*)value); + OPK_Unpack_int(message, (int*)value); } void OPK_Pack_OEMCrypto_SharedMemory(ODK_Message* message, @@ -193,3 +193,23 @@ void OPK_Unpack_OEMCrypto_SharedMemory(ODK_Message* message, (void)value; ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); } + +void OPK_Pack_OEMCrypto_Clock_Security_Level( + ODK_Message* message, const OEMCrypto_Clock_Security_Level* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Pack_uint32_t(message, (const uint32_t*)value); +} + +void OPK_Unpack_OEMCrypto_Clock_Security_Level( + ODK_Message* message, OEMCrypto_Clock_Security_Level* value) { + if (value == NULL) { + ODK_MESSAGE_SETSTATUS(message, MESSAGE_STATUS_NULL_POINTER_ERROR); + return; + } + + OPK_Unpack_uint32_t(message, (uint32_t*)value); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h index f588462..48b67a2 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/common/common_special_cases.h @@ -44,9 +44,15 @@ void OPK_Unpack_RSA_Padding_Scheme(ODK_Message* msg, void OPK_Pack_KeySize(ODK_Message* msg, const KeySize* key_size); void OPK_Unpack_KeySize(ODK_Message* msg, KeySize* key_size); + void OPK_Pack_OEMCrypto_SharedMemory(ODK_Message* message, const OEMCrypto_SharedMemory* value); - void OPK_Unpack_OEMCrypto_SharedMemory(ODK_Message* message, OEMCrypto_SharedMemory* value); + +void OPK_Pack_OEMCrypto_Clock_Security_Level( + ODK_Message* msg, const OEMCrypto_Clock_Security_Level* value); +void OPK_Unpack_OEMCrypto_Clock_Security_Level( + ODK_Message* msg, OEMCrypto_Clock_Security_Level* value); + #endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp index 3935c8a..5c50093 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/crypto_test.cpp @@ -6,7 +6,9 @@ #include "OEMCryptoCENC.h" #include "log.h" +#include "oemcrypto_key_types.h" #include "opk_init.h" +#include "ssl_util.h" #include "tos_shared_memory_interface.h" #include "wtpi_crc32_interface.h" #include "wtpi_crypto_and_key_management_interface_layer1.h" @@ -26,57 +28,66 @@ class CryptoTest : public ::testing::Test { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); - OPK_Initialize(); + ASSERT_EQ(true, OPK_Initialize()); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_InitializeKeyManagement()); } void TearDown() override { + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_TerminateKeyManagement()); OPK_Terminate(); ::testing::Test::TearDown(); } }; TEST_F(CryptoTest, CreateKeyHandleWorksWithTypicalKeySize) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, CONTENT_KEY, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, CONTENT_KEY, + &key_handle)); ASSERT_NE(nullptr, key_handle); - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, CONTENT_KEY, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, CONTENT_KEY, + &key_handle)); ASSERT_NE(nullptr, key_handle); } TEST_F(CryptoTest, CreateKeyHandleFailsWithBadParams) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_K1_CreateKeyHandle(key, UNKNOWN_KEY_SIZE, CONTENT_KEY, &key_handle)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_CreateKeyHandle(key.data(), UNKNOWN_KEY_SIZE, CONTENT_KEY, + &key_handle)); ASSERT_EQ( OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_K1_CreateKeyHandle(NULL, KEY_SIZE_128, CONTENT_KEY, &key_handle)); - ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, CONTENT_KEY, NULL)); + ASSERT_EQ( + OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, CONTENT_KEY, NULL)); } TEST_F(CryptoTest, AESCBCEncryptHelloWorld) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + SymmetricKeyType key_type = CONTENT_KEY; WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, + key_type, &key_handle)); ASSERT_NE(nullptr, key_handle); // Encrypt @@ -99,14 +110,16 @@ TEST_F(CryptoTest, AESCBCEncryptHelloWorld) { } TEST_F(CryptoTest, AESCBCEncryptFailsForBadInput) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + SymmetricKeyType key_type = CONTENT_KEY; WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, + key_type, &key_handle)); std::string message = "Hello world!______"; std::vector input(message.begin(), message.end()); @@ -140,14 +153,16 @@ TEST_F(CryptoTest, AESCBCEncryptFailsForBadInput) { } TEST_F(CryptoTest, AESCBCDecryptHelloWorld) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + SymmetricKeyType key_type = CONTENT_KEY; WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, + key_type, &key_handle)); ASSERT_NE(nullptr, key_handle); // Decrypt @@ -169,14 +184,16 @@ TEST_F(CryptoTest, AESCBCDecryptHelloWorld) { } TEST_F(CryptoTest, AESCBCEncryptDecryptLoop) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, CONTENT_KEY, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, CONTENT_KEY, + &key_handle)); ASSERT_NE(nullptr, key_handle); std::string message = "EncryptDecryptLoop"; @@ -201,14 +218,16 @@ TEST_F(CryptoTest, AESCBCEncryptDecryptLoop) { } TEST_F(CryptoTest, AESCBCDecryptFailsForBadInput) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + SymmetricKeyType key_type = CONTENT_KEY; WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ(OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, key_type, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, + key_type, &key_handle)); std::vector input = {72, 148, 193, 81, 175, 242, 38, 26, 247, 167, 88, 96, 223, 94, 41, 95}; @@ -403,14 +422,16 @@ TEST_F(CryptoTest, Crc32Cont_OutputBufferFailsWithBadInput) { } TEST_F(CryptoTest, HMAC_SHA256FailsWithBadInput) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &key_handle)); std::vector input; for (int i = 0; i < 32; i++) { @@ -433,14 +454,16 @@ TEST_F(CryptoTest, HMAC_SHA256FailsWithBadInput) { } TEST_F(CryptoTest, HMAC_SHA256Basic) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &key_handle)); std::vector input; for (int i = 0; i < 32; i++) { @@ -461,14 +484,16 @@ TEST_F(CryptoTest, HMAC_SHA256Basic) { } TEST_F(CryptoTest, HMAC_SHA256_VerifyBasic) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &key_handle)); std::vector input; for (int i = 0; i < 32; i++) { @@ -490,14 +515,16 @@ TEST_F(CryptoTest, HMAC_SHA256_VerifyBasic) { } TEST_F(CryptoTest, HMAC_SHA256_VerifyFailsWithBadInput) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &key_handle)); std::vector input; for (int i = 0; i < 32; i++) { @@ -524,14 +551,16 @@ TEST_F(CryptoTest, HMAC_SHA256_VerifyFailsWithBadInput) { } TEST_F(CryptoTest, HMAC_SHA1Basic) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &key_handle)); std::vector input; for (int i = 0; i < 32; i++) { @@ -550,14 +579,16 @@ TEST_F(CryptoTest, HMAC_SHA1Basic) { } TEST_F(CryptoTest, HMAC_SHA1FailsWithBadInput) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_256, MAC_KEY_CLIENT, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &key_handle)); std::vector input; for (int i = 0; i < 32; i++) { @@ -689,12 +720,13 @@ TEST_F(CryptoTest, CreateAsymmetricKeyHandleFailsForBadInput) { WTPI_CreateAsymmetricKeyHandle(test_rsa_key_der, TEST_RSA_KEY_DER_LEN, DRM_RSA_PRIVATE_KEY, NULL)); - const uint8_t bad_format[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector bad_format; + for (int i = 0; i < 32; i++) { + bad_format.push_back(i); + } ASSERT_EQ(OEMCrypto_ERROR_INVALID_RSA_KEY, - WTPI_CreateAsymmetricKeyHandle(bad_format, 32, DRM_RSA_PRIVATE_KEY, - &handle)); + WTPI_CreateAsymmetricKeyHandle(bad_format.data(), 32, + DRM_RSA_PRIVATE_KEY, &handle)); } TEST_F(CryptoTest, RSASign) { @@ -712,7 +744,17 @@ TEST_F(CryptoTest, RSASign) { WTPI_RSASign(handle, input.data(), input.size(), output.data(), &output_len, kSign_RSASSA_PSS)); - // TODO: verify RSA signature + // Verify with openssl, since we can't use WTPI functions to verify + RSA* rsa = NULL; + ASSERT_TRUE( + DeserializePKCS8PrivateKey(test_rsa_key_der, TEST_RSA_KEY_DER_LEN, &rsa)); + + boringssl_ptr pkey(EVP_PKEY_new()); + ASSERT_EQ(1, EVP_PKEY_set1_RSA(pkey.get(), rsa)); + + EXPECT_TRUE(VerifyPSSSignature(pkey.get(), input.data(), input.size(), + output.data(), output.size())) + << "PSS signature check failed."; } TEST_F(CryptoTest, RSASignFailsWithBadInput) { @@ -820,9 +862,7 @@ TEST_F(CryptoTest, GetSignatureSizeFailsForBadInputs) { WTPI_GetSignatureSize(handle, NULL)); } -// TODO(b/205752860): wtpi_crypto_and_key_management_interface_layer1.h does not -// actually specify what should happen for NULL/0 inputs to RandomBytes() -TEST_F(CryptoTest, DISABLED_RandomBytesFailsForBadInputs) { +TEST_F(CryptoTest, RandomBytesFailsForBadInputs) { std::vector out(32, 0); size_t size = 32; ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, WTPI_C1_RandomBytes(NULL, size)); @@ -831,14 +871,16 @@ TEST_F(CryptoTest, DISABLED_RandomBytesFailsForBadInputs) { } TEST_F(CryptoTest, DeriveKeyFromKeyHandleFailsForBadInputs) { - const uint8_t key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}; + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; - ASSERT_EQ( - OEMCrypto_SUCCESS, - WTPI_K1_CreateKeyHandle(key, KEY_SIZE_128, DERIVING_KEY, &key_handle)); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, DERIVING_KEY, + &key_handle)); uint8_t counter = 0; const uint8_t context[] = {50, 51, 52, 53}; @@ -864,4 +906,515 @@ TEST_F(CryptoTest, DeriveKeyFromKeyHandleFailsForBadInputs) { out_key_size, NULL)); } -// TODO: DeriveKeyFromKeyHandle with expected CMAC+counter construction output +TEST_F(CryptoTest, DeriveKeyFromKeyHandleWorks) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + + WTPI_K1_SymmetricKey_Handle key_handle; + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, DERIVING_KEY, + &key_handle)); + + const uint8_t context[4] = {'T', 'E', 'S', 'T'}; + + WTPI_K1_SymmetricKey_Handle out_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_DeriveKeyFromKeyHandle(key_handle, 1, context, + sizeof(context), MAC_KEY_CLIENT, + KEY_SIZE_256, &out_key_handle)); + + const uint8_t expected_derived_key[] = {31, 230, 128, 12, 6, 223, 177, 250, + 199, 161, 58, 52, 105, 184, 151, 162, + 131, 204, 51, 13, 29, 230, 183, 214, + 157, 152, 245, 50, 81, 137, 110, 56}; + + WTPI_K1_SymmetricKey_Handle expected_derived_key_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(expected_derived_key, KEY_SIZE_256, + MAC_KEY_CLIENT, &expected_derived_key_handle)); + + // perform an operation with out_key_handle and expected_derived_key_handle to + // prove they are using the same underlying key data + std::vector input; + for (int i = 0; i < 32; i++) { + input.push_back(i); + } + std::vector output1(32, 1); + std::vector output2(32, 2); + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(out_key_handle, input.data(), input.size(), + output1.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(expected_derived_key_handle, input.data(), + input.size(), output2.data())); + + for (int i = 0; i < 32; i++) { + ASSERT_EQ(output1[i], output2[i]); + } +} + +TEST_F(CryptoTest, WrapKeyFailsForBadInputs) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, DERIVING_KEY, + &key_handle)); + + uint32_t context = 0x1234; + SymmetricKeyType key_type = DERIVING_KEY; + uint8_t wrapped_key[256]; + uint8_t wrapped_key_length = KEY_SIZE_128; + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_WrapKey(context, NULL, key_type, wrapped_key, + wrapped_key_length)); + ASSERT_EQ( + OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_WrapKey(context, key_handle, key_type, NULL, wrapped_key_length)); +} + +TEST_F(CryptoTest, UnwrapKeyFailsForBadInputs) { + WTPI_K1_SymmetricKey_Handle out_key_handle; + + uint32_t context = 0x1234; + SymmetricKeyType key_type = DERIVING_KEY; + uint8_t wrapped_key[256]; + uint8_t wrapped_key_length = KEY_SIZE_128; + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_UnwrapIntoKeyHandle(context, NULL, wrapped_key_length, + key_type, &out_key_handle)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_UnwrapIntoKeyHandle(context, wrapped_key, 7, key_type, + &out_key_handle)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_UnwrapIntoKeyHandle(context, wrapped_key, + wrapped_key_length, key_type, NULL)); +} + +TEST_F(CryptoTest, WrapAndUnwrapKeyWorks) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + + WTPI_K1_SymmetricKey_Handle key_handle; + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &key_handle)); + + uint32_t context = 0x1234; + SymmetricKeyType key_type = MAC_KEY_CLIENT; + uint8_t wrapped_key[256]; + uint8_t wrapped_key_length = KEY_SIZE_256; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_WrapKey(context, key_handle, key_type, wrapped_key, + wrapped_key_length)); + + WTPI_K1_SymmetricKey_Handle out_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_UnwrapIntoKeyHandle( + context, wrapped_key, wrapped_key_length, + key_type, &out_key_handle)); + + // Perform the same crypto operation with both key handles to prove the + // unwrapped handle is the same as the wrapped one + std::vector output1(32, 1); + std::vector output2(32, 2); + std::vector input; + for (int i = 0; i < 32; i++) { + input.push_back(i); + } + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(key_handle, input.data(), input.size(), + output1.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(out_key_handle, input.data(), input.size(), + output2.data())); + + for (int i = 0; i < 32; i++) { + ASSERT_EQ(output1[i], output2[i]); + } +} + +TEST_F(CryptoTest, WrapAsymmetricKeyFailsForBadInputs) { + uint8_t output[4000]; + size_t output_length = 4000; + AsymmetricKeyType key_type = DRM_RSA_PRIVATE_KEY; + uint8_t clear_key[256]; + size_t clear_key_length = 256; + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_WrapAsymmetricKey(NULL, output_length, key_type, clear_key, + clear_key_length)); + ASSERT_EQ( + OEMCrypto_ERROR_SHORT_BUFFER, + WTPI_WrapAsymmetricKey(output, 0, key_type, clear_key, clear_key_length)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_WrapAsymmetricKey(output, output_length, key_type, NULL, + clear_key_length)); + ASSERT_EQ( + OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_WrapAsymmetricKey(output, output_length, key_type, clear_key, 0)); +} + +TEST_F(CryptoTest, UnwrapAsymmetricKeyFailsForBadInputs) { + uint8_t input[256]; + size_t input_length = 256; + AsymmetricKeyType key_type = DRM_RSA_PRIVATE_KEY; + WTPI_AsymmetricKey_Handle key_handle; + uint32_t allowed_schemes = 0; + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_UnwrapIntoAsymmetricKeyHandle(NULL, input_length, key_type, + &key_handle, &allowed_schemes)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_UnwrapIntoAsymmetricKeyHandle(input, 0, key_type, &key_handle, + &allowed_schemes)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_UnwrapIntoAsymmetricKeyHandle(input, input_length, key_type, + NULL, &allowed_schemes)); + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_UnwrapIntoAsymmetricKeyHandle(input, input_length, key_type, + &key_handle, NULL)); +} + +TEST_F(CryptoTest, WrapAndUnwrapAsymmetricKeyWorks) { + WTPI_AsymmetricKey_Handle handle; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_CreateAsymmetricKeyHandle( + test_rsa_key_der, TEST_RSA_KEY_DER_LEN, + DRM_RSA_PRIVATE_KEY, &handle)); + + size_t buffer_size = 0; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_GetWrappedAsymmetricKeySize( + TEST_RSA_KEY_DER_LEN, DRM_RSA_PRIVATE_KEY, &buffer_size)); + + std::vector wrapped(buffer_size, 0); + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_WrapAsymmetricKey(wrapped.data(), wrapped.size(), + DRM_RSA_PRIVATE_KEY, test_rsa_key_der, + TEST_RSA_KEY_DER_LEN)); + + WTPI_AsymmetricKey_Handle out_handle; + uint32_t allowed_schemes; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_UnwrapIntoAsymmetricKeyHandle(wrapped.data(), wrapped.size(), + DRM_RSA_PRIVATE_KEY, &out_handle, + &allowed_schemes)); + + // perform an operation with the two handles to prove they are the same + std::vector decrypted1(256, 0); + std::vector decrypted2(256, 0); + size_t output_len = 256; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_RSADecrypt(handle, hello_world_encrypted, HELLO_WORLD_ENC_LEN, + decrypted1.data(), &output_len)); + + output_len = 256; + ASSERT_EQ( + OEMCrypto_SUCCESS, + WTPI_RSADecrypt(out_handle, hello_world_encrypted, HELLO_WORLD_ENC_LEN, + decrypted2.data(), &output_len)); + + std::string message = "Hello world!"; + std::vector expected(message.begin(), message.end()); + for (size_t i = 0; i < expected.size(); i++) { + ASSERT_EQ(expected[i], decrypted1[i]); + ASSERT_EQ(expected[i], decrypted2[i]); + } +} + +TEST_F(CryptoTest, GetKeySizeBasic) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, CONTENT_KEY, + &key_handle)); + + KeySize size = KEY_SIZE_256; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_GetKeySize(key_handle, &size)); + ASSERT_EQ(KEY_SIZE_128, size); +} + +TEST_F(CryptoTest, GetKeySizeFailsForBadInput) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + WTPI_K1_SymmetricKey_Handle key_handle; + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, CONTENT_KEY, + &key_handle)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_GetKeySize(key_handle, NULL)); +} + +TEST_F(CryptoTest, AESDecryptAndCreateKeyHandleFailsForBadInput) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + + WTPI_K1_SymmetricKey_Handle decrypt_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_128, CONTENT_KEY, + &decrypt_key_handle)); + + std::vector enc_key = {72, 148, 193, 81, 175, 242, 38, 26, + 247, 167, 88, 96, 223, 94, 41, 95}; + std::vector iv = {99, 0, 23, 18, 75, 4, 92, 115, + 24, 70, 56, 57, 12, 43, 15, 29}; + + WTPI_K1_SymmetricKey_Handle out_key_handle; + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandle( + NULL, enc_key.data(), enc_key.size(), iv.data(), MAC_KEY_CLIENT, + &out_key_handle)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandle( + decrypt_key_handle, NULL, enc_key.size(), iv.data(), + MAC_KEY_CLIENT, &out_key_handle)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandle( + decrypt_key_handle, enc_key.data(), 7, iv.data(), + MAC_KEY_CLIENT, &out_key_handle)); + + // TODO(b/205751866): serializer allocates iv array on TEE side regardless if + // REE iv ptr is NULL, so the NULL never propagates to the TEE + // + // ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + // WTPI_K1_AESDecryptAndCreateKeyHandle( + // decrypt_key_handle, enc_key.data(), enc_key.size(), NULL, + // MAC_KEY_CLIENT, &out_key_handle)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandle( + decrypt_key_handle, enc_key.data(), enc_key.size(), iv.data(), + MAC_KEY_CLIENT, NULL)); +} + +TEST_F(CryptoTest, AESDecryptAndCreateKeyHandleBasic) { + std::vector key; + for (int i = 0; i < 32; i++) { + key.push_back(i); + } + + WTPI_K1_SymmetricKey_Handle expected_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(key.data(), KEY_SIZE_256, MAC_KEY_CLIENT, + &expected_key_handle)); + + std::vector decryption_key; + for (int i = 0; i < 32; i++) { + decryption_key.push_back(10 + i); + } + + WTPI_K1_SymmetricKey_Handle decryption_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(decryption_key.data(), KEY_SIZE_256, + CONTENT_KEY, &decryption_key_handle)); + + std::vector iv = {99, 0, 23, 18, 75, 4, 92, 115, + 24, 70, 56, 57, 12, 43, 15, 29}; + + // encrypt the `key` array using AES CBC + size_t key_size = KEY_SIZE_256; + uint8_t iv_buffer[KEY_IV_SIZE]; + std::vector encrypted_key(32, 0); + AES_KEY aes_key; + AES_set_encrypt_key(decryption_key.data(), (unsigned int)(key_size * 8), + &aes_key); + memcpy(iv_buffer, iv.data(), KEY_IV_SIZE); + AES_cbc_encrypt(key.data(), encrypted_key.data(), key.size(), &aes_key, + iv_buffer, AES_ENCRYPT); + + WTPI_K1_SymmetricKey_Handle out_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, WTPI_K1_AESDecryptAndCreateKeyHandle( + decryption_key_handle, encrypted_key.data(), + encrypted_key.size(), iv.data(), + MAC_KEY_CLIENT, &out_key_handle)); + + // perform the same operation with both keys + std::vector output1(32, 1); + std::vector output2(32, 2); + std::vector input; + for (int i = 0; i < 32; i++) { + input.push_back(i); + } + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(out_key_handle, input.data(), input.size(), + output1.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(expected_key_handle, input.data(), input.size(), + output2.data())); + + for (int i = 0; i < 32; i++) { + ASSERT_EQ(output1[i], output2[i]); + } +} + +TEST_F(CryptoTest, AESDecryptAndCreateKeyHandleForMacKeysFailsForBadInput) { + std::vector enc_mac_keys; + for (int i = 0; i < 64; i++) { + enc_mac_keys.push_back(i); + } + + std::vector decryption_key; + for (int i = 0; i < 32; i++) { + decryption_key.push_back(10 + i); + } + + WTPI_K1_SymmetricKey_Handle decryption_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(decryption_key.data(), KEY_SIZE_256, + CONTENT_KEY, &decryption_key_handle)); + + std::vector iv = {99, 0, 23, 18, 75, 4, 92, 115, + 24, 70, 56, 57, 12, 43, 15, 29}; + + WTPI_K1_SymmetricKey_Handle out_mac_key_client, out_mac_key_server; + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + NULL, enc_mac_keys.data(), enc_mac_keys.size(), iv.data(), + &out_mac_key_server, &out_mac_key_client)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + decryption_key_handle, NULL, enc_mac_keys.size(), iv.data(), + &out_mac_key_server, &out_mac_key_client)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + decryption_key_handle, enc_mac_keys.data(), 63, iv.data(), + &out_mac_key_server, &out_mac_key_client)); + + // TODO(b/205751866): serializer allocates iv array on TEE side regardless + // if REE iv ptr is NULL, so the NULL never propagates to the TEE + // + // ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + // WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + // decryption_key_handle, enc_mac_keys.data(), enc_mac_keys.size(), NULL, + // &out_mac_key_server, &out_mac_key_client)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + decryption_key_handle, enc_mac_keys.data(), enc_mac_keys.size(), + iv.data(), NULL, &out_mac_key_client)); + + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + decryption_key_handle, enc_mac_keys.data(), enc_mac_keys.size(), + iv.data(), &out_mac_key_server, NULL)); +} + +TEST_F(CryptoTest, AESDecryptAndCreateKeyHandleForMacKeysBasic) { + std::vector in_mac_key_client, in_mac_key_server; + for (int i = 0; i < 32; i++) { + in_mac_key_client.push_back(i); + in_mac_key_server.push_back(i + 50); + } + + WTPI_K1_SymmetricKey_Handle expected_mac_key_client_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(in_mac_key_client.data(), KEY_SIZE_256, + MAC_KEY_CLIENT, &expected_mac_key_client_handle)); + + WTPI_K1_SymmetricKey_Handle expected_mac_key_server_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(in_mac_key_server.data(), KEY_SIZE_256, + MAC_KEY_SERVER, &expected_mac_key_server_handle)); + + std::vector decryption_key; + for (int i = 0; i < 32; i++) { + decryption_key.push_back(10 + i); + } + + WTPI_K1_SymmetricKey_Handle decryption_key_handle; + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_K1_CreateKeyHandle(decryption_key.data(), KEY_SIZE_256, + CONTENT_KEY, &decryption_key_handle)); + + std::vector iv = {99, 0, 23, 18, 75, 4, 92, 115, + 24, 70, 56, 57, 12, 43, 15, 29}; + + // encrypt the mac keys using AES CBC + size_t key_size = KEY_SIZE_256; + uint8_t iv_buffer[KEY_IV_SIZE]; + std::vector enc_mac_keys(64, 0); + AES_KEY aes_key; + AES_set_encrypt_key(decryption_key.data(), (unsigned int)(key_size * 8), + &aes_key); + memcpy(iv_buffer, iv.data(), KEY_IV_SIZE); + AES_cbc_encrypt(in_mac_key_server.data(), enc_mac_keys.data(), + in_mac_key_server.size(), &aes_key, iv_buffer, AES_ENCRYPT); + AES_cbc_encrypt(in_mac_key_client.data(), enc_mac_keys.data() + 32, + in_mac_key_client.size(), &aes_key, iv_buffer, AES_ENCRYPT); + + WTPI_K1_SymmetricKey_Handle out_mac_key_client_handle, + out_mac_key_server_handle; + ASSERT_EQ( + OEMCrypto_SUCCESS, + WTPI_K1_AESDecryptAndCreateKeyHandleForMacKeys( + decryption_key_handle, enc_mac_keys.data(), enc_mac_keys.size(), + iv.data(), &out_mac_key_server_handle, &out_mac_key_client_handle)); + + // perform the same operation with both keys, check that the output is the + // same + std::vector output1(32, 1); + std::vector output2(32, 2); + std::vector output3(32, 3); + std::vector output4(32, 4); + std::vector input; + for (int i = 0; i < 32; i++) { + input.push_back(i); + } + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(out_mac_key_client_handle, input.data(), + input.size(), output1.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(expected_mac_key_client_handle, input.data(), + input.size(), output2.data())); + + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(out_mac_key_server_handle, input.data(), + input.size(), output3.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + WTPI_C1_HMAC_SHA256(expected_mac_key_server_handle, input.data(), + input.size(), output4.data())); + + for (int i = 0; i < 32; i++) { + ASSERT_EQ(output1[i], output2[i]); + ASSERT_EQ(output3[i], output4[i]); + } +} + +TEST_F(CryptoTest, DeriveDeviceKeyIntoHandleFailsForBadInput) { + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + WTPI_K1_DeriveDeviceKeyIntoHandle(0x1234, CONTENT_KEY, NULL, + KEY_SIZE_128)); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/generation_number_interface_test.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/generation_number_interface_test.cpp index 3eeca9d..33fea6d 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/generation_number_interface_test.cpp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/generation_number_interface_test.cpp @@ -18,7 +18,7 @@ class GenerationNumberInterfaceTest : public ::testing::Test { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); - OPK_Initialize(); + ASSERT_EQ(true, OPK_Initialize()); } void TearDown() override { diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c index 6310b47..f436059 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_oemcrypto_tee_test_api.c @@ -803,6 +803,38 @@ cleanup_and_return: return result; } +OEMCryptoResult WTPI_WrapAsymmetricKey(uint8_t* output, size_t output_length, + AsymmetricKeyType key_type, + const uint8_t* clear_key, + size_t clear_key_length) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_WrapAsymmetricKey_Request(output, output_length, key_type, + clear_key, clear_key_length); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_WrapAsymmetricKey_Response(&response, &result, &output, + &output_length); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + OEMCryptoResult WTPI_RSASign(WTPI_AsymmetricKey_Handle key, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, @@ -1042,3 +1074,110 @@ cleanup_and_return: pthread_mutex_unlock(&api_lock); return result; } + +OEMCryptoResult WTPI_GetTrustedTime(uint64_t* time_in_s) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_GetTrustedTime_Request(time_in_s); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetTrustedTime_Response(&response, &result, &time_in_s); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCryptoResult WTPI_InitializeClock(void) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_InitializeClock_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_InitializeClock_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCryptoResult WTPI_TerminateClock(void) { + pthread_mutex_lock(&api_lock); + OEMCryptoResult result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_TerminateClock_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_TerminateClock_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + result = API_CheckResult(result); + pthread_mutex_unlock(&api_lock); + return result; +} + +OEMCrypto_Clock_Security_Level WTPI_GetClockType(void) { + pthread_mutex_lock(&api_lock); + OEMCrypto_Clock_Security_Level result = kInsecureClock; + ODK_Message request = ODK_Message_Create(NULL, 0); + ODK_Message response = ODK_Message_Create(NULL, 0); + API_Initialize(); + request = OPK_Pack_GetClockType_Request(); + if (ODK_Message_GetStatus(&request) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup_and_return; + } + response = API_Transact(&request); + OPK_Unpack_GetClockType_Response(&response, &result); + + if (ODK_Message_GetStatus(&response) != MESSAGE_STATUS_OK) { + api_result = OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +cleanup_and_return: + TOS_Transport_ReleaseMessage(&request); + TOS_Transport_ReleaseMessage(&response); + + API_Terminate(); + pthread_mutex_unlock(&api_lock); + return result; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c index 5a45cd4..0ca78ed 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.c @@ -835,13 +835,60 @@ void OPK_Unpack_GetWrappedAsymmetricKeySize_Response(ODK_Message* msg, } } +ODK_Message OPK_Pack_WrapAsymmetricKey_Request(const uint8_t* output, + size_t output_length, + AsymmetricKeyType key_type, + const uint8_t* clear_key, + size_t clear_key_length) { + uint32_t api_value = 10026; /* from _tee10026 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_Pack_size_t(&msg, &output_length); + OPK_Pack_size_t(&msg, &clear_key_length); + OPK_PackAlloc(&msg, output); + OPK_Pack_AsymmetricKeyType(&msg, &key_type); + OPK_PackMemory(&msg, clear_key, OPK_ToLengthType(clear_key_length)); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_WrapAsymmetricKey_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** output, + size_t* output_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10026) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_size_t(msg, output_length); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + if (SuccessResult(*result)) { + uint8_t* p; + OPK_UnpackInPlace(msg, &p, OPK_FromSizeTPtr(output_length)); + if (p && *output) { + memcpy(*output, p, OPK_SafeDerefSizeTPtr(output_length)); + } + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + ODK_Message OPK_Pack_RSASign_Request(WTPI_AsymmetricKey_Handle key, const uint8_t* message, size_t message_length, const uint8_t* signature, const size_t* signature_length, RSA_Padding_Scheme padding_scheme) { - uint32_t api_value = 10026; /* from _tee10026 */ + uint32_t api_value = 10027; /* from _tee10027 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -862,7 +909,7 @@ void OPK_Unpack_RSASign_Response(ODK_Message* msg, OEMCryptoResult* result, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10026) + if (api_value != 10027) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, signature_length); OPK_Unpack_uint32_t(msg, result); @@ -887,7 +934,7 @@ ODK_Message OPK_Pack_RSADecrypt_Request(WTPI_AsymmetricKey_Handle key, const uint8_t* input, size_t input_length, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10027; /* from _tee10027 */ + uint32_t api_value = 10028; /* from _tee10028 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -906,7 +953,7 @@ void OPK_Unpack_RSADecrypt_Response(ODK_Message* msg, OEMCryptoResult* result, uint8_t** out, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10027) + if (api_value != 10028) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, out_length); OPK_Unpack_uint32_t(msg, result); @@ -932,7 +979,7 @@ ODK_Message OPK_Pack_ECCSign_Request(WTPI_AsymmetricKey_Handle key, size_t message_length, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10028; /* from _tee10028 */ + uint32_t api_value = 10029; /* from _tee10029 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -952,7 +999,7 @@ void OPK_Unpack_ECCSign_Response(ODK_Message* msg, OEMCryptoResult* result, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10028) + if (api_value != 10029) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, signature_length); OPK_Unpack_uint32_t(msg, result); @@ -977,7 +1024,7 @@ ODK_Message OPK_Pack_ECCDeriveSessionKey_Request( WTPI_AsymmetricKey_Handle key, const uint8_t* key_source, size_t key_source_length, const uint8_t* session_key, const size_t* session_key_length) { - uint32_t api_value = 10029; /* from _tee10029 */ + uint32_t api_value = 10030; /* from _tee10030 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -998,7 +1045,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Response(ODK_Message* msg, size_t** session_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10029) + if (api_value != 10030) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_UnpackNullable_size_t(msg, session_key_length); OPK_Unpack_uint32_t(msg, result); @@ -1021,7 +1068,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Response(ODK_Message* msg, ODK_Message OPK_Pack_GetSignatureSize_Request(WTPI_AsymmetricKey_Handle key, const size_t* signature_length) { - uint32_t api_value = 10030; /* from _tee10030 */ + uint32_t api_value = 10031; /* from _tee10031 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1038,7 +1085,7 @@ void OPK_Unpack_GetSignatureSize_Response(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10030) + if (api_value != 10031) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1053,7 +1100,7 @@ void OPK_Unpack_GetSignatureSize_Response(ODK_Message* msg, } ODK_Message OPK_Pack_Crc32Init_Request(const uint32_t* initial_hash) { - uint32_t api_value = 10031; /* from _tee10031 */ + uint32_t api_value = 10032; /* from _tee10032 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1068,7 +1115,7 @@ void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** initial_hash) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10031) + if (api_value != 10032) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1085,7 +1132,7 @@ void OPK_Unpack_Crc32Init_Response(ODK_Message* msg, OEMCryptoResult* result, ODK_Message OPK_Pack_Crc32Cont_Request(const uint8_t* in, size_t in_length, uint32_t prev_crc, const uint32_t* new_crc) { - uint32_t api_value = 10032; /* from _tee10032 */ + uint32_t api_value = 10033; /* from _tee10033 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1103,7 +1150,7 @@ void OPK_Unpack_Crc32Cont_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10032) + if (api_value != 10033) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1122,7 +1169,7 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Request(const OPK_OutputBuffer* in, size_t in_length, uint32_t prev_crc, const uint32_t* new_crc) { - uint32_t api_value = 10033; /* from _tee10033 */ + uint32_t api_value = 10034; /* from _tee10034 */ ODK_Message msg = TOS_Transport_GetRequest(); OPK_Pack_uint32_t(&msg, &api_value); uint64_t timestamp = time(0); @@ -1153,7 +1200,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10033) + if (api_value != 10034) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); OPK_Unpack_uint32_t(msg, result); if (!Is_Valid_OEMCryptoResult(*result)) { @@ -1166,3 +1213,112 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg, OPK_SharedBuffer_FinalizeUnpacking(); } } + +ODK_Message OPK_Pack_GetTrustedTime_Request(const uint64_t* time_in_s) { + uint32_t api_value = 10035; /* from _tee10035 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackIsNull(&msg, time_in_s); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetTrustedTime_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint64_t** time_in_s) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10035) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackNullable_uint64_t(msg, time_in_s); + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_InitializeClock_Request(void) { + uint32_t api_value = 10036; /* from _tee10036 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_InitializeClock_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10036) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_TerminateClock_Request(void) { + uint32_t api_value = 10037; /* from _tee10037 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, + OEMCryptoResult* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10037) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_uint32_t(msg, result); + if (!Is_Valid_OEMCryptoResult(*result)) { + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_INVALID_ENUM_VALUE); + } + OPK_UnpackEOM(msg); + + if (SuccessResult(*result)) { + OPK_SharedBuffer_FinalizeUnpacking(); + } +} + +ODK_Message OPK_Pack_GetClockType_Request(void) { + uint32_t api_value = 10038; /* from _tee10038 */ + ODK_Message msg = TOS_Transport_GetRequest(); + OPK_Pack_uint32_t(&msg, &api_value); + uint64_t timestamp = time(0); + OPK_Pack_uint64_t(&msg, ×tamp); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetClockType_Response(ODK_Message* msg, + OEMCrypto_Clock_Security_Level* result) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10038) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + OPK_Unpack_OEMCrypto_Clock_Security_Level(msg, result); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h index b3f4fa0..e9a4283 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/GEN_ree_serializer.h @@ -146,6 +146,15 @@ ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Request( void OPK_Unpack_GetWrappedAsymmetricKeySize_Response(ODK_Message* msg, OEMCryptoResult* result, size_t** buffer_size); +ODK_Message OPK_Pack_WrapAsymmetricKey_Request(const uint8_t* output, + size_t output_length, + AsymmetricKeyType key_type, + const uint8_t* clear_key, + size_t clear_key_length); +void OPK_Unpack_WrapAsymmetricKey_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint8_t** output, + size_t* output_length); ODK_Message OPK_Pack_RSASign_Request(WTPI_AsymmetricKey_Handle key, const uint8_t* message, size_t message_length, @@ -198,6 +207,19 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Request(const OPK_OutputBuffer* in, void OPK_Unpack_Crc32Cont_OutputBuffer_Response(ODK_Message* msg, OEMCryptoResult* result, uint32_t** new_crc); +ODK_Message OPK_Pack_GetTrustedTime_Request(const uint64_t* time_in_s); +void OPK_Unpack_GetTrustedTime_Response(ODK_Message* msg, + OEMCryptoResult* result, + uint64_t** time_in_s); +ODK_Message OPK_Pack_InitializeClock_Request(void); +void OPK_Unpack_InitializeClock_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_TerminateClock_Request(void); +void OPK_Unpack_TerminateClock_Response(ODK_Message* msg, + OEMCryptoResult* result); +ODK_Message OPK_Pack_GetClockType_Request(void); +void OPK_Unpack_GetClockType_Response(ODK_Message* msg, + OEMCrypto_Clock_Security_Level* result); #ifdef __cplusplus } // extern "C" #endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp new file mode 100644 index 0000000..cdf50e9 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.cpp @@ -0,0 +1,103 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include "ssl_util.h" +#include "log.h" + +void dump_ssl_error(void) { + int count = 0; + unsigned long err; + while ((err = ERR_get_error())) { + count++; + char buffer[120]; + ERR_error_string_n((int)err, buffer, sizeof(buffer)); + LOGE("SSL Error %d -- %lu -- %s", count, err, buffer); + } +} + +bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size, + RSA** rsa) { + BIO* bio = BIO_new_mem_buf(serialized_bytes, (int)size); + if (bio == NULL) { + LOGE("Could not allocate bio buffer"); + return false; + } + bool success = false; + EVP_PKEY* evp = NULL; + PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); + if (pkcs8_pki == NULL) { + LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL"); + goto cleanup; + } + evp = EVP_PKCS82PKEY(pkcs8_pki); + if (evp == NULL) { + LOGE("EVP_PKCS82PKEY returned NULL"); + goto cleanup; + } + *rsa = EVP_PKEY_get1_RSA(evp); + if (*rsa == NULL) { + LOGE("PrivateKeyInfo did not contain an RSA key"); + goto cleanup; + } + success = true; + +cleanup: + dump_ssl_error(); + if (evp != NULL) { + EVP_PKEY_free(evp); + } + if (pkcs8_pki != NULL) { + PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); + } + BIO_free(bio); + return success; +} + +bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, + size_t message_length, const uint8_t* signature, + size_t signature_length) { + boringssl_ptr md_ctx(EVP_MD_CTX_new()); + EVP_PKEY_CTX* pkey_ctx = nullptr; + + if (EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, EVP_sha1(), + nullptr /* no ENGINE */, pkey) != 1) { + LOGE("EVP_DigestVerifyInit failed in VerifyPSSSignature"); + goto err; + } + + if (EVP_PKEY_CTX_set_signature_md(pkey_ctx, + const_cast(EVP_sha1())) != 1) { + LOGE("EVP_PKEY_CTX_set_signature_md failed in VerifyPSSSignature"); + goto err; + } + + if (EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1) { + LOGE("EVP_PKEY_CTX_set_rsa_padding failed in VerifyPSSSignature"); + goto err; + } + + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, SHA_DIGEST_LENGTH) != 1) { + LOGE("EVP_PKEY_CTX_set_rsa_pss_saltlen failed in VerifyPSSSignature"); + goto err; + } + + if (EVP_DigestVerifyUpdate(md_ctx.get(), message, message_length) != 1) { + LOGE("EVP_DigestVerifyUpdate failed in VerifyPSSSignature"); + goto err; + } + + if (EVP_DigestVerifyFinal(md_ctx.get(), const_cast(signature), + signature_length) != 1) { + LOGE( + "EVP_DigestVerifyFinal failed in VerifyPSSSignature. (Probably a bad " + "signature.)"); + goto err; + } + + return true; + +err: + dump_ssl_error(); + return false; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.h new file mode 100644 index 0000000..2add519 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/ssl_util.h @@ -0,0 +1,37 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include "openssl/aes.h" +#include "openssl/bio.h" +#include "openssl/err.h" +#include "openssl/rsa.h" +#include "openssl/sha.h" +#include "openssl/x509.h" + +// A smart pointer for BoringSSL objects. It uses the specified free function +// to release resources and free memory when the pointer is deleted. +template +class boringssl_ptr { + public: + explicit boringssl_ptr(T* p = nullptr) : ptr_(p) {} + boringssl_ptr(const boringssl_ptr& ptr) = delete; + + ~boringssl_ptr() { + if (ptr_) func(ptr_); + } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + bool NotNull() const { return ptr_ != nullptr; } + + private: + T* ptr_; +}; + +bool DeserializePKCS8PrivateKey(const uint8_t* serialized_bytes, size_t size, + RSA** rsa); +bool VerifyPSSSignature(EVP_PKEY* pkey, const uint8_t* message, + size_t message_length, const uint8_t* signature, + size_t signature_length); diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c index d0e40a9..493be03 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_dispatcher.c @@ -23,6 +23,7 @@ #include "tee_special_cases.h" #include "tos_shared_memory_interface.h" #include "tos_transport_interface.h" +#include "wtpi_clock_interface_layer1.h" #include "wtpi_generation_number_interface.h" static ODK_Message CreateEmptyMessage(void) { @@ -586,7 +587,32 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_GetWrappedAsymmetricKeySize_Response(result, buffer_size); break; } - case 10026: /* WTPI_RSASign */ + case 10026: /* WTPI_WrapAsymmetricKey */ + { + size_t output_length; + OPK_Init_size_t((size_t*)&output_length); + size_t clear_key_length; + OPK_Init_size_t((size_t*)&clear_key_length); + uint8_t* output; + OPK_InitPointer((uint8_t**)&output); + AsymmetricKeyType key_type; + OPK_Init_AsymmetricKeyType((AsymmetricKeyType*)&key_type); + uint8_t* clear_key; + OPK_InitPointer((uint8_t**)&clear_key); + OPK_Unpack_WrapAsymmetricKey_Request(request, &output, &output_length, + &key_type, &clear_key, + &clear_key_length); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("WrapAsymmetricKey"); + result = WTPI_WrapAsymmetricKey(output, output_length, key_type, + clear_key, clear_key_length); + *response = + OPK_Pack_WrapAsymmetricKey_Response(result, output, output_length); + break; + } + case 10027: /* WTPI_RSASign */ { size_t message_length; OPK_Init_size_t((size_t*)&message_length); @@ -613,7 +639,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_RSASign_Response(result, signature, signature_length); break; } - case 10027: /* WTPI_RSADecrypt */ + case 10028: /* WTPI_RSADecrypt */ { size_t input_length; OPK_Init_size_t((size_t*)&input_length); @@ -635,7 +661,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_RSADecrypt_Response(result, out, out_length); break; } - case 10028: /* WTPI_ECCSign */ + case 10029: /* WTPI_ECCSign */ { size_t message_length; OPK_Init_size_t((size_t*)&message_length); @@ -659,7 +685,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, OPK_Pack_ECCSign_Response(result, signature, signature_length); break; } - case 10029: /* WTPI_ECCDeriveSessionKey */ + case 10030: /* WTPI_ECCDeriveSessionKey */ { size_t key_source_length; OPK_Init_size_t((size_t*)&key_source_length); @@ -684,7 +710,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, session_key_length); break; } - case 10030: /* WTPI_GetSignatureSize */ + case 10031: /* WTPI_GetSignatureSize */ { WTPI_AsymmetricKey_Handle key; OPK_Init_WTPI_AsymmetricKey_Handle((WTPI_AsymmetricKey_Handle*)&key); @@ -699,7 +725,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_GetSignatureSize_Response(result, signature_length); break; } - case 10031: /* WTPI_Crc32Init */ + case 10032: /* WTPI_Crc32Init */ { uint32_t* initial_hash; OPK_InitPointer((uint8_t**)&initial_hash); @@ -712,7 +738,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Init_Response(result, initial_hash); break; } - case 10032: /* WTPI_Crc32Cont */ + case 10033: /* WTPI_Crc32Cont */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -732,7 +758,7 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_Response(result, new_crc); break; } - case 10033: /* WTPI_Crc32Cont_OutputBuffer */ + case 10034: /* WTPI_Crc32Cont_OutputBuffer */ { size_t in_length; OPK_Init_size_t((size_t*)&in_length); @@ -755,6 +781,53 @@ ODK_MessageStatus OPK_DispatchMessage(ODK_Message* request, *response = OPK_Pack_Crc32Cont_OutputBuffer_Response(result, new_crc); break; } + case 10035: /* WTPI_GetTrustedTime */ + { + uint64_t* time_in_s; + OPK_InitPointer((uint8_t**)&time_in_s); + OPK_Unpack_GetTrustedTime_Request(request, &time_in_s); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("GetTrustedTime"); + result = WTPI_GetTrustedTime(time_in_s); + *response = OPK_Pack_GetTrustedTime_Response(result, time_in_s); + break; + } + case 10036: /* WTPI_InitializeClock */ + { + OPK_Unpack_InitializeClock_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("InitializeClock"); + result = WTPI_InitializeClock(); + *response = OPK_Pack_InitializeClock_Response(result); + break; + } + case 10037: /* WTPI_TerminateClock */ + { + OPK_Unpack_TerminateClock_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCryptoResult result; + OPK_Init_uint32_t((uint32_t*)&result); + LOGD("TerminateClock"); + result = WTPI_TerminateClock(); + *response = OPK_Pack_TerminateClock_Response(result); + break; + } + case 10038: /* WTPI_GetClockType */ + { + OPK_Unpack_GetClockType_Request(request); + if (!ODK_Message_IsValid(request)) goto handle_invalid_request; + OEMCrypto_Clock_Security_Level result; + OPK_Init_OEMCrypto_Clock_Security_Level( + (OEMCrypto_Clock_Security_Level*)&result); + LOGD("GetClockType"); + result = WTPI_GetClockType(); + *response = OPK_Pack_GetClockType_Response(result); + break; + } default: return MESSAGE_STATUS_API_VALUE_ERROR; } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c index 880a388..72ef87c 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.c @@ -680,6 +680,43 @@ ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Response( return msg; } +void OPK_Unpack_WrapAsymmetricKey_Request(ODK_Message* msg, uint8_t** output, + size_t* output_length, + AsymmetricKeyType* key_type, + uint8_t** clear_key, + size_t* clear_key_length) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10026) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_Unpack_size_t(msg, output_length); + OPK_Unpack_size_t(msg, clear_key_length); + *output = (uint8_t*)OPK_UnpackAllocBuffer( + msg, OPK_FromSizeTPtr(output_length), sizeof(uint8_t)); + OPK_Unpack_AsymmetricKeyType(msg, key_type); + OPK_UnpackInPlace(msg, clear_key, OPK_FromSizeTPtr(clear_key_length)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_WrapAsymmetricKey_Response(OEMCryptoResult result, + const uint8_t* output, + size_t output_length) { + uint32_t api_value = 10026; /* from _tee10026 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_size_t(&msg, &output_length); + OPK_Pack_uint32_t(&msg, &result); + if (SuccessResult(result)) { + OPK_PackMemory(&msg, output, OPK_ToLengthType(output_length)); + } + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + void OPK_Unpack_RSASign_Request(ODK_Message* msg, WTPI_AsymmetricKey_Handle* key, uint8_t** message, size_t* message_length, @@ -687,7 +724,7 @@ void OPK_Unpack_RSASign_Request(ODK_Message* msg, RSA_Padding_Scheme* padding_scheme) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10026) + if (api_value != 10027) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -705,7 +742,7 @@ void OPK_Unpack_RSASign_Request(ODK_Message* msg, ODK_Message OPK_Pack_RSASign_Response(OEMCryptoResult result, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10026; /* from _tee10026 */ + uint32_t api_value = 10027; /* from _tee10027 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, signature_length); @@ -724,7 +761,7 @@ void OPK_Unpack_RSADecrypt_Request(ODK_Message* msg, uint8_t** out, size_t** out_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10027) + if (api_value != 10028) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -741,7 +778,7 @@ void OPK_Unpack_RSADecrypt_Request(ODK_Message* msg, ODK_Message OPK_Pack_RSADecrypt_Response(OEMCryptoResult result, const uint8_t* out, const size_t* out_length) { - uint32_t api_value = 10027; /* from _tee10027 */ + uint32_t api_value = 10028; /* from _tee10028 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, out_length); @@ -761,7 +798,7 @@ void OPK_Unpack_ECCSign_Request(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10028) + if (api_value != 10029) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -778,7 +815,7 @@ void OPK_Unpack_ECCSign_Request(ODK_Message* msg, ODK_Message OPK_Pack_ECCSign_Response(OEMCryptoResult result, const uint8_t* signature, const size_t* signature_length) { - uint32_t api_value = 10028; /* from _tee10028 */ + uint32_t api_value = 10029; /* from _tee10029 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, signature_length); @@ -799,7 +836,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Request(ODK_Message* msg, size_t** session_key_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10029) + if (api_value != 10030) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -816,7 +853,7 @@ void OPK_Unpack_ECCDeriveSessionKey_Request(ODK_Message* msg, ODK_Message OPK_Pack_ECCDeriveSessionKey_Response( OEMCryptoResult result, const uint8_t* session_key, const size_t* session_key_length) { - uint32_t api_value = 10029; /* from _tee10029 */ + uint32_t api_value = 10030; /* from _tee10030 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_PackNullable_size_t(&msg, session_key_length); @@ -834,7 +871,7 @@ void OPK_Unpack_GetSignatureSize_Request(ODK_Message* msg, size_t** signature_length) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10030) + if (api_value != 10031) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -846,7 +883,7 @@ void OPK_Unpack_GetSignatureSize_Request(ODK_Message* msg, ODK_Message OPK_Pack_GetSignatureSize_Response(OEMCryptoResult result, const size_t* signature_length) { - uint32_t api_value = 10030; /* from _tee10030 */ + uint32_t api_value = 10031; /* from _tee10031 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -859,7 +896,7 @@ ODK_Message OPK_Pack_GetSignatureSize_Response(OEMCryptoResult result, void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10031) + if (api_value != 10032) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -870,7 +907,7 @@ void OPK_Unpack_Crc32Init_Request(ODK_Message* msg, uint32_t** initial_hash) { ODK_Message OPK_Pack_Crc32Init_Response(OEMCryptoResult result, const uint32_t* initial_hash) { - uint32_t api_value = 10031; /* from _tee10031 */ + uint32_t api_value = 10032; /* from _tee10032 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -885,7 +922,7 @@ void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10032) + if (api_value != 10033) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -899,7 +936,7 @@ void OPK_Unpack_Crc32Cont_Request(ODK_Message* msg, uint8_t** in, ODK_Message OPK_Pack_Crc32Cont_Response(OEMCryptoResult result, const uint32_t* new_crc) { - uint32_t api_value = 10032; /* from _tee10032 */ + uint32_t api_value = 10033; /* from _tee10033 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -914,7 +951,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( size_t* in_length, uint32_t* prev_crc, uint32_t** new_crc) { uint32_t api_value = UINT32_MAX; OPK_Unpack_uint32_t(msg, &api_value); - if (api_value != 10033) + if (api_value != 10034) ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); uint64_t timestamp; OPK_Unpack_uint64_t(msg, ×tamp); @@ -954,7 +991,7 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result, const uint32_t* new_crc) { - uint32_t api_value = 10033; /* from _tee10033 */ + uint32_t api_value = 10034; /* from _tee10034 */ ODK_Message msg = TOS_Transport_GetResponse(); OPK_Pack_uint32_t(&msg, &api_value); OPK_Pack_uint32_t(&msg, &result); @@ -963,3 +1000,91 @@ ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result, OPK_SharedBuffer_FinalizePacking(); return msg; } + +void OPK_Unpack_GetTrustedTime_Request(ODK_Message* msg, uint64_t** time_in_s) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10035) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + *time_in_s = (uint64_t*)OPK_UnpackAlloc(msg, sizeof(uint64_t)); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetTrustedTime_Response(OEMCryptoResult result, + const uint64_t* time_in_s) { + uint32_t api_value = 10035; /* from _tee10035 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackNullable_uint64_t(&msg, time_in_s); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_InitializeClock_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10036) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_InitializeClock_Response(OEMCryptoResult result) { + uint32_t api_value = 10036; /* from _tee10036 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_TerminateClock_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10037) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result) { + uint32_t api_value = 10037; /* from _tee10037 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_uint32_t(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} + +void OPK_Unpack_GetClockType_Request(ODK_Message* msg) { + uint32_t api_value = UINT32_MAX; + OPK_Unpack_uint32_t(msg, &api_value); + if (api_value != 10038) + ODK_MESSAGE_SETSTATUS(msg, MESSAGE_STATUS_API_VALUE_ERROR); + uint64_t timestamp; + OPK_Unpack_uint64_t(msg, ×tamp); + OPK_UnpackEOM(msg); + OPK_SharedBuffer_FinalizeUnpacking(); +} + +ODK_Message OPK_Pack_GetClockType_Response( + OEMCrypto_Clock_Security_Level result) { + uint32_t api_value = 10038; /* from _tee10038 */ + ODK_Message msg = TOS_Transport_GetResponse(); + OPK_Pack_uint32_t(&msg, &api_value); + OPK_Pack_OEMCrypto_Clock_Security_Level(&msg, &result); + OPK_PackEOM(&msg); + OPK_SharedBuffer_FinalizePacking(); + return msg; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h index 5bf0eb5..41d31e4 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/GEN_tee_serializer.h @@ -131,6 +131,14 @@ void OPK_Unpack_GetWrappedAsymmetricKeySize_Request( AsymmetricKeyType* key_type, size_t** buffer_size); ODK_Message OPK_Pack_GetWrappedAsymmetricKeySize_Response( OEMCryptoResult result, const size_t* buffer_size); +void OPK_Unpack_WrapAsymmetricKey_Request(ODK_Message* msg, uint8_t** output, + size_t* output_length, + AsymmetricKeyType* key_type, + uint8_t** clear_key, + size_t* clear_key_length); +ODK_Message OPK_Pack_WrapAsymmetricKey_Response(OEMCryptoResult result, + const uint8_t* output, + size_t output_length); void OPK_Unpack_RSASign_Request(ODK_Message* msg, WTPI_AsymmetricKey_Handle* key, uint8_t** message, size_t* message_length, @@ -180,6 +188,16 @@ void OPK_Unpack_Crc32Cont_OutputBuffer_Request( size_t* in_length, uint32_t* prev_crc, uint32_t** new_crc); ODK_Message OPK_Pack_Crc32Cont_OutputBuffer_Response(OEMCryptoResult result, const uint32_t* new_crc); +void OPK_Unpack_GetTrustedTime_Request(ODK_Message* msg, uint64_t** time_in_s); +ODK_Message OPK_Pack_GetTrustedTime_Response(OEMCryptoResult result, + const uint64_t* time_in_s); +void OPK_Unpack_InitializeClock_Request(ODK_Message* msg); +ODK_Message OPK_Pack_InitializeClock_Response(OEMCryptoResult result); +void OPK_Unpack_TerminateClock_Request(ODK_Message* msg); +ODK_Message OPK_Pack_TerminateClock_Response(OEMCryptoResult result); +void OPK_Unpack_GetClockType_Request(ODK_Message* msg); +ODK_Message OPK_Pack_GetClockType_Response( + OEMCrypto_Clock_Security_Level result); #ifdef __cplusplus } // extern "C" #endif diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c index 733e97a..67ba929 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.c @@ -69,6 +69,13 @@ void OPK_Init_KeySize(KeySize* obj) { } } +void OPK_Init_OEMCrypto_Clock_Security_Level( + OEMCrypto_Clock_Security_Level* obj) { + if (obj) { + memset(obj, 0, sizeof(OEMCrypto_Clock_Security_Level)); + } +} + void OPK_Unpack_WTPI_K1_SymmetricKey_Handle(ODK_Message* message, WTPI_K1_SymmetricKey_Handle* value); void OPK_Unpack_C1_HMAC_SHA256_Verify_Request(ODK_Message* msg, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h index eecec08..040351e 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee/tee_special_cases.h @@ -19,6 +19,8 @@ void OPK_Init_AsymmetricKeyType(AsymmetricKeyType* obj); void OPK_Init_WTPI_AsymmetricKey_Handle(WTPI_AsymmetricKey_Handle* obj); void OPK_Init_RSA_Padding_Scheme(RSA_Padding_Scheme* obj); void OPK_Init_KeySize(KeySize* obj); +void OPK_Init_OEMCrypto_Clock_Security_Level( + OEMCrypto_Clock_Security_Level* obj); void OPK_Unpack_C1_HMAC_SHA256_Verify_Request(ODK_Message* msg, WTPI_K1_SymmetricKey_Handle* key, uint8_t** message, diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp b/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp index 435bd35..0063652 100644 --- a/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test.gyp @@ -5,6 +5,10 @@ 'variables': { 'platform_specific_dir': '<(DEPTH)/linux/src', 'opk_ree': 'ree/ree.gyp:opk_ree', + 'privacy_crypto_impl': 'boringssl', + 'boringssl_libcrypto_path': '<(third_party_dir)/boringssl/boringssl.gyp:crypto', + 'boringssl_libssl_path': '<(third_party_dir)/boringssl/boringssl.gyp:ssl', + 'use_linux_tos_impl%': 'false', }, 'target_defaults': { 'include_dirs': [ @@ -23,7 +27,6 @@ 'wtpi_test_main.cpp', ], 'dependencies': [ - '<(opk_ree)', '<(third_party_dir)/googletest.gyp:gtest', 'wtpi_test_lib', ], @@ -33,6 +36,13 @@ 'libwtpi_test_lib.a', '-Wl,--no-whole-archive', ], + 'conditions': [ + ['use_linux_tos_impl=="true"', { + 'dependencies': [ + '<(opk_ree)', + ], + }], + ], }, { 'target_name': 'wtpi_test_lib', @@ -40,11 +50,16 @@ 'toolsets': ['target'], 'standalone_static_library': 1, 'sources': [ - 'generation_number_interface_test.cpp', + 'clock_interface_test.cpp', 'crypto_test.cpp', + 'generation_number_interface_test.cpp', + 'ssl_util.cpp', 'test_rsa_key.cpp', '<(DEPTH)/linux/src/log.cpp', ], + 'includes': [ + '../../../../util/libcrypto_dependency.gypi', + ], }, ] } diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/README.md b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/README.md new file mode 100644 index 0000000..44d31bf --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/README.md @@ -0,0 +1,4 @@ +The files in this directory implement some of the WTPI functions required by +the OEMCrypto TA. These implementations will pass unit tests, but they are not +useful for production. To emphasize this, we have named this directory +"useless". Partners should NOT include this code for production builds. diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_device_key_access.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_device_key_access.c new file mode 100644 index 0000000..e3ec0ab --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_device_key_access.c @@ -0,0 +1,32 @@ +/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_device_key_access_interface.h" + +#include +#include + +#include "wtpi_crypto_and_key_management_interface_layer1.h" + +/* This implementation generates a new device key on reboot. This is good enough + * to pass the unit tests but won't work for an actual device, since the device + * key needs to be constant across reboots. You should replace this file with an + * implementation that accesses a real device-unique secret on your device, + * preferably a key derived from your device's actual device-unique key. + */ + +static bool device_key_initialized; +static uint8_t fake_device_key[KEY_SIZE_128]; + +const uint8_t* WTPI_GetDeviceKey(void) { + if (!device_key_initialized) { + WTPI_C1_RandomBytes(fake_device_key, sizeof(fake_device_key)); + device_key_initialized = true; + } + return fake_device_key; +} + +KeySize WTPI_GetDeviceKeySize(void) { + return (KeySize)(sizeof(fake_device_key)); +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_root_of_trust_layer2.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_root_of_trust_layer2.c new file mode 100644 index 0000000..fb211a3 --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_root_of_trust_layer2.c @@ -0,0 +1,46 @@ +/* Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine + License Agreement. */ + +#include "wtpi_root_of_trust_interface_layer2.h" + +#include +#include + +#include "wtpi_config_interface.h" +#include "wtpi_crypto_and_key_management_interface_layer1.h" +#include "wtpi_logging_interface.h" + +// In practice, ROT_SIZE is the size of a keybox. +#define MAX_ROT_SIZE 1000 +static size_t gBufferSize = 0; +static uint8_t gBuffer[MAX_ROT_SIZE]; + +OEMCryptoResult WTPI_UnwrapRootOfTrust(const uint8_t* input, + size_t input_length, uint8_t* output, + size_t* output_length) { + if (input == NULL || output == NULL || output_length == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (input_length > *output_length) { + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *output_length = input_length; + memcpy(output, input, *output_length); // TODO: decrypt using system key. + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_SaveRootOfTrust(const uint8_t* input, size_t length) { + if (length > MAX_ROT_SIZE) return OEMCrypto_ERROR_INVALID_CONTEXT; + gBufferSize = length; + memcpy(&gBuffer, input, length); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WTPI_LoadRootOfTrust(uint8_t* output, size_t* length) { + if (length == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; + if (*length < gBufferSize) return OEMCrypto_ERROR_SHORT_BUFFER; + *length = gBufferSize; + memcpy(output, gBuffer, gBufferSize); + return OEMCrypto_SUCCESS; +} diff --git a/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c new file mode 100644 index 0000000..a9cc59b --- /dev/null +++ b/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.c @@ -0,0 +1,14 @@ +/* Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary + source code may only be used and distributed under the Widevine License + Agreement. */ + +#include "wtpi_secure_buffer_access_interface.h" + +/* Secure buffers are not supported by the test build. */ +OEMCryptoResult WTPI_GetSecureBufferAddress(void* secure, size_t offset, + uint8_t** out_addr) { + if (secure == NULL || out_addr == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} diff --git a/oemcrypto/opk/ports/optee/README.md b/oemcrypto/opk/ports/optee/README.md index 25f608c..66fc92f 100644 --- a/oemcrypto/opk/ports/optee/README.md +++ b/oemcrypto/opk/ports/optee/README.md @@ -1,5 +1,32 @@ This is a port of the OEMCrypto Trusted App for OP-TEE using the OPK. +### Quick build steps + +1. Make sure you have an OPTEE repo setup somewhere. Set that path to the + environment variable OPTEE_DIR. If the GCC toolchain is separate from the one + included in $OPTEE_DIR/toolchains, set that path to OPTEE_TOOLCHAIN_DIR. +2. Set up the third_party directory. The makefiles for unit tests reference + googletest and boringssl, and expect them to be under a top level directory + called "third_party": + ``` + # From the top level of the repo + $ mkdir third_party + $ git clone https://github.com/google/googletest.git googletest + $ mkdir boringssl && cd boringssl + $ mkdir kit && cd kit + $ git clone https://boringssl.googlesource.com/boringssl src && cd src + + # Commits after this change some filenames, which is incompatible with + # current OPK makefiles + $ git checkout 1e15682f1a4bb64c48b84884976a2b5c4201e878 + $ cd ../ + $ python ./src/util/generate_build_files.py gyp + ``` +2. From the top level of this repo (CDM), run `make -j32 -C + ./oemcrypto/opk/build -f Makefile.optee` + +### Background + In general, an end-to-end system consists of the following components on the REE side: @@ -80,22 +107,22 @@ https://optee.readthedocs.io/en/latest/building/devices/qemu.html Specifically the steps are: ``` -export OPTEE=~/optee-qemu # change to your OPTEE root directory -mkdir $OPTEE +export OPTEE_DIR=~/optee-qemu # change to your OPTEE root directory +mkdir $OPTEE_DIR # get the QEMU v7 devkit -cd $OPTEE +cd $OPTEE_DIR repo init -u https://github.com/OP-TEE/manifest.git repo sync -c # build toolchains -cd $OPTEE/build +cd $OPTEE_DIR/build make toolchains export QEMU_VIRTFS_AUTOMOUNT=y export PLATFORM=vexpress-qemu_virt -cd $OPTEE/qemu +cd $OPTEE_DIR/qemu ./configure --enable-virtfs # you may need to sudo apt-get install libcap-ng-dev @@ -103,7 +130,7 @@ cd $OPTEE/qemu # over ssh # To run OP_TEE: -cd $OPTEE/build +cd $OPTEE_DIR/build make -j30 QEMU_VIRTFS_ENABLE=y run # Use this the first time make QEMU_VIRTFS_ENABLE=y run-only # Use this subsequently @@ -111,22 +138,23 @@ make QEMU_VIRTFS_ENABLE=y run-only # Use this subsequently # in console, type ‘c’ # in non-secure login as ‘root’ or ‘test’ -# /mnt/host in non-secure should now link to $OPTEE on linux -To build the port using gyp: # TODO: b/194955656 +# /mnt/host in QEMU REE should now link to $OPTEE_DIR outside of QEMU +# Back outside of QEMU: # Build the OP-TEE port. This includes the OEMCrypto TA and host apps, as well # as the WTPI test TA and host app. -cd $CDM/jenkins -./opk_optee # invokes make to build the OP-TEE port +cd $CDM_DIR +make -j32 -C ./oemcrypto/opk/build -f Makefile.optee -# Push the build artifacts to to $OPTEE, which is the virtfs directory for QEMU +# Push the build artifacts to to $OPTEE_DIR, which is the virtfs directory for QEMU +cd oemcrypto/opk/ports/optee ./push.sh -# in the non-secure login terminal: +# in the QEMU REE terminal: cd /mnt/host/oemcrypto/test . ./install_ta.sh -# run world +# run hello world ./oemcrypto_helloworld # run WTPI unit tests diff --git a/oemcrypto/opk/ports/optee/build/helloworld.gyp b/oemcrypto/opk/ports/optee/build/helloworld.gyp index b8d469a..0fb33e0 100644 --- a/oemcrypto/opk/ports/optee/build/helloworld.gyp +++ b/oemcrypto/opk/ports/optee/build/helloworld.gyp @@ -7,7 +7,6 @@ ], 'variables': { 'optee_port_dir': '<(oemcrypto_dir)/opk/ports/optee', - 'optee_repo_dir': '<(DEPTH)/../optee', }, 'targets' : [ { @@ -19,7 +18,6 @@ ], 'include_dirs' : [ '<(optee_port_dir)/ta/wtpi_test_ta/include', - '<(optee_repo_dir)/optee_client/public', ], 'dependencies': [ '<(oemcrypto_dir)/opk/build/host.gyp:liboemcrypto', diff --git a/oemcrypto/opk/ports/optee/build/host.gyp b/oemcrypto/opk/ports/optee/build/host.gyp index b09febb..690db7e 100644 --- a/oemcrypto/opk/ports/optee/build/host.gyp +++ b/oemcrypto/opk/ports/optee/build/host.gyp @@ -5,7 +5,7 @@ 'variables': { 'optee_port_dir': '<(oemcrypto_dir)/opk/ports/optee', 'tos_src_dir': '<(optee_port_dir)/host/common/tos', - 'optee_repo_dir': '<(DEPTH)/../optee', + 'optee_repo_dir': '$(OPTEE_DIR)', }, 'targets' : [ { diff --git a/oemcrypto/opk/ports/optee/build/ta.gyp b/oemcrypto/opk/ports/optee/build/ta.gyp index 35e954c..16d859d 100644 --- a/oemcrypto/opk/ports/optee/build/ta.gyp +++ b/oemcrypto/opk/ports/optee/build/ta.gyp @@ -7,8 +7,8 @@ 'common': '<(optee_port_dir)/ta/common', 'wtpi_impl': '<(optee_port_dir)/ta/common/wtpi_impl', 'wtpi_ref': '<(oemcrypto_ta_dir)/wtpi_reference', - 'test_impl': '<(DEPTH)/oemcrypto/opk/ports/linux/wtpi_test_impl', - 'optee_dir': '<(DEPTH)/../optee', + 'wtpi_stub': '<(DEPTH)/oemcrypto/opk/oemcrypto_ta/wtpi_useless', + 'optee_dir': '$(OPTEE_DIR)', }, 'targets' : [ { @@ -21,23 +21,22 @@ '<(common)/ta_log.c', '<(common)/der_parse.c', '<(optee_port_dir)/host/common/tos/optee_secure_buffers.c', - '<(wtpi_impl)/abort_interface.c', - '<(wtpi_impl)/clock_interface_layer2.c', - '<(wtpi_impl)/crypto_asymmetric.c', - '<(wtpi_impl)/initialize_terminate_interface.c', - '<(wtpi_impl)/logging_interface.c', - '<(wtpi_impl)/wtpi_config_interface.c', - '<(wtpi_impl)/persistent_storage_layer2.c', - '<(wtpi_impl)/crypto_and_key_management_layer1.c', - '<(wtpi_ref)/crc32.c', - '<(wtpi_impl)/decrypt_sample.c', - '<(wtpi_ref)/clock_and_gn_layer1.c', - '<(wtpi_impl)/root_of_trust_layer1.c', - '<(wtpi_ref)/device_key.c', - '<(wtpi_ref)/crypto_wrap_asymmetric.c', - '<(test_impl)/secure_buffer_access.c', - '<(test_impl)/root_of_trust_layer2.c', - '<(test_impl)/test_keybox.c', + '<(wtpi_impl)/wtpi_abort.c', + '<(wtpi_impl)/wtpi_clock_layer2.c', + '<(wtpi_impl)/wtpi_config.c', + '<(wtpi_impl)/wtpi_crypto_and_key_management_layer1.c', + '<(wtpi_impl)/wtpi_crypto_asymmetric.c', + '<(wtpi_impl)/wtpi_decrypt_sample.c', + '<(wtpi_impl)/wtpi_initialize_terminate_interface.c', + '<(wtpi_impl)/wtpi_logging.c', + '<(wtpi_impl)/wtpi_persistent_storage_layer2.c', + '<(wtpi_stub)/wtpi_root_of_trust_layer2.c', + '<(wtpi_stub)/wtpi_secure_buffer_access.c', + '<(wtpi_ref)/wtpi_clock_and_gn_layer1.c', + '<(wtpi_ref)/wtpi_crc32.c', + '<(wtpi_ref)/wtpi_crypto_wrap_asymmetric.c', + '<(wtpi_ref)/wtpi_device_key.c', + '<(wtpi_ref)/wtpi_root_of_trust_layer1.c', ], 'defines': [ # Needed for to work. @@ -55,6 +54,11 @@ '<(oemcrypto_ta_dir)/wtpi', '<(common)', '<(optee_dir)/optee_os/out/arm/export-ta_arm32/include', + '<(optee_dir)/optee_os/out/arm/export-ta_arm32/include/mbedtls', + ], + 'ldflags': [ + '-L<(optee_dir)/optee_os/out/arm/export-ta_arm32/lib', + '-lmbedtls', ], }, ], diff --git a/oemcrypto/opk/ports/optee/host/common/tos/ree_tos.target.mk b/oemcrypto/opk/ports/optee/host/common/tos/ree_tos.target.mk new file mode 100644 index 0000000..fff5e61 --- /dev/null +++ b/oemcrypto/opk/ports/optee/host/common/tos/ree_tos.target.mk @@ -0,0 +1,161 @@ +# +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := ree_tos +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/include \ + -I$(OPTEE_DIR)/optee_client/public + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/include \ + -I$(OPTEE_DIR)/optee_client/public + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/load_library.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/optee_ree_tos.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/optee_tos_log.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a +# Add target alias +.PHONY: ree_tos +ree_tos: $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a + +# Add target alias to "all" target. +.PHONY: all +all: ree_tos + +# Add target alias +.PHONY: ree_tos +ree_tos: $(builddir)/libree_tos.a + +# Copy this to the static library output path. +$(builddir)/libree_tos.a: TOOLSET := $(TOOLSET) +$(builddir)/libree_tos.a: $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libree_tos.a +# Short alias for building this static library. +.PHONY: libree_tos.a +libree_tos.a: $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos.a $(builddir)/libree_tos.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libree_tos.a + diff --git a/oemcrypto/opk/ports/optee/host/common/tos/ree_tos_wtpi.target.mk b/oemcrypto/opk/ports/optee/host/common/tos/ree_tos_wtpi.target.mk new file mode 100644 index 0000000..e3df517 --- /dev/null +++ b/oemcrypto/opk/ports/optee/host/common/tos/ree_tos_wtpi.target.mk @@ -0,0 +1,160 @@ +# +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := ree_tos_wtpi +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/include \ + -I$(OPTEE_DIR)/optee_client/public + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/include \ + -I$(OPTEE_DIR)/optee_client/public + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/optee_ree_tos.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/optee_tos_log.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a +# Add target alias +.PHONY: ree_tos_wtpi +ree_tos_wtpi: $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a + +# Add target alias to "all" target. +.PHONY: all +all: ree_tos_wtpi + +# Add target alias +.PHONY: ree_tos_wtpi +ree_tos_wtpi: $(builddir)/libree_tos_wtpi.a + +# Copy this to the static library output path. +$(builddir)/libree_tos_wtpi.a: TOOLSET := $(TOOLSET) +$(builddir)/libree_tos_wtpi.a: $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libree_tos_wtpi.a +# Short alias for building this static library. +.PHONY: libree_tos_wtpi.a +libree_tos_wtpi.a: $(obj).target/oemcrypto/opk/ports/optee/build/libree_tos_wtpi.a $(builddir)/libree_tos_wtpi.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libree_tos_wtpi.a + diff --git a/oemcrypto/opk/ports/optee/host/oemcrypto_helloworld/oemcrypto_helloworld.target.mk b/oemcrypto/opk/ports/optee/host/oemcrypto_helloworld/oemcrypto_helloworld.target.mk new file mode 100644 index 0000000..9778ba1 --- /dev/null +++ b/oemcrypto/opk/ports/optee/host/oemcrypto_helloworld/oemcrypto_helloworld.target.mk @@ -0,0 +1,147 @@ +# # +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := oemcrypto_helloworld +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/include + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/oemcrypto_helloworld/main.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# Make sure our dependencies are built before any of us. +$(OBJS): | $(builddir)/lib.target/liboemcrypto.so $(obj).target/oemcrypto/opk/build/liboemcrypto.so + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := \ + -Wl,-rpath=\$$ORIGIN/lib.target/ \ + -Wl,-rpath-link=\$(builddir)/lib.target/ + +LDFLAGS_release := \ + -O2 \ + -Wl,--strip-debug \ + -Wl,-rpath=\$$ORIGIN/lib.target/ \ + -Wl,-rpath-link=\$(builddir)/lib.target/ + +LIBS := \ + $(TRUSTED_OS_SDK_LIBS) + +$(builddir)/oemcrypto_helloworld: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/oemcrypto_helloworld: LIBS := $(LIBS) +$(builddir)/oemcrypto_helloworld: LD_INPUTS := $(OBJS) $(obj).target/oemcrypto/opk/build/liboemcrypto.so +$(builddir)/oemcrypto_helloworld: TOOLSET := $(TOOLSET) +$(builddir)/oemcrypto_helloworld: $(OBJS) $(obj).target/oemcrypto/opk/build/liboemcrypto.so FORCE_DO_CMD + $(call do_cmd,link) + +all_deps += $(builddir)/oemcrypto_helloworld +# Add target alias +.PHONY: oemcrypto_helloworld +oemcrypto_helloworld: $(builddir)/oemcrypto_helloworld + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/oemcrypto_helloworld + diff --git a/oemcrypto/opk/ports/optee/host/oemcrypto_unittests/oemcrypto_unittests.target.mk b/oemcrypto/opk/ports/optee/host/oemcrypto_unittests/oemcrypto_unittests.target.mk new file mode 100644 index 0000000..c9b5696 --- /dev/null +++ b/oemcrypto/opk/ports/optee/host/oemcrypto_unittests/oemcrypto_unittests.target.mk @@ -0,0 +1,188 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := oemcrypto_unittests +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-DOEMCRYPTO_TESTS' \ + '-D_DEFAULT_SOURCE' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/util/include \ + -I$(srcdir)/util/test \ + -I$(srcdir)/oemcrypto/ref/src \ + -I$(srcdir)/oemcrypto/test \ + -I$(srcdir)/oemcrypto/test/fuzz_tests \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DOEMCRYPTO_TESTS' \ + '-D_DEFAULT_SOURCE' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/util/include \ + -I$(srcdir)/util/test \ + -I$(srcdir)/oemcrypto/ref/src \ + -I$(srcdir)/oemcrypto/test \ + -I$(srcdir)/oemcrypto/test/fuzz_tests \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/third_party/boringssl/kit/src/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/test/oemcrypto_test_main.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/core_message_deserialize.o \ + $(obj).target/$(TARGET)/oemcrypto/odk/src/core_message_serialize.o \ + $(obj).target/$(TARGET)/linux/src/file_store.o \ + $(obj).target/$(TARGET)/linux/src/log.o \ + $(obj).target/$(TARGET)/util/src/cdm_random.o \ + $(obj).target/$(TARGET)/util/src/platform.o \ + $(obj).target/$(TARGET)/util/src/rw_lock.o \ + $(obj).target/$(TARGET)/util/src/string_conversions.o \ + $(obj).target/$(TARGET)/util/test/test_sleep.o \ + $(obj).target/$(TARGET)/util/test/test_clock.o \ + $(obj).target/$(TARGET)/oemcrypto/test/oec_device_features.o \ + $(obj).target/$(TARGET)/oemcrypto/test/oec_decrypt_fallback_chain.o \ + $(obj).target/$(TARGET)/oemcrypto/test/oec_key_deriver.o \ + $(obj).target/$(TARGET)/oemcrypto/test/oec_session_util.o \ + $(obj).target/$(TARGET)/oemcrypto/test/oemcrypto_corpus_generator_helper.o \ + $(obj).target/$(TARGET)/oemcrypto/test/oemcrypto_session_tests_helper.o \ + $(obj).target/$(TARGET)/oemcrypto/test/oemcrypto_test.o \ + $(obj).target/$(TARGET)/oemcrypto/test/wvcrc.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# Make sure our dependencies are built before any of us. +$(OBJS): | $(builddir)/lib.target/liboemcrypto.so $(obj).target/third_party/libgtest.a $(obj).target/third_party/libgmock.a $(builddir)/libodk.a $(builddir)/libssl.a $(builddir)/libcrypto.a $(obj).target/oemcrypto/opk/build/liboemcrypto.so $(obj).target/oemcrypto/odk/src/libodk.a $(obj).target/third_party/boringssl/libssl.a $(obj).target/third_party/boringssl/libcrypto.a + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := \ + $(OEMCRYPTO_UNITTEST_LDFLAGS) \ + -Wl,-rpath=\$$ORIGIN/lib.target/ \ + -Wl,-rpath-link=\$(builddir)/lib.target/ + +LDFLAGS_release := \ + $(OEMCRYPTO_UNITTEST_LDFLAGS) \ + -O2 \ + -Wl,--strip-debug \ + -Wl,-rpath=\$$ORIGIN/lib.target/ \ + -Wl,-rpath-link=\$(builddir)/lib.target/ + +LIBS := \ + $(TRUSTED_OS_SDK_LIBS) \ + $(builddir)/libree_tos.a \ + -lpthread + +$(builddir)/oemcrypto_unittests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/oemcrypto_unittests: LIBS := $(LIBS) +$(builddir)/oemcrypto_unittests: LD_INPUTS := $(OBJS) $(obj).target/oemcrypto/opk/build/liboemcrypto.so $(obj).target/third_party/libgtest.a $(obj).target/third_party/libgmock.a $(obj).target/oemcrypto/odk/src/libodk.a $(obj).target/third_party/boringssl/libssl.a $(obj).target/third_party/boringssl/libcrypto.a +$(builddir)/oemcrypto_unittests: TOOLSET := $(TOOLSET) +$(builddir)/oemcrypto_unittests: $(OBJS) $(obj).target/oemcrypto/opk/build/liboemcrypto.so $(obj).target/third_party/libgtest.a $(obj).target/third_party/libgmock.a $(obj).target/oemcrypto/odk/src/libodk.a $(obj).target/third_party/boringssl/libssl.a $(obj).target/third_party/boringssl/libcrypto.a FORCE_DO_CMD + $(call do_cmd,link) + +all_deps += $(builddir)/oemcrypto_unittests +# Add target alias +.PHONY: oemcrypto_unittests +oemcrypto_unittests: $(builddir)/oemcrypto_unittests + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/oemcrypto_unittests + diff --git a/oemcrypto/opk/ports/optee/host/wtpi_unittests/wtpi_unittests.target.mk b/oemcrypto/opk/ports/optee/host/wtpi_unittests/wtpi_unittests.target.mk new file mode 100644 index 0000000..f71ae06 --- /dev/null +++ b/oemcrypto/opk/ports/optee/host/wtpi_unittests/wtpi_unittests.target.mk @@ -0,0 +1,142 @@ +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := wtpi_unittests +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest/include + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/third_party/googletest/googlemock/include \ + -I$(srcdir)/third_party/googletest/googletest/include + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_test/wtpi_test_main.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# Make sure our dependencies are built before any of us. +$(OBJS): | $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a $(builddir)/libwtpi_test_lib.a $(obj).target/third_party/libgtest.a $(obj).target/third_party/libgmock.a $(builddir)/libcrypto.a $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a $(obj).target/third_party/boringssl/libcrypto.a + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cpp FORCE_DO_CMD + @$(call do_cmd,cxx,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := \ + $(WTPI_UNITTEST_LDFLAGS) + +LDFLAGS_release := \ + $(WTPI_UNITTEST_LDFLAGS) \ + -O2 \ + -Wl,--strip-debug + +LIBS := \ + -lpthread + +$(builddir)/wtpi_unittests: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(builddir)/wtpi_unittests: LIBS := $(LIBS) +$(builddir)/wtpi_unittests: LD_INPUTS := $(OBJS) $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a $(obj).target/third_party/libgtest.a $(obj).target/third_party/libgmock.a $(obj).target/third_party/boringssl/libcrypto.a +$(builddir)/wtpi_unittests: TOOLSET := $(TOOLSET) +$(builddir)/wtpi_unittests: $(OBJS) $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/ree/libopk_ree_api.a $(obj).target/oemcrypto/opk/oemcrypto_ta/wtpi_test/libwtpi_test_lib.a $(obj).target/third_party/libgtest.a $(obj).target/third_party/libgmock.a $(obj).target/third_party/boringssl/libcrypto.a FORCE_DO_CMD + $(call do_cmd,link) + +all_deps += $(builddir)/wtpi_unittests +# Add target alias +.PHONY: wtpi_unittests +wtpi_unittests: $(builddir)/wtpi_unittests + +# Add executable to "all" target. +.PHONY: all +all: $(builddir)/wtpi_unittests + diff --git a/oemcrypto/opk/ports/optee/push.sh b/oemcrypto/opk/ports/optee/push.sh index 6521a35..40787e1 100755 --- a/oemcrypto/opk/ports/optee/push.sh +++ b/oemcrypto/opk/ports/optee/push.sh @@ -1,21 +1,21 @@ #!/bin/bash -[ -z "${OPTEE}" ] && echo "Set \$OPTEE to your OPTEE SDK root. See README.md" && exit -[ -z "${CDM}" ] && echo "Set \$CDM to your CDM repo root" && exit +[ -z "${OPTEE_DIR}" ] && echo "Set \$OPTEE_DIR to your OPTEE SDK root. See README.md" && exit +[ -z "${CDM_DIR}" ] && echo "Set \$CDM_DIR to your CDM_DIR repo root" && exit -echo "copy oemcrypto_ta (a92d116c-ce27-4917-b30c-4a416e2d9351) to $OPTEE/oemcrypto/test" -cp ta/oemcrypto_ta/out/a92d116c-ce27-4917-b30c-4a416e2d9351.ta $OPTEE/oemcrypto/test -cp $CDM/out/opk_optee/debug/oemcrypto_helloworld $OPTEE/oemcrypto/test +echo "copy oemcrypto_ta (a92d116c-ce27-4917-b30c-4a416e2d9351) to $OPTEE_DIR/oemcrypto/test" +cp ta/oemcrypto_ta/out/a92d116c-ce27-4917-b30c-4a416e2d9351.ta $OPTEE_DIR/oemcrypto/test +cp $CDM_DIR/out/opk_optee/debug/oemcrypto_helloworld $OPTEE_DIR/oemcrypto/test -echo "copy wtpi_test_ta (b0f42504-01ec-11ec-9a03-0242ac130003) to $OPTEE/oemcrypto/test" -cp ta/wtpi_test_ta/out/b0f42504-01ec-11ec-9a03-0242ac130003.ta $OPTEE/oemcrypto/test -cp $CDM/out/opk_optee/debug/wtpi_unittests $OPTEE/oemcrypto/test +echo "copy wtpi_test_ta (b0f42504-01ec-11ec-9a03-0242ac130003) to $OPTEE_DIR/oemcrypto/test" +cp ta/wtpi_test_ta/out/b0f42504-01ec-11ec-9a03-0242ac130003.ta $OPTEE_DIR/oemcrypto/test +cp $CDM_DIR/out/opk_optee/debug/wtpi_unittests $OPTEE_DIR/oemcrypto/test -test -d $OPTEE/oemcrypto/host || mkdir -p $OPTEE/oemcrypto/test -echo "copy oemcrypto unit tests to $OPTEE/oemcrypto/test" -cp $CDM/out/opk_optee/debug/oemcrypto_unittests $OPTEE/oemcrypto/test +test -d $OPTEE_DIR/oemcrypto/host || mkdir -p $OPTEE_DIR/oemcrypto/test +echo "copy oemcrypto unit tests to $OPTEE_DIR/oemcrypto/test" +cp $CDM_DIR/out/opk_optee/debug/oemcrypto_unittests $OPTEE_DIR/oemcrypto/test -echo "copy liboemcrypto.so $OPTEE/oemcrypto/test" -cp $CDM/out/opk_optee/debug/lib.target/liboemcrypto.so $OPTEE/oemcrypto/test +echo "copy liboemcrypto.so $OPTEE_DIR/oemcrypto/test" +cp $CDM_DIR/out/opk_optee/debug/lib.target/liboemcrypto.so $OPTEE_DIR/oemcrypto/test -echo "copy install_ta.sh $OPTEE/oemcrypto/test" -cp ./install_ta.sh $OPTEE/oemcrypto/test +echo "copy install_ta.sh $OPTEE_DIR/oemcrypto/test" +cp ./install_ta.sh $OPTEE_DIR/oemcrypto/test diff --git a/oemcrypto/opk/ports/optee/ta/common/der_parse.c b/oemcrypto/opk/ports/optee/ta/common/der_parse.c index 150264d..9e7e8a0 100644 --- a/oemcrypto/opk/ports/optee/ta/common/der_parse.c +++ b/oemcrypto/opk/ports/optee/ta/common/der_parse.c @@ -6,258 +6,50 @@ #include "der_parse.h" #include +#include "bignum.h" +#include "pk.h" +#include "rsa.h" /* - * Extracts the DER encoded length attribute located at |offset| in the |data| - * buffer. Increments |offset| to point to the next byte after the length. + * Takes an mbedtls_mpi pointer |src|, an empty buffer pointer |dest|, and + * a 0 value |dest_len|. * - * Places length information in |output|. + * Extracts the length value from |src| and places that into |dest_len| * - * Does not support lengths larger than uint32_t (4 bytes), even though DER can - * encode up to 128 bytes of length information. - */ -static OEMCryptoResult der_get_len(const uint8_t* data, size_t* offset, - size_t* output) { - size_t n = *offset; - uint8_t comp = data[n] & 0x80; - if (comp == 0) { - *output = data[n]; - n++; - } else { - uint8_t remainder = data[n++] & 0x7F; - if (remainder > 4) { - // not supporting anything bigger than a uint32_t size right now - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - for (int i = remainder - 1; i >= 0; i--) { - *output = *output | (data[n] << (i * 8)); - n++; - } - } - - *offset = n; - return OEMCrypto_SUCCESS; -} - -/* - * Parses the header information in a DER-encoded PKCS8 RSA private key, which - * is passed in as |input|. + * Malloc's a buffer with size |dest_len| and assigns the buffer pointer to + * |dest| * - * Since a PKCS8 RSA key has a specific ordering of data, we can expect that the - * header information will be the same across different keys. Eg. SEQUENCE tag - * followed by version INTEGER followed by SEQUENCE tag followed by OID, etc. - * - * This function returns SUCCESS when it has reached the start of the RSA - * private key data (modulus, exponents, etc). The |offset| is changed to point - * to that position in the |input| data. + * Extracts the data from |src| to |dest| with the mbed_mpi_write_binary + * function * */ -static OEMCryptoResult validate_and_go_to_rsa_data(const uint8_t* input, - size_t input_length, - size_t* offset) { - if (input == NULL || input_length <= 2) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; +static OEMCryptoResult extract_rsa_param(mbedtls_mpi* src, uint8_t** dest, + size_t* dest_len) { + if (src == NULL || dest == NULL || dest_len == NULL) { + return OEMCrypto_ERROR_INVALID_CONTEXT; } - /* - * DER format is {tag, data length, data}. The data can then be another - * triplet of new tag/length/data, recursively. - * - * The PKCS8 spec is very particular about how RSA private key data is ordered - * and encoded. This allows us to narrow down on the start of the RSA data by - * looking for a specific ordering of tags/values from the start. - * - * Once we get there, the individual values are laid out in an order defined - * by PKCS1, encoded as DER tag+length+data blobs. The first blob is the - * version, followed by a blob with the modulus, a blob with the public - * exponent, etc. - * - */ + size_t len = mbedtls_mpi_size(src); - // tags - const uint8_t SEQUENCE = 0x30; - const uint8_t INTEGER = 0x02; - const uint8_t OCTET_STRING = 0x04; - const uint8_t OID = 0x06; - const uint8_t DER_NULL = 0x05; - - size_t n = 0; - - // must start with {SEQUENCE} - if (input[n] != 0x30) { - EMSG("n: %d, not sequence", n); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - size_t provided_len = 0; - n++; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &provided_len)) { - EMSG("n: %d, bad len %d ", n, provided_len); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // version - if (input[n] != INTEGER) { - EMSG("n: %d, not integer", n); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n++; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - size_t version_len = 0; - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &version_len)) { - EMSG("n: %d, bad len %d ", n, version_len); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n += version_len; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // sequence - if (input[n] != SEQUENCE) { - EMSG("n: %d, not sequence 2", n); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n++; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - size_t seq2_len = 0; - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &seq2_len)) { - EMSG("n: %d, bad len %d ", n, seq2_len); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // OID - if (input[n] != OID) { - EMSG("n: %d, not oid", n); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n++; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - size_t oid_len = 0; - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &oid_len)) { - EMSG("n: %d, bad len %d ", n, oid_len); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - const uint8_t rsa_oid[6] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d}; - for (int i = 0; i < 6; i++) { - if (input[n + i] != rsa_oid[i]) { - EMSG("n: %d, bad RSA OID for i=%d", n, i); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - } - n += oid_len; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // NULL - if (input[n] != DER_NULL) { - EMSG("n: %d, not null", n); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n++; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - size_t null_len = 0; - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &null_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n += null_len; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // octet string followed by sequence - if (input[n] != OCTET_STRING) { - EMSG("n: %d, not octet", n); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n++; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - size_t octet_str_len = 0; - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &octet_str_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (input[n] != SEQUENCE) { - EMSG("n: %d, not seq 3", n); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n++; - if (input_length < n) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - size_t seq3_len = 0; - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &seq3_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // we made it - - *offset = n; - - return OEMCrypto_SUCCESS; -} - -/* - * Helper function to parse and extract information from the RSA private key - * blob located in the main body of the |input| PKCS8 data. - */ -static OEMCryptoResult get_data_blob(const uint8_t* input, size_t* offset, - uint8_t** dest, size_t* dest_len) { - size_t n = *offset; - if (input[n] != 0x02) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - n++; - size_t data_len = 0; - if (OEMCrypto_SUCCESS != der_get_len(input, &n, &data_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - if (input[n] == 0x00) { - // leading zero, can skip because DER/ASN.1 encodes what it considers - // "positive" integers with a leading zero. - - n++; - data_len--; - } - - uint8_t* data = TEE_Malloc(data_len, 0); + uint8_t* data = TEE_Malloc(len, 0); if (data == TEE_HANDLE_NULL) { EMSG("Malloc failed, out of memory"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - TEE_MemMove(data, &input[n], data_len); + int ret = mbedtls_mpi_write_binary(src, data, len); + if (ret != 0 || len == 0) { + TEE_Free(data); + EMSG("mbedtls_mpi_write_binary failed"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + *dest = data; - n += data_len; - *dest_len = data_len; - *offset = n; + *dest_len = len; + return OEMCrypto_SUCCESS; } + /* * Parses |input| data, which is a DER-encoded PKCS8 RSA private key. Extracts * the RSA private key components such as modulus, exponents, primes, @@ -268,57 +60,86 @@ static OEMCryptoResult get_data_blob(const uint8_t* input, size_t* offset, */ OEMCryptoResult ParsePKCS8_DER(const uint8_t* input, size_t input_length, pkcs1_rsa* output) { - size_t off = 0; - if (OEMCrypto_SUCCESS != - validate_and_go_to_rsa_data(input, input_length, &off)) { + OEMCryptoResult res; + + mbedtls_pk_context pk_ctx; + mbedtls_pk_init(&pk_ctx); + int ret = mbedtls_pk_parse_key(&pk_ctx, input, input_length, NULL, 0); + if (ret != 0) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - size_t n = off; + mbedtls_mpi N, P, Q, D, E, DP, DQ, QP; - // get version info and promptly ignore it. We don't care about it. - uint8_t* version; - size_t version_length = 0; - if (OEMCrypto_SUCCESS != - get_data_blob(input, &n, &version, &version_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - TEE_Free(version); + mbedtls_mpi_init(&N); + mbedtls_mpi_init(&P); + mbedtls_mpi_init(&Q); + mbedtls_mpi_init(&D); + mbedtls_mpi_init(&E); + mbedtls_mpi_init(&DP); + mbedtls_mpi_init(&DQ); + mbedtls_mpi_init(&QP); - if (OEMCrypto_SUCCESS != - get_data_blob(input, &n, &output->modulus, &output->modulus_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (OEMCrypto_SUCCESS != - get_data_blob(input, &n, &output->public_exp, &output->public_exp_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (OEMCrypto_SUCCESS != get_data_blob(input, &n, &output->private_exp, - &output->private_exp_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (OEMCrypto_SUCCESS != - get_data_blob(input, &n, &output->prime1, &output->prime1_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (OEMCrypto_SUCCESS != - get_data_blob(input, &n, &output->prime2, &output->prime2_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (OEMCrypto_SUCCESS != - get_data_blob(input, &n, &output->exp1, &output->exp1_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (OEMCrypto_SUCCESS != - get_data_blob(input, &n, &output->exp2, &output->exp2_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (OEMCrypto_SUCCESS != get_data_blob(input, &n, &output->coefficient, - &output->coefficient_len)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; + mbedtls_rsa_context* rsa_ctx = mbedtls_pk_rsa(pk_ctx); + + ret = mbedtls_rsa_export(rsa_ctx, &N, &P, &Q, &D, &E); + if (ret != 0) { + res = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; } - // print_pkcs1_rsa_data_preview(output); + ret = mbedtls_rsa_export_crt(rsa_ctx, &DP, &DQ, &QP); + if (ret != 0) { + res = OEMCrypto_ERROR_UNKNOWN_FAILURE; + goto cleanup; + } - return OEMCrypto_SUCCESS; + if ((res = extract_rsa_param(&N, &output->modulus, &output->modulus_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + + if ((res = extract_rsa_param(&E, &output->public_exp, + &output->public_exp_len)) != OEMCrypto_SUCCESS) + goto cleanup; + + if ((res = extract_rsa_param(&D, &output->private_exp, + &output->private_exp_len)) != OEMCrypto_SUCCESS) + goto cleanup; + + if ((res = extract_rsa_param(&P, &output->prime1, &output->prime1_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + + if ((res = extract_rsa_param(&Q, &output->prime2, &output->prime2_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + + if ((res = extract_rsa_param(&DP, &output->exp1, &output->exp1_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + + if ((res = extract_rsa_param(&DQ, &output->exp2, &output->exp2_len)) != + OEMCrypto_SUCCESS) + goto cleanup; + + if ((res = extract_rsa_param(&QP, &output->coefficient, + &output->coefficient_len)) != OEMCrypto_SUCCESS) + goto cleanup; + + res = OEMCrypto_SUCCESS; + +cleanup: + + mbedtls_mpi_free(&N); + mbedtls_mpi_free(&P); + mbedtls_mpi_free(&Q); + mbedtls_mpi_free(&D); + mbedtls_mpi_free(&E); + mbedtls_mpi_free(&DP); + mbedtls_mpi_free(&DQ); + mbedtls_mpi_free(&QP); + + mbedtls_pk_free(&pk_ctx); + + return res; } diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/abort_interface.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_abort.c similarity index 100% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/abort_interface.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_abort.c diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/clock_interface_layer2.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_clock_layer2.c similarity index 100% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/clock_interface_layer2.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_clock_layer2.c diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_interface.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c similarity index 96% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_interface.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c index 9ba7da2..e6d4074 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config_interface.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.c @@ -14,7 +14,6 @@ OEMCrypto_ProvisioningMethod WTPI_GetProvisioningMethod(void) { uint32_t WTPI_GetResourceRatingTier(void) { return 1; } -// TODO: Not sure what a valid SRM Version should be. Trusty uses 0. OEMCryptoResult WTPI_GetCurrentSRMVersion(uint32_t* srm_version) { if (srm_version == NULL) { return OEMCrypto_ERROR_INVALID_CONTEXT; diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_and_key_management_layer1.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c similarity index 99% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_and_key_management_layer1.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c index 7c6e2da..22624f8 100644 --- a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_and_key_management_layer1.c +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.c @@ -58,6 +58,7 @@ typedef struct wtpi_k1_symmetric_key_handle { OEMCryptoResult WTPI_K1_GetKeySize(WTPI_K1_SymmetricKey_Handle key, KeySize* size) { + if (size == NULL) return OEMCrypto_ERROR_INVALID_CONTEXT; *size = OPK_LengthToKeySize(key->key_size); return OEMCrypto_SUCCESS; } @@ -647,7 +648,7 @@ OEMCryptoResult WTPI_K1_WrapKey(UNUSED uint32_t context, WTPI_K1_SymmetricKey_Handle key, SymmetricKeyType key_type, uint8_t* wrapped_key, size_t wrapped_key_length) { - if (key == NULL) { + if (key == NULL || wrapped_key == NULL || wrapped_key_length == 0) { return OEMCrypto_ERROR_INVALID_CONTEXT; } diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_asymmetric.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c similarity index 100% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/crypto_asymmetric.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.c diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/decrypt_sample.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c similarity index 100% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/decrypt_sample.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.c diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_impl.target.mk b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_impl.target.mk new file mode 100644 index 0000000..f445d7d --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_impl.target.mk @@ -0,0 +1,190 @@ +# +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +# This file is generated by gyp; do not edit. + +TOOLSET := target +TARGET := wtpi_impl +DEFS_debug := \ + '-DENABLE_LOGGING=1' \ + '-D_DEFAULT_SOURCE' \ + '-D__USE_MISC' \ + '-D_DEBUG' \ + '-D_GLIBCXX_DEBUG' + +# Flags passed to all source files. +CFLAGS_debug := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -g \ + -Og + +# Flags passed to only C files. +CFLAGS_C_debug := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_debug := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_debug := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/common \ + -I$(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32/include \ + -I$(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32/include/mbedtls \ + -I$(OPTEE_DIR)/optee_os/lib/libmbedtls/mbedtls/include/mbedtls + +DEFS_release := \ + '-DENABLE_LOGGING=1' \ + '-D_DEFAULT_SOURCE' \ + '-D__USE_MISC' \ + '-DNDEBUG' + +# Flags passed to all source files. +CFLAGS_release := \ + -fPIC \ + -fvisibility=hidden \ + -fno-common \ + -g \ + -Werror=all \ + -O2 \ + -g0 + +# Flags passed to only C files. +CFLAGS_C_release := \ + -std=c11 \ + -D_POSIX_C_SOURCE=200809L + +# Flags passed to only C++ files. +CFLAGS_CC_release := \ + -std=c++11 \ + -Wnon-virtual-dtor \ + -fno-exceptions \ + -fno-rtti + +INCS_release := \ + -I$(srcdir)/oemcrypto/opk/serialization \ + -I$(srcdir)/oemcrypto/opk/serialization/common \ + -I$(srcdir)/oemcrypto/opk/serialization/common/include \ + -I$(srcdir)/third_party/nlohmann-json/single_include \ + -I$(srcdir)/oemcrypto/odk/include \ + -I$(srcdir)/oemcrypto/odk/src \ + -I$(srcdir)/oemcrypto/include \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta \ + -I$(srcdir)/oemcrypto/opk/oemcrypto_ta/wtpi \ + -I$(srcdir)/oemcrypto/opk/serialization/os_interfaces \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl \ + -I$(srcdir)/oemcrypto/opk/ports/optee/ta/common \ + -I$(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32/include \ + -I$(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32/include/mbedtls \ + -I$(OPTEE_DIR)/optee_os/lib/libmbedtls/mbedtls/include/mbedtls + +OBJS := \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/ta_log.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/der_parse.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/host/common/tos/optee_secure_buffers.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_abort.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_clock_layer2.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_config.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_and_key_management_layer1.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_crypto_asymmetric.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_decrypt_sample.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_initialize_terminate_interface.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_logging.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_root_of_trust_layer1.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_root_of_trust_layer2.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_useless/wtpi_secure_buffer_access.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_clock_and_gn_layer1.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crc32.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_crypto_wrap_asymmetric.o \ + $(obj).target/$(TARGET)/oemcrypto/opk/oemcrypto_ta/wtpi_reference/wtpi_device_key.o + +# Add to the list of files we specially track dependencies for. +all_deps += $(OBJS) + +# CFLAGS et al overrides must be target-local. +# See "Target-specific Variable Values" in the GNU Make manual. +$(OBJS): TOOLSET := $(TOOLSET) +$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE)) +$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE)) + +# Suffix rules, putting all outputs into $(obj). + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# Try building from generated source, too. + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.c FORCE_DO_CMD + @$(call do_cmd,cc,1) + +# End of this set of suffix rules +### Rules for final target. +LDFLAGS_debug := \ + -L$(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32/lib \ + -lmbedtls + +LDFLAGS_release := \ + -L$(OPTEE_DIR)/optee_os/out/arm/export-ta_arm32/lib \ + -lmbedtls \ + -O2 \ + -Wl,--strip-debug + +LIBS := + +$(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE)) +$(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a: LIBS := $(LIBS) +$(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a: TOOLSET := $(TOOLSET) +$(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a: $(OBJS) FORCE_DO_CMD + $(call do_cmd,alink) + +all_deps += $(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a +# Add target alias +.PHONY: wtpi_impl +wtpi_impl: $(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a + +# Add target alias to "all" target. +.PHONY: all +all: wtpi_impl + +# Add target alias +.PHONY: wtpi_impl +wtpi_impl: $(builddir)/libwtpi_impl.a + +# Copy this to the static library output path. +$(builddir)/libwtpi_impl.a: TOOLSET := $(TOOLSET) +$(builddir)/libwtpi_impl.a: $(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a FORCE_DO_CMD + $(call do_cmd,copy) + +all_deps += $(builddir)/libwtpi_impl.a +# Short alias for building this static library. +.PHONY: libwtpi_impl.a +libwtpi_impl.a: $(obj).target/oemcrypto/opk/ports/optee/build/libwtpi_impl.a $(builddir)/libwtpi_impl.a + +# Add static library to "all" target. +.PHONY: all +all: $(builddir)/libwtpi_impl.a + diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/initialize_terminate_interface.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_initialize_terminate_interface.c similarity index 100% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/initialize_terminate_interface.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_initialize_terminate_interface.c diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/logging_interface.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_logging.c similarity index 100% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/logging_interface.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_logging.c diff --git a/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/persistent_storage_layer2.c b/oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c similarity index 100% rename from oemcrypto/opk/ports/optee/ta/common/wtpi_impl/persistent_storage_layer2.c rename to oemcrypto/opk/ports/optee/ta/common/wtpi_impl/wtpi_persistent_storage_layer2.c diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile new file mode 100644 index 0000000..50dba94 --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/Makefile @@ -0,0 +1,31 @@ +# +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +CFG_TEE_TA_LOG_LEVEL := 4 + +# The UUID for the Trusted Application +BINARY=a92d116c-ce27-4917-b30c-4a416e2d9351 + +# OP-TEE-specifc defines for the target build +# Must have the following defined for OP-TEE's build system. These are defined +# by the top level makefile, but can be overridden locally if desired. +# - CROSS_COMPILE: prefix of compiler, eg arm-linux-gnueabihf- +# - PLATFORM: OP-TEE platform enumeration, eg vexpress-qemu_virt +# - TEEC_EXPORT: path to libteec.so in OP-TEE client build output +# - TA_DEV_KIT_DIR: path to OP-TEE TA dev kit makefiles +# - O: optional output directory specification +.EXPORT_ALL_VARIABLES: +TEEC_EXPORT ?= $(OPTEE_DIR)/out-br/build/optee_client_ext-1.0/libteec +PATH := $(PATH):$(OPTEE_DIR)/toolchains/aarch32/bin/:$(OPTEE_DIR)/toolchains/aarch64/bin/ +O := ./out +CFG_TEE_TA_MALLOC_DEBUG:=y + +include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk + +ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) +clean: + @echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' + @echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' +endif diff --git a/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk new file mode 100644 index 0000000..272fec4 --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/oemcrypto_ta/sub.mk @@ -0,0 +1,44 @@ +# +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +OEMCRYPTO=../../../../.. +ODK=$(OEMCRYPTO)/odk +OPK=$(OEMCRYPTO)/opk +SER=$(OPK)/serialization +OEMCRYPTO_TA=$(OPK)/oemcrypto_ta +OPTEE_PORT=$(OPK)/ports/optee +MAIN_TA=$(OPTEE_PORT)/ta/oemcrypto_ta +COMMON=$(OPTEE_PORT)/ta/common + +global-incdirs-y += $(OEMCRYPTO)/include +global-incdirs-y += $(ODK)/include +global-incdirs-y += $(ODK)/src +global-incdirs-y += $(SER)/common/include +global-incdirs-y += $(SER)/os_interfaces +global-incdirs-y += $(OEMCRYPTO_TA) +global-incdirs-y += $(OEMCRYPTO_TA)/wtpi +global-incdirs-y += $(MAIN_TA)/include +global-incdirs-y += $(COMMON) + +srcs-y += oemcrypto_ta.c + +libdirs += $(OEMCRYPTO)/../out/opk_optee/debug + +libnames += odk +libnames += opk_tee +libnames += oemcrypto_ta +libnames += wtpi_impl + +ifeq ($(USE_TA_REFERENCE_CRYPTO),yes) + libnames += oemcrypto_ta_reference_crypto +endif + +ifeq ($(USE_TA_REFERENCE_CLOCK),yes) + libnames += oemcrypto_ta_reference_clock +endif + +ifeq ($(USE_TA_REFERENCE_ROOT_OF_TRUST),yes) + libnames += oemcrypto_ta_reference_root_of_trust +endif diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile new file mode 100644 index 0000000..14c27a9 --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/Makefile @@ -0,0 +1,30 @@ +# +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +CFG_TEE_TA_LOG_LEVEL ?= 4 + +# The UUID for the Trusted Application +BINARY=b0f42504-01ec-11ec-9a03-0242ac130003 + +# OP-TEE-specifc defines for the target build +# Must have the following defined for OP-TEE's build system. These are defined +# by the top level makefile, but can be overridden locally if desired. +# - CROSS_COMPILE: prefix of compiler, eg arm-linux-gnueabihf- +# - PLATFORM: OP-TEE platform enumeration, eg vexpress-qemu_virt +# - TEEC_EXPORT: path to libteec.so in OP-TEE client build output +# - TA_DEV_KIT_DIR: path to OP-TEE TA dev kit makefiles +# - O: optional output directory specification +.EXPORT_ALL_VARIABLES: +TEEC_EXPORT ?= $(OPTEE_DIR)/out-br/build/optee_client_ext-1.0/libteec +PATH := $(PATH):$(OPTEE_DIR)/toolchains/aarch32/bin/:$(OPTEE_DIR)/toolchains/aarch64/bin/ +O := ./out + +include $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk + +ifeq ($(wildcard $(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk), ) +clean: + @echo 'Note: $$(TA_DEV_KIT_DIR)/mk/ta_dev_kit.mk not found, cannot clean TA' + @echo 'Note: TA_DEV_KIT_DIR=$(TA_DEV_KIT_DIR)' +endif diff --git a/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk new file mode 100644 index 0000000..49898ac --- /dev/null +++ b/oemcrypto/opk/ports/optee/ta/wtpi_test_ta/sub.mk @@ -0,0 +1,34 @@ +# +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +# +OEMCRYPTO=../../../../.. +ODK=$(OEMCRYPTO)/odk +OPK=$(OEMCRYPTO)/opk +SER=$(OPK)/serialization +OEMCRYPTO_TA=$(OPK)/oemcrypto_ta +OPTEE_PORT=$(OPK)/ports/optee +TEST_TA=$(OPTEE_PORT)/ta/wtpi_test_ta +COMMON=$(OPTEE_PORT)/ta/common + +global-incdirs-y += $(OEMCRYPTO)/include +global-incdirs-y += $(ODK)/include +global-incdirs-y += $(ODK)/src +global-incdirs-y += $(SER)/common/include +global-incdirs-y += $(SER)/os_interfaces +global-incdirs-y += $(OEMCRYPTO_TA) +global-incdirs-y += $(OEMCRYPTO_TA)/wtpi +global-incdirs-y += $(TEST_TA)/include +global-incdirs-y += $(COMMON) + +srcs-y += wtpi_test_ta.c +srcs-y += $(SER)/tee/tee_tos_stubs.c + +libdirs += $(OEMCRYPTO)/../out/opk_optee/debug +libdirs += $(OEMCRYPTO)/../out/opk_optee/debug/obj.target/oemcrypto/opk/oemcrypto_ta/wtpi_test/tee + +libnames += odk +libnames += opk_tee_wtpi_test +libnames += oemcrypto_ta +libnames += wtpi_impl diff --git a/oemcrypto/opk/strict_compiler_flags.gypi b/oemcrypto/opk/strict_compiler_flags.gypi new file mode 100644 index 0000000..0c5318e --- /dev/null +++ b/oemcrypto/opk/strict_compiler_flags.gypi @@ -0,0 +1,27 @@ +# Copyright 2019 Google LLC.All Rights Reserved.This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. + +{ + 'target_defaults': { + # OPK is written in pure C99 aside from a few places where we use the + # preprocessor to include compiler-specific features only on supporting + # compilers. The core OPK code should compile on the most pure, pedantic C99 + # compiler, and to check this, we turn on flags to keep ourselves honest by + # by using the maximum compiler pedantry. + 'cflags': [ + '-pedantic', + '-pedantic-errors', + '-Werror=pedantic', + ], + 'cflags_c': [ + '-std=c99', + ], + # To make sure no other GYP file can override our C version, we filter out + # all other langauge standards here. + 'cflags_c/': [ + ['exclude', '-std=*'], + ['include', '-std=c99'], + ], + }, +} diff --git a/oemcrypto/ref/oec_ref.gypi b/oemcrypto/ref/oec_ref.gypi index 1c34318..889bfbe 100644 --- a/oemcrypto/ref/oec_ref.gypi +++ b/oemcrypto/ref/oec_ref.gypi @@ -8,6 +8,7 @@ '<(oemcrypto_dir)/include', '<(oemcrypto_dir)/ref/src', '<(oemcrypto_dir)/odk/include', + '<(oemcrypto_dir)/opk/oemcrypto_ta', '<(util_dir)/include', ], 'direct_dependent_settings': { @@ -18,13 +19,19 @@ ], }, 'sources': [ + '<(oemcrypto_dir)/opk/oemcrypto_ta/oemcrypto_wall_clock.c', + '<(oemcrypto_dir)/ref/src/cmac.cpp', '<(oemcrypto_dir)/ref/src/keys.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_auth_ref.cpp', + '<(oemcrypto_dir)/ref/src/oemcrypto_drm_key.cpp', + '<(oemcrypto_dir)/ref/src/oemcrypto_ecc_key.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_engine_ref.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_key_ref.cpp', + '<(oemcrypto_dir)/ref/src/oemcrypto_key_deriver.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_keybox_ref.cpp', + '<(oemcrypto_dir)/ref/src/oemcrypto_oem_cert.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_ref.cpp', - '<(oemcrypto_dir)/ref/src/oemcrypto_rsa_key_shared.cpp', + '<(oemcrypto_dir)/ref/src/oemcrypto_rsa_key.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_session.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_session_key_table.cpp', '<(oemcrypto_dir)/ref/src/oemcrypto_usage_table_ref.cpp', diff --git a/oemcrypto/ref/oec_ref_unittests.gypi b/oemcrypto/ref/oec_ref_unittests.gypi new file mode 100644 index 0000000..c499025 --- /dev/null +++ b/oemcrypto/ref/oec_ref_unittests.gypi @@ -0,0 +1,20 @@ +# Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine License +# Agreement. +{ + 'include_dirs': [ + '<(oemcrypto_dir)/include', + '<(oemcrypto_dir)/ref/src', + '<(oemcrypto_dir)/ref/test', + '<(util_dir)/include', + ], + 'sources': [ + '<(oemcrypto_dir)/ref/test/cmac_unittest.cpp', + '<(oemcrypto_dir)/ref/test/oem_cert_test.cpp', + '<(oemcrypto_dir)/ref/test/oemcrypto_ecc_key_unittest.cpp', + '<(oemcrypto_dir)/ref/test/oemcrypto_oem_cert_unittest.cpp', + '<(oemcrypto_dir)/ref/test/oemcrypto_ref_test_utils.cpp', + '<(oemcrypto_dir)/ref/test/oemcrypto_rsa_key_unittest.cpp', + '<(oemcrypto_dir)/ref/test/oemcrypto_wvcrc32_unittest.cpp', + ], +} diff --git a/oemcrypto/ref/src/cmac.cpp b/oemcrypto/ref/src/cmac.cpp new file mode 100644 index 0000000..ffc73b3 --- /dev/null +++ b/oemcrypto/ref/src/cmac.cpp @@ -0,0 +1,171 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include "cmac.h" + +#include + +#include "log.h" +#include "scoped_object.h" + +namespace wvoec_ref { +namespace { +using ScopedCmacCtx = ScopedObject; +constexpr size_t kAes128KeySize = 16; +constexpr size_t kAes256KeySize = 32; +constexpr size_t kCmacOutputSize = 16; + +// Gets the appropriate AES block cipher for the CMAC algortihm +// based on the key size. +// Ownership of the pointer returned by this function is retained by +// the OpenSSL/BoringSSL framework. +const EVP_CIPHER* KeySizeToCipher(size_t key_size) { + switch (key_size) { + case kAes128KeySize: + return EVP_aes_128_cbc(); + case kAes256KeySize: + return EVP_aes_256_cbc(); + } + LOGE("Unexpected key size: size = %zu", key_size); + return nullptr; +} +} // namespace + +// static +std::unique_ptr Cmac::Create(const uint8_t* key, size_t key_size) { + std::unique_ptr cmac; + if (key == nullptr) { + LOGE("CMAC key is null"); + return cmac; + } + if (key_size != kAes128KeySize && key_size != kAes256KeySize) { + LOGE("Invalid CMAC key size: size = %zu", key_size); + return cmac; + } + cmac.reset(new Cmac()); + if (!cmac->Init(key, key_size)) { + cmac.reset(); + } + return cmac; +} + +// static +std::unique_ptr Cmac::Create(const std::vector& key) { + if (key.empty()) { + LOGE("CMAC key is empty"); + return std::unique_ptr(); + } + return Create(key.data(), key.size()); +} + +bool Cmac::Init(const uint8_t* key, size_t key_size) { + const EVP_CIPHER* const cipher = KeySizeToCipher(key_size); + if (cipher == nullptr) { + LOGE("Failed to get block cipher for CMAC"); + return false; + } + ScopedCmacCtx ctx(CMAC_CTX_new()); + if (!ctx) { + LOGE("Failed allocate CMAC CTX"); + return false; + } + if (!CMAC_Init(ctx.get(), key, key_size, cipher, nullptr)) { + LOGE("Failed to initialize CMAC CTX"); + return false; + } + ctx_ = ctx.release(); + ready_ = true; + return true; +} + +bool Cmac::Update(const uint8_t* data, size_t data_length) { + if (data == nullptr) { + LOGE("Data is null"); + return false; + } + if (data_length == 0) { + return true; + } + if (!ready_) { + LOGE("CMAC must be reset before updating"); + return false; + } + if (!CMAC_Update(ctx_, data, data_length)) { + LOGE("Failed to update CMAC CTX"); + ready_ = false; + return false; + } + return true; +} + +bool Cmac::Update(const std::vector& data) { + return Update(data.data(), data.size()); +} + +bool Cmac::Update(uint8_t datum) { return Update(&datum, 1); } + +bool Cmac::Finalize(std::vector* mac) { + if (mac == nullptr) { + LOGE("Output MAC buffer is null"); + return false; + } + mac->clear(); + return FinalizeAppend(mac); +} + +bool Cmac::FinalizeAppend(std::vector* mac) { + if (mac == nullptr) { + LOGE("Output MAC buffer is null"); + return false; + } + if (!ready_) { + LOGE("CMAC must be reset before finalizing"); + return false; + } + const size_t end = mac->size(); + size_t mac_size = kCmacOutputSize; + mac->resize(end + mac_size); + if (!CMAC_Final(ctx_, &mac->at(end), &mac_size)) { + LOGE("Failed to finalize CMAC CTX"); + mac->resize(end); + ready_ = false; + return false; + } + ready_ = false; + return true; +} + +#ifdef OPENSSL_IS_BORINGSSL +// BoringSSL allows for resetting a CMAC context explicitly, whereas +// OpenSSL does so by reinitializing using all nulls/zeros. This +// causes segfaults on systems using BoringSSL. +void Cmac::Reset() { + if (!CMAC_Reset(ctx_)) { + LOGE("Failed to reset CMAC CTX"); + ready_ = false; + } else { + ready_ = true; + } +} +#else // OpenSSL is OpenSSL +void Cmac::Reset() { + if (!CMAC_Init(ctx_, nullptr, 0, nullptr, nullptr)) { + LOGE("Failed to reset CMAC CTX"); + ready_ = false; + } else { + ready_ = true; + } +} +#endif + +Cmac::~Cmac() { + if (ctx_ != nullptr) { + CMAC_CTX_free(ctx_); + ctx_ = nullptr; + } + ready_ = false; +} +} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/cmac.h b/oemcrypto/ref/src/cmac.h new file mode 100644 index 0000000..b5582a7 --- /dev/null +++ b/oemcrypto/ref/src/cmac.h @@ -0,0 +1,62 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef CMAC_H_ +#define CMAC_H_ + +#include +#include + +#include +#include + +#include + +namespace wvoec_ref { + +class Cmac { + public: + // Creates an AES-128-CMAC or an AES-256-CMAC depending on |key_size|. + // Returns an empty pointer if the key size is not valid. + static std::unique_ptr Create(const uint8_t* key, size_t key_size); + static std::unique_ptr Create(const std::vector& key); + + // Updates the CMAC with more data. This allows for streaming or + // scatter-gather based MAC generation. + // Returns true if the data was updated successfully and false + // if any unexpected errors occur. + bool Update(const uint8_t* data, size_t data_length); + bool Update(const std::vector& data); + bool Update(uint8_t datum); + + // Generates the final MAC and stores it in the |mac| output + // parameter. + // After finalizing, one must reset the Cmac instance before it + // can digest additional information. + bool Finalize(std::vector* mac); + // Similar to Finalize() except that the output is appended to + // the end of the provided |mac| buffer. + bool FinalizeAppend(std::vector* mac); + + // Clears the underlying CMAC without clearing the key. Resetting + // it to its post-initialization state. + void Reset(); + + ~Cmac(); + + private: + Cmac() {} + + // Assumes |key_size| is a valid AES-128 or AES-256 key. + bool Init(const uint8_t* key, size_t key_size); + + CMAC_CTX* ctx_ = nullptr; + bool ready_ = false; +}; + +} // namespace wvoec_ref + +#endif // CMAC_H_ diff --git a/oemcrypto/ref/src/oemcrypto_auth_ref.cpp b/oemcrypto/ref/src/oemcrypto_auth_ref.cpp index f3d9a45..8cebca1 100644 --- a/oemcrypto/ref/src/oemcrypto_auth_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_auth_ref.cpp @@ -6,14 +6,20 @@ // #include "oemcrypto_auth_ref.h" +#include + +#include #include #include "keys.h" #include "log.h" -#include "oemcrypto_rsa_key_shared.h" +namespace wvoec_ref { namespace { +// Fake device ID which is to be returned inplace of a real ID. +const std::string kFakeDeviceId = "device_with_no_keybox"; + // A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format // This is the RSA Test Key. This key is not derived // from any Widevine authentication root. @@ -171,33 +177,271 @@ static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = { 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03 }; - } // namespace -namespace wvoec_ref { - -AuthenticationRoot::AuthenticationRoot(OEMCrypto_ProvisioningMethod method) : - provisioning_method_(method), - use_test_keybox_(false) { - if ((provisioning_method_ == OEMCrypto_DrmCertificate) && - !rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) { - // This error message is OK in unit tests which use test certificate. - LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a " - "keybox, but the certificate could not be loaded."); +bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) { + if (prov_method_ != OEMCrypto_ProvisioningError) { + // If provisioning method is something other than ProvisioningError + // indicates it has already been initialized before. Must + // existing data. + drm_cert_key_.reset(); + test_drm_cert_key_.reset(); + keybox_.reset(); + test_keybox_.reset(); + oem_cert_.reset(); + oem_cert_key_.reset(); + } + prov_method_ = method; + switch (method) { + case OEMCrypto_DrmCertificate: { + std::unique_ptr key = + RsaPrivateKey::Load(kPrivateKey, kPrivateKeySize); + if (key) { + drm_cert_key_ = std::move(key); + } else { + // This error message is OK in unit tests which use test certificate. + LOGE( + "FATAL ERROR: Platform uses a baked-in certificate instead of a " + "keybox, but the certificate could not be loaded."); + } + return true; + } + case OEMCrypto_Keybox: + case OEMCrypto_OEMCertificate: + // Nothing to do yet. + return true; + case OEMCrypto_ProvisioningError: + default: { + LOGE("Invalid provisioning method: method = %d", + static_cast(method)); + prov_method_ = OEMCrypto_ProvisioningError; + return false; + } } } -KeyboxError AuthenticationRoot::ValidateKeybox() { - return keybox().Validate(); +bool AuthenticationRoot::IsValid() const { + switch (prov_method_) { + case OEMCrypto_DrmCertificate: { + return HasDrmCertKey() && HasDeviceKey(); + } + case OEMCrypto_Keybox: { + return HasDeviceKey(); + } + case OEMCrypto_OEMCertificate: { + return HasOemCertKey() && HasDeviceKey(); + } + default: { + LOGE("Root of trust is not properly initialized"); + return false; + } + } } -bool AuthenticationRoot::LoadTestRsaKey() { - return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048, - sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); +OEMCryptoResult AuthenticationRoot::IsKeyboxOrOemCertValid() const { + switch (prov_method_) { + case OEMCrypto_Keybox: { + WvKeybox* kb = keybox(); + if (kb == nullptr) { + LOGW("Keybox is missing, requires keybox provisioning"); + return OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING; + } + return kb->IsKeyboxValid(); + } + case OEMCrypto_OEMCertificate: { + if (!oem_cert_) { + LOGW("OEM cert is not installed"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return oem_cert_->IsCertificateValid(); + } + case OEMCrypto_DrmCertificate: { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + default: + LOGE("Root of trust is not properly initialized"); + return OEMCrypto_ERROR_SYSTEM_INVALIDATED; + } } -bool AuthenticationRoot::Validate() { - return NO_ERROR == ValidateKeybox(); +OEMCryptoResult AuthenticationRoot::GetDeviceId( + uint8_t* device_id, size_t* device_id_length) const { + WvKeybox* kb = keybox(); + if (kb != nullptr) { + return kb->GetDeviceId(device_id, device_id_length); + } + if (prov_method_ == OEMCrypto_Keybox) { + // Keybox devices must have keybox for the source of the device + // ID. + LOGE("Expected keybox to be set for a device ID"); + return OEMCrypto_ERROR_NO_DEVICEID; + } + // For non-Keybox devices use fake device ID. + if (device_id_length == nullptr) { + LOGE("Output device ID length is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (device_id == nullptr && *device_id_length > 0) { + LOGE("Output device ID buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (*device_id_length < kFakeDeviceId.size()) { + *device_id_length = kFakeDeviceId.size(); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *device_id_length = kFakeDeviceId.size(); + memcpy(device_id, kFakeDeviceId.data(), kFakeDeviceId.size()); + return OEMCrypto_SUCCESS; } +std::vector AuthenticationRoot::DeviceId() const { + WvKeybox* kb = keybox(); + if (kb != nullptr) { + return kb->DeviceId(); + } + if (prov_method_ == OEMCrypto_Keybox) { + LOGE("Expected keybox to be set for a device ID"); + return std::vector(); + } + return std::vector(kFakeDeviceId.begin(), kFakeDeviceId.end()); +} + +std::vector AuthenticationRoot::DeviceKey() const { + WvKeybox* kb = keybox(); + if (kb != nullptr) { + return kb->DeviceKey(); + } + LOGE("No device key has been set"); + return std::vector(); +} + +bool AuthenticationRoot::HasDeviceKey() const { return keybox() != nullptr; } + +void AuthenticationRoot::Clear() { + RemoveTestRsaKey(); + RemoveTestKeybox(); +} + +OEMCryptoResult AuthenticationRoot::LoadTestRsaKey() { + if (prov_method_ != OEMCrypto_DrmCertificate) { + LOGE("System does not support DRM certificates"); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (test_drm_cert_key_) { + LOGE("Test RSA key is already loaded"); + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + std::unique_ptr key = + RsaPrivateKey::Load(kTestRSAPKCS8PrivateKeyInfo2_2048, + sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); + if (!key) { + LOGE("Failed to load test RSA key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + test_drm_cert_key_ = std::move(key); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult AuthenticationRoot::IsKeyboxValid() const { + WvKeybox* kb = keybox(); + if (kb == nullptr) { + return OEMCrypto_ERROR_KEYBOX_INVALID; + } + return kb->IsKeyboxValid(); +} + +OEMCryptoResult AuthenticationRoot::InstallKeybox(const uint8_t* keybox_data, + size_t keybox_length) { + if (keybox_) { + LOGE("Keybox already installed"); + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + const OEMCryptoResult result = + WvKeybox::ValidateData(keybox_data, keybox_length); + if (result != OEMCrypto_SUCCESS) { + LOGE("Cannot install an invalid keybox"); + return result; + } + keybox_ = WvKeybox::Create(keybox_data, keybox_length); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult AuthenticationRoot::InstallTestKeybox( + const uint8_t* keybox_data, size_t keybox_length) { + if (prov_method_ != OEMCrypto_Keybox) { + LOGE("System does not support keybox"); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (test_keybox_) { + LOGE("Test keybox already installed"); + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + const OEMCryptoResult result = + WvKeybox::ValidateData(keybox_data, keybox_length); + if (result != OEMCrypto_SUCCESS) { + LOGE("Cannot install an invalid test keybox"); + return result; + } + test_keybox_ = WvKeybox::Create(keybox_data, keybox_length); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult AuthenticationRoot::GetKeyData(uint8_t* key_data, + size_t* key_data_length) const { + if (prov_method_ != OEMCrypto_Keybox) { + LOGE("System does not support keybox"); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + WvKeybox* kb = keybox(); + if (kb == nullptr) { + LOGE("No keybox to be set for source of key data"); + return OEMCrypto_ERROR_NO_KEYDATA; + } + return kb->GetKeyData(key_data, key_data_length); +} + +OEMCryptoResult AuthenticationRoot::InstallOemCertificate( + const uint8_t* private_key, size_t private_key_size, + const uint8_t* public_cert, size_t public_cert_size) { + if (prov_method_ != OEMCrypto_OEMCertificate) { + LOGE("System does not support OEM certificates"); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (oem_cert_ || oem_cert_key_) { + LOGE("OEM certificate is already installed"); + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + std::unique_ptr oem_cert = OemCertificate::Create( + private_key, private_key_size, public_cert, public_cert_size); + if (!oem_cert) { + LOGE("Failed to install OEM certificate as root of trust"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (oem_cert->key_type() != OemCertificate::kRsa) { + LOGE("Only RSA-based OEM certificates supported"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + std::unique_ptr oem_cert_key = + RsaPrivateKey::Load(oem_cert->GetPrivateKey()); + if (!oem_cert_key) { + LOGE("Failed to parse OEM certificate private key"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + oem_cert_ = std::move(oem_cert); + oem_cert_key_ = std::move(oem_cert_key); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult AuthenticationRoot::GetOemPublicCertificate( + uint8_t* public_cert, size_t* public_cert_length) const { + if (prov_method_ != OEMCrypto_OEMCertificate) { + LOGE("System does not support OEM certificates"); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (!oem_cert_) { + LOGE("OEM certificate is not installed"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return oem_cert_->GetPublicCertificate(public_cert, public_cert_length); +} } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_auth_ref.h b/oemcrypto/ref/src/oemcrypto_auth_ref.h index 4e8ede7..f436c3d 100644 --- a/oemcrypto/ref/src/oemcrypto_auth_ref.h +++ b/oemcrypto/ref/src/oemcrypto_auth_ref.h @@ -8,74 +8,170 @@ #define OEMCRYPTO_AUTH_REF_H_ #include + #include #include -#include - #include "OEMCryptoCENC.h" // Needed for enums only. #include "disallow_copy_and_assign.h" -#include "oemcrypto_key_ref.h" #include "oemcrypto_keybox_ref.h" -#include "oemcrypto_rsa_key_shared.h" -#include "oemcrypto_types.h" +#include "oemcrypto_oem_cert.h" +#include "oemcrypto_rsa_key.h" namespace wvoec_ref { - +// The AuthenticationRoot class contains the OEMCrypto information +// which makes up the "root of trust" of a device. class AuthenticationRoot { public: - explicit AuthenticationRoot(OEMCrypto_ProvisioningMethod method); + AuthenticationRoot() {} ~AuthenticationRoot() {} - bool Validate(); + // Initializes the root of authentication for the provided + // |method|. This will clear any previously initialied data. + bool Initialize(OEMCrypto_ProvisioningMethod method); - KeyboxError ValidateKeybox(); + // General root of trust API. - bool InstallKeybox(const uint8_t* keybox_data, size_t keybox_length) { - return keybox().InstallKeybox(keybox_data, keybox_length); + // Checks that the auth root has been properly initialized and can + // be used by the rest of OEMCrypto for the current provisioning + // method. + bool IsValid() const; + + // Checks the validity of the underlying Keybox or OEM Certificate + // depending on the provisioning method. + // Similar to the expected behavior of OEMCrypto_IsKeyboxOrOEMCertValid(). + OEMCryptoResult IsKeyboxOrOemCertValid() const; + + // Gets the device ID from the root of trust. + // Similar to the expected behavior of OEMCrypto_GetDeviceID(). + OEMCryptoResult GetDeviceId(uint8_t* device_id, + size_t* device_id_length) const; + + // Returns the device ID from the root of trust. Intended to be used + // for core message generation. + std::vector DeviceId() const; + + // Returns the device key from the root of trust. For keybox-based + // devices, this is the device key from the keybox (or test keybox + // if installed). For devices that use a non-keybox provisioning + // method, this will be a device specific key. + std::vector DeviceKey() const; + + // Check for the existence of a device key. + bool HasDeviceKey() const; + + // Clears any test data inside this root of trust. + void Clear(); + + // DRM Certificate-based root of trust API. + + // Returns the shared RSA private key from the built-in DRM + // Certificate. + std::shared_ptr ShareDrmCertKey() { + return test_drm_cert_key_ ? test_drm_cert_key_ : drm_cert_key_; + } + RsaPrivateKey* DrmCertKey() const { + return test_drm_cert_key_ ? test_drm_cert_key_.get() : drm_cert_key_.get(); + } + bool HasDrmCertKey() const { return test_drm_cert_key_ || drm_cert_key_; } + + // Loads the system's built-in RSA key. Only implemented for + // devices that are that pre-provisioned with a built-in DRM + // Certificate, + // This method implements the expected behavior of + // OEMCrypto_LoadTestRSAKey(). + OEMCryptoResult LoadTestRsaKey(); + + // Removes any installed test RSA key. + void RemoveTestRsaKey() { test_drm_cert_key_.reset(); } + + // Keybox-based root of trust API. + + // Returns the currently installed keybox (or test keybox) if any + // present. The test keybox takes priority over the standard. + WvKeybox* keybox() const { + return test_keybox_ ? test_keybox_.get() : keybox_.get(); } - const std::vector& DeviceKey(bool use_real_keybox = false) { - return use_real_keybox ? real_keybox().device_key() : - keybox().device_key(); + // Checks the validity of the keybox regardless of the provisioning + // method. + OEMCryptoResult IsKeyboxValid() const; + + // Installs a clear WV keybox as the root of trust. + // A keybox can only be installed once, however, the provisioning + // method stated at initialization remains the same. + // + // This method is similar to the expected behavior of + // OEMCrypto_InstallKeyboxOrOEMCert() for keybox devices except + // that the keybox provided here must be decrypted before installing. + OEMCryptoResult InstallKeybox(const uint8_t* keybox_data, + size_t keybox_length); + + // Installs a clear test WV keybox. Only settable for devices that + // uses a keybox for provisioning. + // + // This method is similar to the expected behavior of + // OEMCrypto_LoadTestKeybox() for keybox devices except that + // the keybox provided here must be decrypted before installing. + OEMCryptoResult InstallTestKeybox(const uint8_t* keybox_data, + size_t keybox_length); + + // Removes any installed test keybox. + void RemoveTestKeybox() { test_keybox_.reset(); } + // Removes all keyboxes. + void RemoveKeybox() { + keybox_.reset(); + test_keybox_.reset(); } - const std::vector& DeviceId() { - return keybox().device_id(); - } + // Gets the keybox key data. + // Implements the expected behavior of OEMCrypto_GetKeyData(). + OEMCryptoResult GetKeyData(uint8_t* key_data, size_t* key_data_length) const; - size_t DeviceTokenLength() { - return keybox().key_data_length(); - } + // OEM Certificate-base root of trust API. - const uint8_t* DeviceToken() { - return keybox().key_data(); - } + // Installs an OEM certificate as the root of trust. The provided + // private key and public cert are parsed, but not validated. The + // private key will be made available for sessions to load. + OEMCryptoResult InstallOemCertificate(const uint8_t* private_key, + size_t private_key_size, + const uint8_t* public_cert, + size_t public_cert_size); - WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; } - bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) { - use_test_keybox_ = true; - return test_keybox_.InstallKeybox(keybox_data, keybox_length); - } + // For OEM Cert-based devices, returns the OEM Public Certificate + // component of the OEM Certificate. + // This method implements the expected behavior of + // OEMCrypto_GetOEMPublicCertificate(). + OEMCryptoResult GetOemPublicCertificate(uint8_t* public_cert, + size_t* public_cert_length) const; - RSA_shared_ptr& SharedRsaKey() { return rsa_key_; } - RSA* rsa_key() { return rsa_key_.get(); } - bool LoadTestRsaKey(); - void Clear() { use_test_keybox_ = false; } + // Returns the OEM private key. Intended to be used when loading + // the OEM private key into a session. + // Should only be called for devices that use OEM Certificates + // for provisioning. + std::shared_ptr ShareOemCertKey() { return oem_cert_key_; } + RsaPrivateKey* OemCertKey() const { return oem_cert_key_.get(); } + bool HasOemCertKey() const { return static_cast(oem_cert_key_); } private: - OEMCrypto_ProvisioningMethod provisioning_method_; - WvKeybox& real_keybox() { return keybox_; } + OEMCrypto_ProvisioningMethod prov_method_ = OEMCrypto_ProvisioningError; - WvKeybox keybox_; - WvKeybox test_keybox_; - bool use_test_keybox_; + // DRM certificate. + // If no keybox, this is the private key of the baked-in DRM + // Certificate. + std::shared_ptr drm_cert_key_; + std::shared_ptr test_drm_cert_key_; - RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate. + // Keybox data. + std::unique_ptr keybox_; + std::unique_ptr test_keybox_; + + // OEM certificate. + std::unique_ptr oem_cert_; + std::shared_ptr oem_cert_key_; CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot); }; - } // namespace wvoec_ref #endif // OEMCRYPTO_AUTH_REF_H_ diff --git a/oemcrypto/ref/src/oemcrypto_drm_key.cpp b/oemcrypto/ref/src/oemcrypto_drm_key.cpp new file mode 100644 index 0000000..d2acb35 --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_drm_key.cpp @@ -0,0 +1,184 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include "oemcrypto_drm_key.h" + +#include + +#include "OEMCryptoCENC.h" +#include "log.h" + +namespace wvoec_ref { +// static +std::unique_ptr DrmPrivateKey::Create( + std::shared_ptr&& rsa_key) { + if (!rsa_key) { + LOGE("No RSA key provided"); + return std::unique_ptr(); + } + std::unique_ptr drm_key(new DrmPrivateKey()); + drm_key->rsa_key_ = std::move(rsa_key); + return drm_key; +} + +// static +std::unique_ptr DrmPrivateKey::Create( + std::unique_ptr&& rsa_key) { + if (!rsa_key) { + LOGE("No RSA key provided"); + return std::unique_ptr(); + } + std::unique_ptr drm_key(new DrmPrivateKey()); + drm_key->rsa_key_ = std::move(rsa_key); + return drm_key; +} + +// static +std::unique_ptr DrmPrivateKey::Create( + std::shared_ptr&& ecc_key) { + if (!ecc_key) { + LOGE("No ECC key provided"); + return std::unique_ptr(); + } + std::unique_ptr drm_key(new DrmPrivateKey()); + drm_key->ecc_key_ = std::move(ecc_key); + return drm_key; +} + +// static +std::unique_ptr DrmPrivateKey::Create( + std::unique_ptr&& ecc_key) { + if (!ecc_key) { + LOGE("No ECC key provided"); + return std::unique_ptr(); + } + std::unique_ptr drm_key(new DrmPrivateKey()); + drm_key->ecc_key_ = std::move(ecc_key); + return drm_key; +} + +OEMCryptoResult DrmPrivateKey::GetSessionKey( + const uint8_t* key_source, size_t key_source_size, + std::vector* session_key) const { + if (session_key == nullptr) { + LOGE("Output session key is null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // RSA -> Decrypt session key. + if (rsa_key_) { + if (!(rsa_key_->allowed_schemes() & kSign_RSASSA_PSS)) { + LOGE("RSA key cannot be used for session key decryption"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + size_t session_key_size = rsa_key_->SessionKeyLength(); + session_key->resize(session_key_size); + const OEMCryptoResult res = rsa_key_->DecryptSessionKey( + key_source, key_source_size, session_key->data(), &session_key_size); + if (res != OEMCrypto_SUCCESS) { + session_key->clear(); + return res; + } + session_key->resize(session_key_size); + return OEMCrypto_SUCCESS; + } + // ECC -> ECDH. + // Step 1: Parse |key_source| as ECC key. + std::unique_ptr ephemeral_ecc_key = + EccPublicKey::Load(key_source, key_source_size); + if (!ephemeral_ecc_key) { + LOGE("Failed to load server's ephemeral ECC key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2: Derive session key. + size_t session_key_size = ecc_key_->SessionKeyLength(); + session_key->resize(session_key_size); + const OEMCryptoResult res = ecc_key_->DeriveSessionKey( + *ephemeral_ecc_key, session_key->data(), &session_key_size); + if (res != OEMCrypto_SUCCESS) { + session_key->clear(); + return res; + } + session_key->resize(session_key_size); + return OEMCrypto_SUCCESS; +} + +std::vector DrmPrivateKey::GetSessionKey( + const std::vector& key_source) const { + // RSA -> Decrypt session key. + if (rsa_key_) { + if (!(rsa_key_->allowed_schemes() & kSign_RSASSA_PSS)) { + LOGE("RSA key cannot be used for session key decryption"); + return std::vector(); + } + return rsa_key_->DecryptSessionKey(key_source); + } + // ECC -> ECDH. + // Step 1: Parse |key_source| as ECC key. + std::unique_ptr ephemeral_ecc_key = + EccPublicKey::Load(key_source); + if (!ephemeral_ecc_key) { + LOGE("Failed to load server's ephemeral ECC key"); + return std::vector(); + } + // Step 2: Derive session key. + return ecc_key_->DeriveSessionKey(*ephemeral_ecc_key); +} + +std::vector DrmPrivateKey::GetEncryptionKey( + const std::vector& key_source) const { + if (!rsa_key_) { + LOGE("Only RSA DRM keys can derive an encryption key"); + return std::vector(); + } + return rsa_key_->DecryptEncryptionKey(key_source); +} + +OEMCryptoResult DrmPrivateKey::GenerateSignature( + const uint8_t* message, size_t message_length, uint8_t* signature, + size_t* signature_length) const { + if (rsa_key_) { + return rsa_key_->GenerateSignature(message, message_length, kRsaPssDefault, + signature, signature_length); + } + return ecc_key_->GenerateSignature(message, message_length, signature, + signature_length); +} + +std::vector DrmPrivateKey::GenerateSignature( + const std::vector& message) const { + if (rsa_key_) { + return rsa_key_->GenerateSignature(message, kRsaPssDefault); + } + return ecc_key_->GenerateSignature(message); +} + +size_t DrmPrivateKey::SignatureSize() const { + if (rsa_key_) { + return rsa_key_->SignatureSize(); + } + return ecc_key_->SignatureSize(); +} + +OEMCryptoResult DrmPrivateKey::GenerateRsaSignature( + const uint8_t* message, size_t message_length, uint8_t* signature, + size_t* signature_length) const { + if (!rsa_key_) { + LOGE("Only RSA DRM keys can generate PKCS1 signatures"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + return rsa_key_->GenerateSignature(message, message_length, kRsaPkcs1Cast, + signature, signature_length); +} + +std::vector DrmPrivateKey::GenerateRsaSignature( + const std::vector& message) const { + if (!rsa_key_) { + LOGE("Only RSA DRM keys can generate PKCS1 signatures"); + return std::vector(); + } + return rsa_key_->GenerateSignature(message, kRsaPkcs1Cast); +} +} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_drm_key.h b/oemcrypto/ref/src/oemcrypto_drm_key.h new file mode 100644 index 0000000..7481a64 --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_drm_key.h @@ -0,0 +1,85 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef OEMCRYPTO_DRM_KEY_H_ +#define OEMCRYPTO_DRM_KEY_H_ + +#include +#include +#include + +#include "OEMCryptoCENCCommon.h" +#include "oemcrypto_ecc_key.h" +#include "oemcrypto_rsa_key.h" + +namespace wvoec_ref { + +// DRM private key performs all of the operations required by an +// OEMCrypto session's RSA/ECC private key. +class DrmPrivateKey { + public: + // Create an RSA-based DRM key. + static std::unique_ptr Create( + std::shared_ptr&& rsa_key); + static std::unique_ptr Create( + std::unique_ptr&& rsa_key); + // Create an ECC-based DRM key. + static std::unique_ptr Create( + std::shared_ptr&& ecc_key); + static std::unique_ptr Create( + std::unique_ptr&& ecc_key); + + bool IsRsaKey() const { return static_cast(rsa_key_); } + bool IsEccKey() const { return static_cast(ecc_key_); } + + // Generates a session key from the key source. + // For RSA keys, |key_source| is an encrypted session key. + // For ECC keys, |key_source| is a ephemeral public key to be + // used in ECDH. + OEMCryptoResult GetSessionKey(const uint8_t* key_source, + size_t key_source_size, + std::vector* session_key) const; + std::vector GetSessionKey( + const std::vector& key_source) const; + + // Generates a encryption key from the key source. + // For RSA keys, |key_source| is an encrypted encryption key. + // For ECC keys, this method is not supported. + std::vector GetEncryptionKey( + const std::vector& key_source) const; + + // Generates a signature for the provided message. + // For RSA keys, the signature is RSASSA-PSS. + // For ECC keys, the signature is ECDSA. + OEMCryptoResult GenerateSignature(const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length) const; + std::vector GenerateSignature( + const std::vector& message) const; + size_t SignatureSize() const; + + // Generates a signature for the provided message. + // For RSA keys, the signature is RSASSA-PKCS1. + // For ECC keys, this is not supported. + OEMCryptoResult GenerateRsaSignature(const uint8_t* message, + size_t message_length, + uint8_t* signature, + size_t* signature_length) const; + std::vector GenerateRsaSignature( + const std::vector& message) const; + + ~DrmPrivateKey() {} + + private: + DrmPrivateKey() {} + + // Only one will be set. + std::shared_ptr ecc_key_; + std::shared_ptr rsa_key_; +}; +} // namespace wvoec_ref + +#endif // OEMCRYPTO_DRM_KEY_H_ diff --git a/oemcrypto/ref/src/oemcrypto_ecc_key.cpp b/oemcrypto/ref/src/oemcrypto_ecc_key.cpp new file mode 100644 index 0000000..d3eee9b --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_ecc_key.cpp @@ -0,0 +1,845 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include "oemcrypto_ecc_key.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "scoped_object.h" + +namespace wvoec_ref { +namespace { +// Estimated max size (in bytes) of a serialized ECC key (public or +// private). These values are based on rough calculations for +// secp521r1 (largest of the supported curves) and should be slightly +// larger needed. +constexpr size_t kPrivateKeySize = 250; +constexpr size_t kPublicKeySize = 164; + +// 256 bit key, intended to be used with CMAC-AES-256. +constexpr size_t kEccSessionKeySize = 32; + +using ScopedBigNum = ScopedObject; +using ScopedBigNumCtx = ScopedObject; +using ScopedBio = ScopedObject; +using ScopedEcKey = ScopedObject; +using ScopedEvpMdCtx = ScopedObject; +using ScopedEvpPkey = ScopedObject; +using ScopedPrivateKeyInfo = + ScopedObject; +using ScopedSigPoint = ScopedObject; + +const EC_GROUP* GetEcGroup(EccCurve curve) { + // Creating a named EC_GROUP is an expensive operation, and they + // are always used in a manner which does not transfer ownership. + // Maintaining a process-wide set of supported EC groups reduces + // the overhead of group operations. + static std::mutex group_mutex; + static EC_GROUP* group_256 = nullptr; + static EC_GROUP* group_384 = nullptr; + static EC_GROUP* group_521 = nullptr; + std::lock_guard group_lock(group_mutex); + switch (curve) { + case kEccSecp256r1: { + if (group_256 == nullptr) { + LOGD("Creating secp256r1 group"); + // The curve secp256r1 was originally named prime256v1 + // in the X9.62 specification. + group_256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + assert(group_256 != nullptr); + } + return group_256; + } + case kEccSecp384r1: { + if (group_384 == nullptr) { + LOGD("Creating secp384r1 group"); + group_384 = EC_GROUP_new_by_curve_name(NID_secp384r1); + assert(group_384 != nullptr); + } + return group_384; + } + case kEccSecp521r1: { + if (group_521 == nullptr) { + LOGD("Creating secp521r1 group"); + group_521 = EC_GROUP_new_by_curve_name(NID_secp521r1); + assert(group_521 != nullptr); + } + return group_521; + } + default: + LOGE("Cannot get EC group for unknown curve: curve = %d", + static_cast(curve)); + return nullptr; + } +} + +// Determines which of the supported ECC curves the provided |key| +// belongs to. +// +// This is intended to be used on keys that have been deserialized +// from an ASN.1 structure which may have contained a key which is +// supported by OpenSSL/BoringSSL but not necessarily by OEMCrypto. +// +// If the key group is unknown to OEMCrypto or if an error occurs, +// kEccCurveUnknown is returned. +EccCurve GetCurveFromKeyGroup(const EC_KEY* key) { + ScopedBigNumCtx ctx(BN_CTX_new()); + if (!ctx) { + LOGE("Failed to allocate BN ctx"); + return kEccCurveUnknown; + } + const EC_GROUP* group = EC_KEY_get0_group(key); + if (group == nullptr) { + LOGE("Provided key does not have a group"); + return kEccCurveUnknown; + } + int rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp256r1), ctx.get()); + if (rc == 0) { + return kEccSecp256r1; + } + if (rc == -1) { + LOGE("Error occurred while checking against secp256r1"); + return kEccCurveUnknown; + } + + rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp384r1), ctx.get()); + if (rc == 0) { + return kEccSecp384r1; + } + if (rc == -1) { + LOGE("Error occurred while checking against secp384r1"); + return kEccCurveUnknown; + } + + rc = EC_GROUP_cmp(group, GetEcGroup(kEccSecp521r1), ctx.get()); + if (rc == 0) { + return kEccSecp521r1; + } + if (rc == -1) { + LOGE("Error occurred while checking against secp521r1"); + return kEccCurveUnknown; + } + + LOGW("Unsupported curve group"); + return kEccCurveUnknown; +} + +// Compares the public EC points of both keys to see if they are the +// equal. +// Both |public_key| and |private_key| must be of the same group. +bool IsMatchingKeyPair(const EC_KEY* public_key, const EC_KEY* private_key) { + ScopedBigNumCtx ctx(BN_CTX_new()); + if (!ctx) { + LOGE("Failed to allocate BN ctx"); + return false; + } + // Returns: 1 if not equal, 0 if equal, -1 if error. + const int res = EC_POINT_cmp(EC_KEY_get0_group(public_key), + EC_KEY_get0_public_key(public_key), + EC_KEY_get0_public_key(private_key), ctx.get()); + if (res == -1) { + LOGE("Error occurred comparing keys"); + } + return res == 0; +} + +// Performs a SHA2 digest on the provided |message| and outputs the +// computed hash to |digest|. +// The digest algorithm used depends on which curve is used. +// - secp256r1 -> SHA-256 +// - secp384r1 -> SHA-384 +// - secp521r1 -> SHA-512 +// This function assumes that all parameters are valid. +// Returns true on success, false otherwise. +bool DigestMessage(EccCurve curve, const uint8_t* message, size_t message_size, + std::vector* digest) { + const EVP_MD* md_engine = nullptr; + switch (curve) { + case kEccSecp256r1: { + md_engine = EVP_sha256(); + break; + } + case kEccSecp384r1: { + md_engine = EVP_sha384(); + break; + } + case kEccSecp521r1: { + md_engine = EVP_sha512(); + break; + } + case kEccCurveUnknown: + // This case is to suppress compiler warnings. It will never + // occur. + break; + } + if (md_engine == nullptr) { + LOGE("Failed to get MD engine: curve = %d", static_cast(curve)); + return false; + } + + ScopedEvpMdCtx md_ctx(EVP_MD_CTX_new()); + if (!md_ctx) { + LOGE("Failed to create MD CTX"); + return false; + } + if (!EVP_DigestInit_ex(md_ctx.get(), md_engine, nullptr)) { + LOGE("Failed to init MD CTX"); + return false; + } + if (message_size > 0 && + !EVP_DigestUpdate(md_ctx.get(), message, message_size)) { + LOGE("Failed to update"); + return false; + } + digest->resize(EVP_MD_CTX_size(md_ctx.get()), 0); + const int res = EVP_DigestFinal_ex(md_ctx.get(), digest->data(), nullptr); + if (!res) { + LOGE("Failed to finalize"); + return false; + } + return true; +} + +// This KDF function is defined by OEMCrypto ECC specification. +// Function signature is based on the |kdf| parameter of +// ECDH_compute_key(). This function assumes that all pointer +// parameters are not null. +extern "C" void* WidevineEccKdf(const void* secret, size_t secret_length, + void* key, size_t* key_size) { + if (*key_size < kEccSessionKeySize) { + LOGE("Output buffer is too small: required = %zu, size = %zu", + kEccSessionKeySize, *key_size); + return nullptr; + } + std::vector digest; + if (!DigestMessage(kEccSecp256r1 /* SHA-256 */, + reinterpret_cast(secret), secret_length, + &digest)) { + LOGE("Cannot derive key: Failed to hash secret"); + return nullptr; + } + if (digest.size() != kEccSessionKeySize) { + LOGE("Unexpected hash size: actual = %zu, expected = %zu", digest.size(), + kEccSessionKeySize); + return nullptr; + } + *key_size = kEccSessionKeySize; + memcpy(key, digest.data(), *key_size); + return key; +} +} // namespace + +std::string EccCurveToString(EccCurve curve) { + switch (curve) { + case kEccSecp256r1: + return "secp256r1"; + case kEccSecp384r1: + return "secp384r1"; + case kEccSecp521r1: + return "secp521r1"; + case kEccCurveUnknown: + return "Unknown"; + } + return "Unknown(" + std::to_string(static_cast(curve)) + ")"; +} + +// static +std::unique_ptr EccPublicKey::New( + const EccPrivateKey& private_key) { + std::unique_ptr key(new EccPublicKey()); + if (!key->InitFromPrivateKey(private_key)) { + LOGE("Failed to initialize public key from private key"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr EccPublicKey::Load(const uint8_t* buffer, + size_t length) { + std::unique_ptr key; + if (buffer == nullptr) { + LOGE("Provided public key buffer is null"); + return key; + } + if (length == 0) { + LOGE("Provided public key buffer is zero length"); + return key; + } + key.reset(new EccPublicKey()); + if (!key->InitFromBuffer(buffer, length)) { + LOGE("Failed to initialize public key from buffer"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr EccPublicKey::Load(const std::string& buffer) { + if (buffer.empty()) { + LOGE("Provided public key buffer is empty"); + return std::unique_ptr(); + } + return Load(reinterpret_cast(buffer.data()), buffer.size()); +} + +// static +std::unique_ptr EccPublicKey::Load( + const std::vector& buffer) { + if (buffer.empty()) { + LOGE("Provided public key buffer is empty"); + return std::unique_ptr(); + } + return Load(buffer.data(), buffer.size()); +} + +bool EccPublicKey::IsMatchingPrivateKey( + const EccPrivateKey& private_key) const { + if (private_key.curve() != curve_) { + return false; + } + return IsMatchingKeyPair(GetEcKey(), private_key.GetEcKey()); +} + +OEMCryptoResult EccPublicKey::Serialize(uint8_t* buffer, + size_t* buffer_size) const { + if (buffer_size == nullptr) { + LOGE("Output buffer size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (buffer == nullptr && *buffer_size > 0) { + LOGE("Output buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + uint8_t* der_key = nullptr; + const int der_res = i2d_EC_PUBKEY(key_, &der_key); + if (der_res < 0) { + LOGE("Public key serialization failed"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (der_key == nullptr) { + LOGE("Encoded key is unexpectedly null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (der_res == 0) { + LOGE("Unexpected DER encoded size"); + OPENSSL_free(der_key); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + const size_t required_size = static_cast(der_res); + if (buffer == nullptr || *buffer_size < required_size) { + *buffer_size = required_size; + OPENSSL_free(der_key); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(buffer, der_key, required_size); + *buffer_size = required_size; + OPENSSL_free(der_key); + return OEMCrypto_SUCCESS; +} + +std::vector EccPublicKey::Serialize() const { + size_t key_size = kPublicKeySize; + std::vector key_data(key_size, 0); + const OEMCryptoResult res = Serialize(key_data.data(), &key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to serialize public key: result = %d", static_cast(res)); + key_data.clear(); + } else { + key_data.resize(key_size); + } + return key_data; +} + +OEMCryptoResult EccPublicKey::VerifySignature(const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length) const { + if (signature == nullptr || signature_length == 0) { + LOGE("Signature is missing"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (message == nullptr && message_length > 0) { + LOGE("Bad message data"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // Step 1: Parse signature. + const uint8_t* tp = signature; + ScopedSigPoint sig_point(d2i_ECDSA_SIG(nullptr, &tp, signature_length)); + if (!sig_point) { + LOGE("Failed to parse signature"); + // Most likely an invalid signature than an OpenSSL error. + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + // Step 2: Hash message + std::vector digest; + if (!DigestMessage(curve_, message, message_length, &digest)) { + LOGE("Failed to digest message"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 3: Verify signature + const int res = ECDSA_do_verify( + digest.data(), static_cast(digest.size()), sig_point.get(), key_); + if (res == -1) { + LOGE("Error occurred checking signature"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (res == 0) { + LOGD("Signature did not match"); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult EccPublicKey::VerifySignature( + const std::string& message, const std::string& signature) const { + if (signature.empty()) { + LOGE("Signature should not be empty"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return VerifySignature( + reinterpret_cast(message.data()), message.size(), + reinterpret_cast(signature.data()), signature.size()); +} + +OEMCryptoResult EccPublicKey::VerifySignature( + const std::vector& message, + const std::vector& signature) const { + if (signature.empty()) { + LOGE("Signature should not be empty"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return VerifySignature(message.data(), message.size(), signature.data(), + signature.size()); +} + +EccPublicKey::~EccPublicKey() { + if (key_ != nullptr) { + EC_KEY_free(key_); + key_ = nullptr; + } + curve_ = kEccCurveUnknown; +} + +bool EccPublicKey::InitFromBuffer(const uint8_t* buffer, size_t length) { + // Deserialize SubjectPublicKeyInfo + const uint8_t* tp = buffer; + ScopedEcKey key(d2i_EC_PUBKEY(nullptr, &tp, length)); + if (!key) { + LOGE("Failed to parse ECC key"); + return false; + } + // Verify key parameters and curve family. + const int check = EC_KEY_check_key(key.get()); + if (check == 0) { + LOGE("ECC key parameters are invalid"); + return false; + } else if (check == -1) { + LOGE("Failed to check ECC key"); + return false; + } + curve_ = GetCurveFromKeyGroup(key.get()); + if (curve_ == kEccCurveUnknown) { + LOGE("Failed to determine key group"); + return false; + } + // Required flags for IETF compliance. + EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED); + key_ = key.release(); + return true; +} + +bool EccPublicKey::InitFromPrivateKey(const EccPrivateKey& private_key) { + ScopedEcKey key(EC_KEY_new()); + if (!key) { + LOGE("Failed to allocate key"); + return false; + } + if (!EC_KEY_set_group(key.get(), EC_KEY_get0_group(private_key.GetEcKey()))) { + LOGE("Failed to set group"); + return false; + } + if (!EC_KEY_set_public_key(key.get(), + EC_KEY_get0_public_key(private_key.GetEcKey()))) { + LOGE("Failed to set public point"); + return false; + } + curve_ = private_key.curve(); + // Required flags for IETF compliance. + EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED); + key_ = key.release(); + return true; +} + +// static +std::unique_ptr EccPrivateKey::New(EccCurve curve) { + std::unique_ptr key(new EccPrivateKey()); + if (!key->InitFromCurve(curve)) { + LOGE("Failed to initialize private key from curve"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr EccPrivateKey::Load(const uint8_t* buffer, + size_t length) { + std::unique_ptr key; + if (buffer == nullptr) { + LOGE("Provided private key buffer is null"); + return key; + } + if (length == 0) { + LOGE("Provided private key buffer is zero length"); + return key; + } + key.reset(new EccPrivateKey()); + if (!key->InitFromBuffer(buffer, length)) { + LOGE("Failed to initialize private key from buffer"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr EccPrivateKey::Load(const std::string& buffer) { + if (buffer.empty()) { + LOGE("Provided private key buffer is empty"); + return std::unique_ptr(); + } + return Load(reinterpret_cast(buffer.data()), buffer.size()); +} + +// static +std::unique_ptr EccPrivateKey::Load( + const std::vector& buffer) { + if (buffer.empty()) { + LOGE("Provided private key buffer is empty"); + return std::unique_ptr(); + } + return Load(buffer.data(), buffer.size()); +} + +std::unique_ptr EccPrivateKey::MakePublicKey() const { + return EccPublicKey::New(*this); +} + +bool EccPrivateKey::IsMatchingPublicKey(const EccPublicKey& public_key) const { + if (public_key.curve() != curve_) { + return false; + } + return IsMatchingKeyPair(public_key.GetEcKey(), GetEcKey()); +} + +OEMCryptoResult EccPrivateKey::Serialize(uint8_t* buffer, + size_t* buffer_size) const { + if (buffer_size == nullptr) { + LOGE("Output buffer size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (buffer == nullptr && *buffer_size > 0) { + LOGE("Output buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // Step 1: Convert EC_KEY key to EVP. + ScopedEvpPkey pkey(EVP_PKEY_new()); + if (!pkey) { + LOGE("Failed to allocate EVP"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!EVP_PKEY_set1_EC_KEY(pkey.get(), key_)) { + LOGE("Failed to set EVP ECC key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2: Convert ECC EVP to PKCS8 format. + ScopedPrivateKeyInfo priv_info(EVP_PKEY2PKCS8(pkey.get())); + if (!priv_info) { + LOGE("Failed to convert ECC key to PKCS8 info"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 3: Serialize PKCS8 to DER encoding. + ScopedBio bio(BIO_new(BIO_s_mem())); + if (!bio) { + LOGE("Failed to allocate IO buffer for ECC key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio.get(), priv_info.get())) { + LOGE("Failed to serialize ECC key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 4: Determine key size and copy. + char* key_ptr = nullptr; + const long key_size = BIO_get_mem_data(bio.get(), &key_ptr); + if (key_size < 0) { + LOGE("Failed to get ECC key size"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (key_ptr == nullptr) { + LOGE("Encoded key is unexpectedly null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + const size_t required_size = static_cast(key_size); + if (*buffer_size < required_size) { + *buffer_size = required_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *buffer_size = required_size; + memcpy(buffer, key_ptr, required_size); + return OEMCrypto_SUCCESS; +} + +std::vector EccPrivateKey::Serialize() const { + size_t key_size = kPrivateKeySize; + std::vector key_data(key_size, 0); + const OEMCryptoResult res = Serialize(key_data.data(), &key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to serialize private key: result = %d", static_cast(res)); + key_data.clear(); + } else { + key_data.resize(key_size); + } + return key_data; +} + +OEMCryptoResult EccPrivateKey::GenerateSignature( + const uint8_t* message, size_t message_length, uint8_t* signature, + size_t* signature_length) const { + if (signature_length == nullptr) { + LOGE("Output signature size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (signature == nullptr && *signature_length > 0) { + LOGE("Output signature is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (message == nullptr && message_length > 0) { + LOGE("Invalid message data"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + const size_t expected_signature_length = ECDSA_size(key_); + if (*signature_length < expected_signature_length) { + *signature_length = expected_signature_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + + // Step 1: Hash message. + std::vector digest; + if (!DigestMessage(curve_, message, message_length, &digest)) { + LOGE("Failed to digest message"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2: Generate signature point. + ScopedSigPoint sig_point( + ECDSA_do_sign(digest.data(), static_cast(digest.size()), key_)); + if (!sig_point) { + LOGE("Failed to perform ECDSA"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 3: Serialize + std::vector temp(expected_signature_length); + uint8_t* sig_ptr = temp.data(); + const int res = i2d_ECDSA_SIG(sig_point.get(), &sig_ptr); + if (res <= 0) { + LOGE("Failed to serialize signature"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + const size_t required_size = static_cast(res); + if (signature == nullptr || *signature_length < required_size) { + *signature_length = required_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(signature, temp.data(), required_size); + *signature_length = required_size; + return OEMCrypto_SUCCESS; +} + +std::vector EccPrivateKey::GenerateSignature( + const std::string& message) const { + size_t signature_size = SignatureSize(); + std::vector signature(signature_size, 0); + const OEMCryptoResult res = + GenerateSignature(reinterpret_cast(message.data()), + message.size(), signature.data(), &signature_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to generate signature: result = %d", static_cast(res)); + signature.clear(); + } else { + signature.resize(signature_size); + } + return signature; +} + +std::vector EccPrivateKey::GenerateSignature( + const std::vector& message) const { + size_t signature_size = SignatureSize(); + std::vector signature(signature_size, 0); + const OEMCryptoResult res = GenerateSignature( + message.data(), message.size(), signature.data(), &signature_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to generate signature: result = %d", static_cast(res)); + signature.clear(); + } else { + signature.resize(signature_size); + } + return signature; +} + +size_t EccPrivateKey::SignatureSize() const { return ECDSA_size(key_); } + +OEMCryptoResult EccPrivateKey::DeriveSessionKey( + const EccPublicKey& public_key, uint8_t* session_key, + size_t* session_key_size) const { + if (public_key.curve() != curve_) { + LOGE("Incompatible ECC keys: public = %s, private = %s", + EccCurveToString(public_key.curve()).c_str(), + EccCurveToString(curve_).c_str()); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (session_key_size == nullptr) { + LOGE("Output session key size buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (session_key == nullptr && *session_key_size > 0) { + LOGE("Output session key buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (*session_key_size < kEccSessionKeySize) { + *session_key_size = kEccSessionKeySize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + const int res = ECDH_compute_key( + session_key, kEccSessionKeySize, + EC_KEY_get0_public_key(public_key.GetEcKey()), key_, WidevineEccKdf); + if (res < 0) { + LOGE("ECDH error occurred"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (static_cast(res) != kEccSessionKeySize) { + LOGE("Unexpected key size: size = %d", res); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + *session_key_size = kEccSessionKeySize; + return OEMCrypto_SUCCESS; +} + +std::vector EccPrivateKey::DeriveSessionKey( + const EccPublicKey& public_key) const { + size_t session_key_size = kEccSessionKeySize; + std::vector session_key(session_key_size, 0); + const OEMCryptoResult res = + DeriveSessionKey(public_key, session_key.data(), &session_key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to derive session key: result = %d", static_cast(res)); + session_key.clear(); + } else { + session_key.resize(session_key_size); + } + return session_key; +} + +size_t EccPrivateKey::SessionKeyLength() const { return kEccSessionKeySize; } + +EccPrivateKey::~EccPrivateKey() { + if (key_ != nullptr) { + EC_KEY_free(key_); + key_ = nullptr; + } + curve_ = kEccCurveUnknown; +} + +bool EccPrivateKey::InitFromBuffer(const uint8_t* buffer, size_t length) { + if (length == 0) { + LOGE("Public key is too small: length = %zu", length); + return false; + } + ScopedBio bio(BIO_new_mem_buf(buffer, static_cast(length))); + if (!bio) { + LOGE("Failed to allocate BIO buffer"); + return false; + } + // Step 1: Deserializes PKCS8 PrivateKeyInfo containing an ECC key. + ScopedPrivateKeyInfo priv_info( + d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); + if (!priv_info) { + LOGE("Failed to parse private key"); + return false; + } + // Step 2: Convert to EC_KEY. + ScopedEvpPkey pkey(EVP_PKCS82PKEY(priv_info.get())); + if (!pkey) { + LOGE("Failed to convert PKCS8 to EVP"); + return false; + } + ScopedEcKey key(EVP_PKEY_get1_EC_KEY(pkey.get())); + if (!key) { + LOGE("Failed to get ECC key"); + return false; + } + // Step 3: Verify key parameters and curve family. + const int check = EC_KEY_check_key(key.get()); + if (check == 0) { + LOGE("ECC key parameters are invalid"); + return false; + } else if (check == -1) { + LOGE("Failed to check ECC key"); + return false; + } + curve_ = GetCurveFromKeyGroup(key.get()); + if (curve_ == kEccCurveUnknown) { + LOGE("Failed to determine key group"); + return false; + } + // Required flags for IETF compliance. + EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED); + key_ = key.release(); + return true; +} + +bool EccPrivateKey::InitFromCurve(EccCurve curve) { + const EC_GROUP* group = GetEcGroup(curve); + if (group == nullptr) { + LOGE("Failed to get ECC group"); + return false; + } + ScopedEcKey key(EC_KEY_new()); + if (!key) { + LOGE("Failed to allocate key"); + return false; + } + if (!EC_KEY_set_group(key.get(), group)) { + LOGE("Failed to set group"); + return false; + } + // Generate random key. + if (!EC_KEY_generate_key(key.get())) { + LOGE("Failed to generate random key"); + return false; + } + curve_ = curve; + // Required flags for IETF compliance. + EC_KEY_set_asn1_flag(key.get(), OPENSSL_EC_NAMED_CURVE); + EC_KEY_set_conv_form(key.get(), POINT_CONVERSION_UNCOMPRESSED); + key_ = key.release(); + return true; +} + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_ecc_key.h b/oemcrypto/ref/src/oemcrypto_ecc_key.h new file mode 100644 index 0000000..88a65aa --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_ecc_key.h @@ -0,0 +1,260 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef OEMCRYPTO_ECC_KEY_H_ +#define OEMCRYPTO_ECC_KEY_H_ + +#include +#include + +#include +#include +#include + +#include + +#include "OEMCryptoCENCCommon.h" + +namespace wvoec_ref { + +enum EccCurve { + kEccCurveUnknown = 0, + kEccSecp256r1 = 256, + kEccSecp384r1 = 384, + kEccSecp521r1 = 521 +}; + +// Returns the string representation of the provided curve. +// Intended for logging purposes. +std::string EccCurveToString(EccCurve curve); + +class EccPrivateKey; + +class EccPublicKey { + public: + // Creates a new public key equivalent of the provided private key. + static std::unique_ptr New(const EccPrivateKey& private_key); + + // Loads a serialized EC public key. + // The provided |buffer| must contain a valid ASN.1 DER encoded + // SubjectPublicKey. Only supported curves by this API are those + // enumerated by EccCurve. + // + // buffer: SubjectPublicKeyInfo = { + // algorithm: AlgorithmIdentifier = { + // algorithm: OID = id-ecPublicKey, + // parameters: ECParameters = { + // namedCurve: OID = secp256r1 | secp384r1 | secp521r1 + // } + // }, + // subjectPublicKey: BIT STRING = ... -- SEC1 encoded ECPoint + // } + // + // Failure will occur if the provided |buffer| does not contain a + // valid SubjectPublicKey, or if the specified curve is not + // supported. + static std::unique_ptr Load(const uint8_t* buffer, + size_t length); + static std::unique_ptr Load(const std::string& buffer); + static std::unique_ptr Load(const std::vector& buffer); + + EccCurve curve() const { return curve_; } + const EC_KEY* GetEcKey() const { return key_; } + + // Checks if the provided |private_key| is the EC private key of this + // public key. + bool IsMatchingPrivateKey(const EccPrivateKey& private_key) const; + + // Serializes the public key into an ASN.1 DER encoded SubjectPublicKey + // representation. + // On success, |buffer_size| is populated with the number of bytes + // written to |buffer|, and OEMCrypto_SUCCESS is returned. + // If the provided |buffer_size| is too small, ERROR_SHORT_BUFFER + // is returned and |buffer_size| is set to the required buffer size. + OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const; + // Same as above, except directly returns the serialized key. + // Returns an empty vector on error. + std::vector Serialize() const; + + // Verifies the |signature| matches the provided |message| by the + // private equivalent of this public key. + // The |signature| should be a valid ASN.1 DER encoded + // ECDSA-Sig-Value. + // This implementation uses ECDSA with the following digest + // algorithms for the supported curve types. + // - SHA-256 / secp256r1 + // - SHA-384 / secp384r1 (optional support) + // - SHA-512 / secp521r1 (optional support) + // Returns: + // OEMCrypto_SUCCESS if signature is valid + // OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature is invalid + // Any other result indicates an unexpected error + OEMCryptoResult VerifySignature(const uint8_t* message, size_t message_length, + const uint8_t* signature, + size_t signature_length) const; + OEMCryptoResult VerifySignature(const std::string& message, + const std::string& signature) const; + OEMCryptoResult VerifySignature(const std::vector& message, + const std::vector& signature) const; + + ~EccPublicKey(); + + EccPublicKey(const EccPublicKey&) = delete; + EccPublicKey(EccPublicKey&&) = delete; + const EccPublicKey& operator=(const EccPublicKey&) = delete; + EccPublicKey& operator=(EccPublicKey&&) = delete; + + private: + EccPublicKey() {} + + // Initializes the public key object using the provided |buffer|. + // In case of any failure, false is return and the key should be + // discarded. + bool InitFromBuffer(const uint8_t* buffer, size_t length); + // Initializes the public key object from a private. + bool InitFromPrivateKey(const EccPrivateKey& private_key); + + // OpenSSL/BoringSSL implementation of an ECC key. + // As a public key, this will only have key point initialized. + EC_KEY* key_ = nullptr; + EccCurve curve_ = kEccCurveUnknown; +}; + +class EccPrivateKey { + public: + // Creates a new, pseudorandom ECC private key belonging to the + // curve specified. + static std::unique_ptr New(EccCurve curve); + + // Loads a serialized ECC private key. + // The provided |buffer| must contain a valid ASN.1 DER encoded + // PrivateKeyInfo containing a valid ECC key description. Only + // supported curves by this API are those enumerated by EccCurve. + // + // PrivateKeyInfo := { + // version: INTEGER = v1(0) | v2(1), + // privateKeyAlgorithm: AlgorithmIdentifier := { + // algorithm: OID = id-ecPublicKey, + // parameters: ECParameters = { + // namedCurve: OID = secp256r1 | secp384r1 | secp521r1 + // } + // }, + // privateKey: OCTET STRING = ..., -- BER encoding of ECPrivateKey + // } + // + // ECPrivateKey := { + // version: INTEGER = ecPrivateKeyVer1(1), + // privateKey: OCTET STRING = ..., -- I2OSP of private key point + // -- |parameters| are obtained from PrivateKeyInfo + // publicKey: BIT STRING OPTIONAL = ... -- SEC1 encoded ECPoint + // } + // Note: If the public key is not included, then it is computed from + // the private key. + // + // References: + // RFC 5208 - Description of PrivateKeyInfo + // RFC 5480 - Curve OIDs + // RFC 5915 - Description of ECPrivateKey in PrivateKeyInfo + // + // Failure will occur if the provided |buffer| does not contain a + // valid PrivateKeyInfo, key is not an ECC key, the specified + // curve is not supported, or the key is not valid. + static std::unique_ptr Load(const uint8_t* buffer, + size_t length); + static std::unique_ptr Load(const std::string& buffer); + static std::unique_ptr Load( + const std::vector& buffer); + + // Creates a new ECC public key of this private key. + // Equivalent to calling EccPublicKey::New with this private + // key. + std::unique_ptr MakePublicKey() const; + + EccCurve curve() const { return curve_; } + const EC_KEY* GetEcKey() const { return key_; } + + // Checks if the provided |public_key| is the EC public key of this + // private key. + bool IsMatchingPublicKey(const EccPublicKey& public_key) const; + + // Serializes the private key into an ASN.1 DER encoded PrivateKeyInfo + // representation. + // On success, |buffer_size| is populated with the number of bytes + // written to |buffer|, and SUCCESS is returned. + // If the provided |buffer_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is + // set to the required buffer size. + OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const; + // Same as above, except directly returns the serialized key. + // Returns an empty vector on error. + std::vector Serialize() const; + + // Signs the provided |message| and serializes the signature + // point to |signature| as a ASN.1 DER encoded ECDSA-Sig-Value. + // This implementation uses ECDSA with the following digest + // algorithms for the supported curve types. + // - SHA-256 / secp256r1 + // - SHA-384 / secp384r1 (optional support) + // - SHA-512 / secp521r1 (optional support) + // On success, |signature_length| is populated with the number of + // bytes written to |signature|, and SUCCESS is returned. + // If the provided |signature_length| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |signature_length| + // is set to the required signature size. + OEMCryptoResult GenerateSignature(const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length) const; + // Same as above, except directly returns the serialized signature. + // Returns an empty vector on error. + std::vector GenerateSignature( + const std::vector& message) const; + std::vector GenerateSignature(const std::string& message) const; + // Returns an upper bound for the signature size. May be larger than + // the actual signature generated by GenerateSignature(). + size_t SignatureSize() const; + + // Derives the OEMCrypto session key used for deriving other keys. + // The provided public key must be of the same curve. + // On success, |session_key_size| is populated with the number of + // bytes written to |session_key|, and OEMCrypto_SUCCESS is returned. + // If the provided |session_key_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |session_key_size| + // is set to the required buffer size. + OEMCryptoResult DeriveSessionKey(const EccPublicKey& public_key, + uint8_t* session_key, + size_t* session_key_size) const; + // Same as above, except directly returns the derived key. + std::vector DeriveSessionKey(const EccPublicKey& public_key) const; + // Returns the byte length of the symmetric key that would be derived + // by DeriveSymmetricKey(). + size_t SessionKeyLength() const; + + ~EccPrivateKey(); + + EccPrivateKey(const EccPrivateKey&) = delete; + EccPrivateKey(EccPrivateKey&&) = delete; + const EccPrivateKey& operator=(const EccPrivateKey&) = delete; + EccPrivateKey& operator=(EccPrivateKey&&) = delete; + + private: + EccPrivateKey() {} + + // Initializes the public key object using the provided |buffer|. + // In case of any failure, false is return and the key should be + // discarded. + bool InitFromBuffer(const uint8_t* buffer, size_t length); + // Generates a new key based on the provided curve. + bool InitFromCurve(EccCurve curve); + + // OpenSSL/BoringSSL implementation of an ECC key. + // The public point of the key will always be present. + EC_KEY* key_ = nullptr; + EccCurve curve_ = kEccCurveUnknown; +}; + +} // namespace wvoec_ref + +#endif // OEMCRYPTO_EC_KEY_H_ diff --git a/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp b/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp index 7e3c2eb..d2115ca 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp +++ b/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp @@ -24,6 +24,15 @@ class Prov30CryptoEngine : public CryptoEngine { explicit Prov30CryptoEngine(std::unique_ptr&& file_system) : CryptoEngine(std::move(file_system)) {} + bool Initialize() override { + if (!CryptoEngine::Initialize()) { + return false; + } + const OEMCryptoResult result = InstallOemCertificate( + kOEMPrivateKey, kOEMPrivateKeySize, kOEMPublicCert, kOEMPublicCertSize); + return result == OEMCrypto_SUCCESS; + } + bool config_local_display_only() { return true; } // Returns the max HDCP version supported. @@ -47,31 +56,6 @@ class Prov30CryptoEngine : public CryptoEngine { return OEMCrypto_OEMCertificate; } - OEMCryptoResult get_oem_certificate(SessionContext* session, - uint8_t* public_cert, - size_t* public_cert_length) { - if (kOEMPublicCertSize == 0) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (public_cert_length == nullptr) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (*public_cert_length < kOEMPublicCertSize) { - *public_cert_length = kOEMPublicCertSize; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *public_cert_length = kOEMPublicCertSize; - if (public_cert == nullptr) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize); - if (!session->LoadRSAKey(kOEMPrivateKey, kOEMPrivateKeySize)) { - LOGE("Private RSA Key did not load correctly."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - return OEMCrypto_SUCCESS; - } - // Returns "L3" for a software only library. L1 is for hardware protected // keys and data paths. L2 is for hardware protected keys but no data path // protection. diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp index 9195617..54f5115 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.cpp @@ -7,6 +7,7 @@ #include "oemcrypto_engine_ref.h" #include +#include #include #include #include @@ -20,7 +21,6 @@ #include "keys.h" #include "log.h" #include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" #include "string_conversions.h" namespace { @@ -39,9 +39,7 @@ namespace wvoec_ref { // for methods that are configured for specific configurations. CryptoEngine::CryptoEngine(std::unique_ptr&& file_system) - : root_of_trust_(config_provisioning_method()), - file_system_(std::move(file_system)), - usage_table_() { + : file_system_(std::move(file_system)), usage_table_() { ERR_load_crypto_strings(); } @@ -53,7 +51,7 @@ bool CryptoEngine::Initialize() { std::string file_path = GetUsageTimeFileFullPath(); LoadOfflineTimeInfo(file_path); usage_table_.reset(MakeUsageTable()); - return true; + return root_of_trust_.Initialize(config_provisioning_method()); } void CryptoEngine::Terminate() { @@ -83,7 +81,10 @@ SessionId CryptoEngine::OpenSession() { } SessionContext* CryptoEngine::MakeSession(SessionId sid) { - return new SessionContext(this, sid, root_of_trust_.SharedRsaKey()); + if (root_of_trust_.HasDrmCertKey()) { + return new SessionContext(this, sid, root_of_trust_.ShareDrmCertKey()); + } + return new SessionContext(this, sid); } UsageTable* CryptoEngine::MakeUsageTable() { return new UsageTable(this); } @@ -116,7 +117,7 @@ int64_t CryptoEngine::MonotonicTime() { wvcdm::Clock().GetCurrentTime() + offline_time_info_.rollback_offset; static int64_t then = now; if (now < then) { - LOGW("Clock rollback detected: %ld seconds", then - now); + LOGW("Clock rollback detected: %" PRId64 " seconds", then - now); offline_time_info_.rollback_offset += then - now; now = then; } diff --git a/oemcrypto/ref/src/oemcrypto_engine_ref.h b/oemcrypto/ref/src/oemcrypto_engine_ref.h index aadb512..5027273 100644 --- a/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -8,19 +8,16 @@ #define REF_OEMCRYPTO_ENGINE_REF_H_ #include -#include + #include #include #include #include -#include - #include "OEMCryptoCENC.h" #include "file_store.h" #include "oemcrypto_auth_ref.h" #include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" #include "oemcrypto_session.h" #include "oemcrypto_types.h" #include "oemcrypto_usage_table_ref.h" @@ -65,31 +62,61 @@ class CryptoEngine { virtual bool Initialize(); - bool ValidRootOfTrust() { return root_of_trust_.Validate(); } + bool ValidRootOfTrust() const { return root_of_trust_.IsValid(); } - bool InstallKeybox(const uint8_t* keybox, size_t keybox_length) { + virtual OEMCryptoResult InstallKeybox(const uint8_t* keybox, + size_t keybox_length) { return root_of_trust_.InstallKeybox(keybox, keybox_length); } - bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) { - return root_of_trust_.UseTestKeybox(keybox_data, keybox_length); + OEMCryptoResult InstallTestKeybox(const uint8_t* keybox_data, + size_t keybox_length) { + return root_of_trust_.InstallTestKeybox(keybox_data, keybox_length); } - bool LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); } + OEMCryptoResult LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); } - KeyboxError ValidateKeybox() { return root_of_trust_.ValidateKeybox(); } + OEMCryptoResult IsKeyboxOrOemCertValid() const { + return root_of_trust_.IsKeyboxOrOemCertValid(); + } - const std::vector& DeviceRootKey() { + std::vector DeviceRootKey() const { return root_of_trust_.DeviceKey(); } - const std::vector& DeviceRootId() { + OEMCryptoResult GetDeviceRootId(uint8_t* device_id, + size_t* device_id_length) const { + return root_of_trust_.GetDeviceId(device_id, device_id_length); + } + + std::vector DeviceRootId() const { return root_of_trust_.DeviceId(); } - size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); } + OEMCryptoResult GetRootKeyData(uint8_t* key_data, + size_t* key_data_length) const { + return root_of_trust_.GetKeyData(key_data, key_data_length); + } - const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); } + OEMCryptoResult InstallOemCertificate(const uint8_t* private_key, + size_t private_key_size, + const uint8_t* public_cert, + size_t public_cert_size) { + return root_of_trust_.InstallOemCertificate(private_key, private_key_size, + public_cert, public_cert_size); + } + + OEMCryptoResult GetOemPublicCertificate(uint8_t* public_cert, + size_t* public_cert_length) const { + return root_of_trust_.GetOemPublicCertificate(public_cert, + public_cert_length); + } + + std::shared_ptr ShareOemPrivateKey() { + return root_of_trust_.ShareOemCertKey(); + } + + bool HasOemPrivateKey() const { return root_of_trust_.HasOemCertKey(); } virtual void Terminate(); @@ -149,15 +176,6 @@ class CryptoEngine { return OEMCrypto_Keybox; } - virtual OEMCryptoResult get_oem_certificate(uint8_t* public_cert, - size_t* public_cert_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - virtual OEMCryptoResult load_oem_private_key(SessionContext* session) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - // Used for OEMCrypto_IsAntiRollbackHwPresent. virtual bool config_is_anti_rollback_hw_present() { return false; } diff --git a/oemcrypto/ref/src/oemcrypto_key_deriver.cpp b/oemcrypto/ref/src/oemcrypto_key_deriver.cpp new file mode 100644 index 0000000..d28e1f1 --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_key_deriver.cpp @@ -0,0 +1,153 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include "oemcrypto_key_deriver.h" + +#include "log.h" + +namespace wvoec_ref { +namespace { +bool Derive128KeyAppend(Cmac* cmac, uint8_t counter, const uint8_t* ctx, + size_t ctx_size, std::vector* derived_key) { + cmac->Reset(); + if (!cmac->Update(counter)) { + return false; + } + if (!cmac->Update(ctx, ctx_size)) { + return false; + } + if (!cmac->FinalizeAppend(derived_key)) { + return false; + } + return true; +} + +bool Derive128Key(Cmac* cmac, uint8_t counter, const uint8_t* ctx, + size_t ctx_size, std::vector* derived_key) { + derived_key->clear(); + return Derive128KeyAppend(cmac, counter, ctx, ctx_size, derived_key); +} + +bool Derive256Key(Cmac* cmac, uint8_t counter_base, const uint8_t* ctx, + size_t ctx_size, std::vector* derived_key) { + derived_key->clear(); + if (!Derive128KeyAppend(cmac, counter_base, ctx, ctx_size, derived_key)) { + return false; + } + return Derive128KeyAppend(cmac, counter_base + 1, ctx, ctx_size, derived_key); +} +} // namespace + +// static +std::unique_ptr KeyDeriver::Create(const uint8_t* key, + size_t key_size) { + if (key == nullptr) { + LOGE("Key deriver key is null"); + return std::unique_ptr(); + } + std::unique_ptr key_deriver(new KeyDeriver()); + if (!key_deriver->Init(key, key_size)) { + key_deriver.reset(); + } + return key_deriver; +} + +// static +std::unique_ptr KeyDeriver::Create( + const std::vector& key) { + if (key.empty()) { + LOGE("Key deriver key is empty"); + return std::unique_ptr(); + } + return Create(key.data(), key.size()); +} + +bool KeyDeriver::Init(const uint8_t* key, size_t key_size) { + cmac_ = Cmac::Create(key, key_size); + if (!cmac_) { + LOGE("Failed to create CMAC for key deriver"); + return false; + } + return true; +} + +bool KeyDeriver::DeriveServerMacKey(const uint8_t* mac_key_context, + size_t mac_key_context_size, + std::vector* mac_key_server) { + if (mac_key_context == nullptr) { + LOGE("Server MAC key context is null"); + return false; + } + if (mac_key_server == nullptr) { + LOGE("Output server MAC key buffer is null"); + return false; + } + return Derive256Key(cmac_.get(), 0x01, mac_key_context, mac_key_context_size, + mac_key_server); +} + +bool KeyDeriver::DeriveServerMacKey(const std::vector& mac_key_context, + std::vector* mac_key_server) { + if (mac_key_context.empty()) { + LOGE("Server MAC key context is empty"); + return false; + } + return DeriveServerMacKey(mac_key_context.data(), mac_key_context.size(), + mac_key_server); +} + +bool KeyDeriver::DeriveClientMacKey(const uint8_t* mac_key_context, + size_t mac_key_context_size, + std::vector* mac_key_client) { + if (mac_key_context == nullptr) { + LOGE("Client MAC key context is null"); + return false; + } + if (mac_key_client == nullptr) { + LOGE("Output client MAC key buffer is null"); + return false; + } + return Derive256Key(cmac_.get(), 0x03, mac_key_context, mac_key_context_size, + mac_key_client); +} + +bool KeyDeriver::DeriveClientMacKey(const std::vector& mac_key_context, + std::vector* mac_key_client) { + if (mac_key_context.empty()) { + LOGE("Client MAC key context is empty"); + return false; + } + return DeriveClientMacKey(mac_key_context.data(), mac_key_context.size(), + mac_key_client); +} + +bool KeyDeriver::DeriveEncryptionKey(const uint8_t* enc_key_context, + size_t enc_key_context_size, + std::vector* enc_key) { + if (enc_key_context == nullptr) { + LOGE("Encryption key context is null"); + return false; + } + if (enc_key == nullptr) { + LOGE("Output encryption key buffer is null"); + return false; + } + return Derive128Key(cmac_.get(), 0x01, enc_key_context, enc_key_context_size, + enc_key); +} + +bool KeyDeriver::DeriveEncryptionKey( + const std::vector& enc_key_context, + std::vector* enc_key) { + if (enc_key_context.empty()) { + LOGE("Encryption key context is empty"); + return false; + } + return DeriveEncryptionKey(enc_key_context.data(), enc_key_context.size(), + enc_key); +} + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_key_deriver.h b/oemcrypto/ref/src/oemcrypto_key_deriver.h new file mode 100644 index 0000000..9e2a964 --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_key_deriver.h @@ -0,0 +1,62 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef OEMCRYPTO_KEY_DERIVER_H_ +#define OEMCRYPTO_KEY_DERIVER_H_ + +#include +#include + +#include +#include + +#include "cmac.h" + +namespace wvoec_ref { + +class KeyDeriver { + public: + // Create a new key deriver using either the session key or the device + // key. + // Returns an empty pointer if the key size is not valid. + static std::unique_ptr Create(const uint8_t* key, + size_t key_size); + static std::unique_ptr Create(const std::vector& key); + + // Derive the mac_key[server] from the provided |mac_key_context|. + bool DeriveServerMacKey(const uint8_t* mac_key_context, + size_t mac_key_context_size, + std::vector* mac_key_server); + bool DeriveServerMacKey(const std::vector& mac_key_context, + std::vector* mac_key_server); + + // Derive the mac_key[client] from the provided |mac_key_context|. + bool DeriveClientMacKey(const uint8_t* mac_key_context, + size_t mac_key_context_size, + std::vector* mac_key_client); + bool DeriveClientMacKey(const std::vector& mac_key_context, + std::vector* mac_key_client); + + // Derive the enc_key from the provided |enc_key_context|. + bool DeriveEncryptionKey(const uint8_t* enc_key_context, + size_t enc_key_context_size, + std::vector* enc_key); + bool DeriveEncryptionKey(const std::vector& enc_key_context, + std::vector* enc_key); + + ~KeyDeriver() {} + + private: + KeyDeriver() {} + + bool Init(const uint8_t* key, size_t key_size); + + std::unique_ptr cmac_; +}; + +} // namespace wvoec_ref + +#endif // OEMCRYPTO_KEY_DERIVER_H_ diff --git a/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp b/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp index e1cc4bc..4e74b82 100644 --- a/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp @@ -17,58 +17,112 @@ #include "wvcrc32.h" namespace wvoec_ref { +namespace { +constexpr size_t kKeyboxSize = 128; +constexpr size_t kDeviceIdSize = 32; +constexpr size_t kKeyDataSize = 72; +constexpr size_t kMagicOffset = 120; +const uint8_t kMagic[4] = {'k', 'b', 'o', 'x'}; +constexpr size_t kCrcKeyboxSize = 124; +constexpr size_t kCrcOffset = 124; -WvKeybox::WvKeybox() : loaded_(false) { - static std::string fake_device_id = "device_with_no_keybox"; - device_id_.assign(fake_device_id.begin(), fake_device_id.end()); +static_assert(sizeof(wvoec::WidevineKeybox) == kKeyboxSize, + "Unexpected keybox size"); + +template +std::vector ToVector(const uint8_t (&field)[N]) { + return std::vector(field, &field[N]); +} +} // namespace + +// static +OEMCryptoResult WvKeybox::ValidateData(const uint8_t* keybox, + size_t keybox_length) { + if (keybox == nullptr) { + LOGE("Keybox data buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (keybox_length != kKeyboxSize) { + LOGE("Invalid keybox length: length = %zu", keybox_length); + return OEMCrypto_ERROR_KEYBOX_INVALID; + } + if (memcmp(&keybox[kMagicOffset], kMagic, sizeof(kMagic))) { + LOGE("Invalid keybox magic"); + return OEMCrypto_ERROR_BAD_MAGIC; + } + uint32_t crc_provided; + memcpy(&crc_provided, &keybox[kCrcOffset], sizeof(crc_provided)); + const uint32_t crc_computed = wvcrc32n(keybox, kCrcKeyboxSize); + if (crc_provided != crc_computed) { + LOGE("Invalid keybox CRC: provided = %08x, computed = %08x", crc_provided, + crc_computed); + return OEMCrypto_ERROR_BAD_CRC; + } + return OEMCrypto_SUCCESS; } -KeyboxError WvKeybox::Validate() { - if (!loaded_) { - LOGE("[KEYBOX NOT LOADED]"); - return OTHER_ERROR; +// static +std::unique_ptr WvKeybox::Create(const uint8_t* keybox_data, + size_t keybox_length) { + std::unique_ptr keybox; + if (keybox_length != kKeyboxSize) { + LOGE("Invalid keybox length: length = %zu", keybox_length); + return keybox; } - if (strncmp(reinterpret_cast(magic_), "kbox", 4) != 0) { - LOGE("[KEYBOX HAS BAD MAGIC]"); - return BAD_MAGIC; - } - uint32_t crc_computed; - uint32_t crc_stored; - uint8_t* crc_stored_bytes = (uint8_t*)&crc_stored; - memcpy(crc_stored_bytes, crc_, sizeof(crc_)); - wvoec::WidevineKeybox keybox; - memset(&keybox, 0, sizeof(keybox)); - memcpy(keybox.device_id_, &device_id_[0], device_id_.size()); - memcpy(keybox.device_key_, &device_key_[0], sizeof(keybox.device_key_)); - memcpy(keybox.data_, key_data_, sizeof(keybox.data_)); - memcpy(keybox.magic_, magic_, sizeof(keybox.magic_)); - - crc_computed = ntohl(wvcrc32(reinterpret_cast(&keybox), - sizeof(keybox) - 4)); // Drop last 4 bytes. - if (crc_computed != crc_stored) { - LOGE("[KEYBOX CRC problem: computed = %08x, stored = %08x]\n", - crc_computed, crc_stored); - return BAD_CRC; - } - return NO_ERROR; + keybox.reset(new WvKeybox()); + memcpy(reinterpret_cast(&keybox->raw_keybox_), keybox_data, + kKeyboxSize); + return keybox; } -bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) { - if (keyBoxLength != 128) { - return false; +OEMCryptoResult WvKeybox::GetDeviceId(uint8_t* device_id, + size_t* device_id_length) const { + if (device_id_length == nullptr) { + LOGE("Output device ID length buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; } - const wvoec::WidevineKeybox* keybox = - reinterpret_cast(buffer); - size_t device_id_length = - strnlen(reinterpret_cast(keybox->device_id_), 32); - device_id_.assign(keybox->device_id_, keybox->device_id_ + device_id_length); - device_key_.assign(keybox->device_key_, - keybox->device_key_ + sizeof(keybox->device_key_)); - memcpy(key_data_, keybox->data_, sizeof(keybox->data_)); - memcpy(magic_, keybox->magic_, sizeof(keybox->magic_)); - memcpy(crc_, keybox->crc_, sizeof(keybox->crc_)); - loaded_ = true; - return true; + if (device_id == nullptr && *device_id_length > 0) { + LOGE("Output device ID buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (*device_id_length < kDeviceIdSize) { + *device_id_length = kDeviceIdSize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *device_id_length = kDeviceIdSize; + memcpy(device_id, raw_keybox_.device_id_, kDeviceIdSize); + return OEMCrypto_SUCCESS; } +std::vector WvKeybox::DeviceId() const { + return ToVector(raw_keybox_.device_id_); +} + +std::vector WvKeybox::DeviceKey() const { + return ToVector(raw_keybox_.device_key_); +} + +OEMCryptoResult WvKeybox::GetKeyData(uint8_t* key_data, + size_t* key_data_length) const { + if (key_data_length == nullptr) { + LOGE("Output key data length buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (key_data == nullptr && *key_data_length > 0) { + LOGE("Output key data buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (*key_data_length < kKeyDataSize) { + *key_data_length = kKeyDataSize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *key_data_length = kKeyDataSize; + memcpy(key_data, raw_keybox_.data_, kKeyDataSize); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult WvKeybox::IsKeyboxValid() const { + return ValidateData(reinterpret_cast(&raw_keybox_), + kKeyboxSize); +} } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_keybox_ref.h b/oemcrypto/ref/src/oemcrypto_keybox_ref.h index bb543fc..c9831c6 100644 --- a/oemcrypto/ref/src/oemcrypto_keybox_ref.h +++ b/oemcrypto/ref/src/oemcrypto_keybox_ref.h @@ -7,38 +7,58 @@ #ifndef OEMCRYPTO_KEYBOX_REF_H_ #define OEMCRYPTO_KEYBOX_REF_H_ -#include "oemcrypto_key_ref.h" +#include +#include + +#include "OEMCryptoCENCCommon.h" +#include "oemcrypto_types.h" namespace wvoec_ref { -const int DEVICE_KEY_LENGTH = 16; -typedef uint8_t WvKeyboxKey[DEVICE_KEY_LENGTH]; - -const int KEY_DATA_LENGTH = 72; -typedef uint8_t WvKeyboxKeyData[KEY_DATA_LENGTH]; - -enum KeyboxError { NO_ERROR, BAD_CRC, BAD_MAGIC, OTHER_ERROR }; - // Widevine keybox class WvKeybox { public: - WvKeybox(); + // Validates keybox data using the following rules: + // 1. Data is not null + // 2. Keybox size + // 3. Matching magic + // 4. CRC-32 check + static OEMCryptoResult ValidateData(const uint8_t* keybox_data, + size_t keybox_length); + + // Creates a keybox from the provided keybox data. + // Provided keybox data must be the proper length, but does + // not need to be valid. + // Once created, keyboxes are immutable. + static std::unique_ptr Create(const uint8_t* keybox_data, + size_t keybox_length); + + // Gets the device ID from the keybox. + // Similar to the expected behavior of OEMCrypto_GetDeviceID(). + OEMCryptoResult GetDeviceId(uint8_t* device_id, + size_t* device_id_length) const; + // Returns the keybox device ID directly. Intended to be used + // for core message generation. + std::vector DeviceId() const; + + // Returns the keybox device key directly. Intended to be used + // for key derivation. + std::vector DeviceKey() const; + + // Gets the keybox data. + // Similar to the expected behavior of OEMCrypto_GetKeyData(). + OEMCryptoResult GetKeyData(uint8_t* key_data, size_t* key_data_length) const; + + // Checks the current keybox instantiation that it is valid. + // Similar to the expected behavior of OEMCrypto_IsKeyboxValid(). + OEMCryptoResult IsKeyboxValid() const; + ~WvKeybox() {} - KeyboxError Validate(); - const std::vector& device_id() { return device_id_; } - std::vector& device_key() { return device_key_; } - const WvKeyboxKeyData& key_data() { return key_data_; } - size_t key_data_length() { return KEY_DATA_LENGTH; } - bool InstallKeybox(const uint8_t* keybox, size_t keyBoxLength); - private: - bool loaded_; - std::vector device_id_; - std::vector device_key_; - WvKeyboxKeyData key_data_; - uint8_t magic_[4]; - uint8_t crc_[4]; + WvKeybox() {} + + wvoec::WidevineKeybox raw_keybox_; }; } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_oem_cert.cpp b/oemcrypto/ref/src/oemcrypto_oem_cert.cpp new file mode 100644 index 0000000..21b2e0b --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_oem_cert.cpp @@ -0,0 +1,233 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include "oemcrypto_oem_cert.h" + +#include + +#include +#include +#include + +#include "log.h" +#include "oemcrypto_rsa_key.h" +#include "scoped_object.h" + +namespace wvoec_ref { +namespace { +using ScopedCertificate = ScopedObject; +using ScopedEvpKey = ScopedObject; +using ScopedPkcs7 = ScopedObject; + +constexpr size_t kExpectedCertCount = 2; // Leaf and intermediate. +constexpr int kDeviceCertIndex = 0; + +// Checks that the |public_key| from an X.509 certificate is the +// correct public key of the serialized |private_key_data|. +OEMCryptoResult VerifyRsaKey(const RSA* public_key, + const std::vector& private_key_data) { + if (public_key == nullptr) { + LOGE("RSA key is null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + std::unique_ptr private_key = + RsaPrivateKey::Load(private_key_data); + if (!private_key) { + LOGE("Failed to parse provided RSA private key"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + if (!RsaKeysAreMatchingPair(public_key, private_key->GetRsaKey())) { + LOGE("OEM certificate keys do not match"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + return OEMCrypto_SUCCESS; +} +} // namespace + +// This utility class encapsulates the minimum functionality of an +// OEM Public Certificate required to verify a device's OEM Public +// Certificate. +class OemPublicCertificate { + public: + // Loads a PKCS #7 signedData message with certificate chain. + // Minimum validation is performed. Only checks that the + // device's public key is of a known type (RSA). + static std::unique_ptr Load(const uint8_t* public_cert, + size_t public_cert_size) { + std::unique_ptr oem_public_cert; + if (public_cert == nullptr) { + LOGE("Public cert buffer is null"); + return oem_public_cert; + } + if (public_cert_size == 0) { + LOGE("Public cert buffer is empty"); + return oem_public_cert; + } + oem_public_cert.reset(new OemPublicCertificate()); + if (!oem_public_cert->InitFromBuffer(public_cert, public_cert_size)) { + oem_public_cert.reset(); + } + return oem_public_cert; + } + + OemCertificate::KeyType key_type() const { return key_type_; } + const std::vector& cert_data() const { return cert_data_; } + + const RSA* GetPublicRsaKey() const { + return EVP_PKEY_get0_RSA(device_public_key_.get()); + } + + ~OemPublicCertificate() = default; + + OemPublicCertificate(const OemPublicCertificate&) = delete; + OemPublicCertificate(OemPublicCertificate&&) = delete; + const OemPublicCertificate& operator=(const OemPublicCertificate&) = delete; + OemPublicCertificate& operator=(OemPublicCertificate&&) = delete; + + private: + OemPublicCertificate() {} + + bool InitFromBuffer(const uint8_t* public_cert, size_t public_cert_size) { + // Step 1: Parse the PKCS7 certificate chain as signedData. + const uint8_t* public_cert_ptr = public_cert; + pkcs7_.reset(d2i_PKCS7(nullptr, &public_cert_ptr, public_cert_size)); + if (!pkcs7_) { + LOGE("Failed to parse PKCS#7 certificate chain"); + return false; + } + if (!PKCS7_type_is_signed(pkcs7_.get())) { + LOGE("OEM Public Certificate is not PKCS#7 signed data"); + return false; + } + PKCS7_SIGNED* signed_data = pkcs7_->d.sign; + // Step 2: Get the leaf certificate. + const size_t cert_count = + static_cast(sk_X509_num(signed_data->cert)); + if (cert_count != kExpectedCertCount) { + LOGE("Unexpected number of certificates: expected = %zu, actual = %zu", + kExpectedCertCount, cert_count); + return false; + } + X509* leaf_cert = sk_X509_value(signed_data->cert, kDeviceCertIndex); + // Step 3a: Get the device's public key. + device_public_key_.reset(X509_get_pubkey(leaf_cert)); + if (!device_public_key_) { + LOGE("Device X.509 certificate is missing a public key"); + return false; + } + // Step 3b: Check key type. + if (EVP_PKEY_get0_RSA(device_public_key_.get()) == nullptr) { + LOGE("Device public key is not RSA"); + return false; + } + key_type_ = OemCertificate::kRsa; + cert_data_.assign(public_cert, public_cert + public_cert_size); + return true; + } + + OemCertificate::KeyType key_type_ = OemCertificate::kNone; + // OpenSSL/BoringSSL's implementation of PKCS7 objects. + ScopedPkcs7 pkcs7_; + ScopedEvpKey device_public_key_; + std::vector cert_data_; +}; + +// ===== ===== ===== OEM Certificate ===== ===== ===== + +// static +std::unique_ptr OemCertificate::Create( + const uint8_t* private_key_data, size_t private_key_size, + const uint8_t* public_cert_data, size_t public_cert_size) { + std::unique_ptr oem_cert; + // Step 1: Verify public cert is well-formed. + std::unique_ptr oem_public_cert = + OemPublicCertificate::Load(public_cert_data, public_cert_size); + if (!oem_public_cert) { + LOGE("Invalid OEM Public Certificate"); + return oem_cert; + } + // Step 2: Verify private key is well-formed. + switch (oem_public_cert->key_type()) { + case kRsa: { + std::unique_ptr oem_private_key = + RsaPrivateKey::Load(private_key_data, private_key_size); + if (!oem_private_key) { + LOGE("Invalid OEM Private Key"); + return oem_cert; + } + } break; + case kNone: // Suppress compiler warnings. + return oem_cert; + } + // Step 3: Copy over data. + oem_cert.reset(new OemCertificate()); + oem_cert->private_key_.assign(private_key_data, + private_key_data + private_key_size); + oem_cert->public_cert_ = std::move(oem_public_cert); + return oem_cert; +} + +// static +std::unique_ptr OemCertificate::Create( + const std::vector& private_key, + const std::vector& public_cert) { + if (private_key.empty()) { + LOGE("Private key buffer is empty"); + return std::unique_ptr(); + } + if (public_cert.empty()) { + LOGE("Public cert buffer is empty"); + return std::unique_ptr(); + } + return Create(private_key.data(), private_key.size(), public_cert.data(), + public_cert.size()); +} + +OemCertificate::KeyType OemCertificate::key_type() const { + return public_cert_->key_type(); +} + +OEMCryptoResult OemCertificate::GetPublicCertificate( + uint8_t* public_cert, size_t* public_cert_length) const { + if (public_cert_length == nullptr) { + LOGE("Output |public_cert_length| is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (public_cert == nullptr && *public_cert_length > 0) { + LOGE("Output |public_cert| is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + const std::vector& cert_data = public_cert_->cert_data(); + if (*public_cert_length < cert_data.size()) { + *public_cert_length = cert_data.size(); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *public_cert_length = cert_data.size(); + memcpy(public_cert, cert_data.data(), cert_data.size()); + return OEMCrypto_SUCCESS; +} + +const std::vector& OemCertificate::GetPublicCertificate() const { + return public_cert_->cert_data(); +} + +OEMCryptoResult OemCertificate::IsCertificateValid() const { + switch (key_type()) { + case kRsa: + return VerifyRsaKey(public_cert_->GetPublicRsaKey(), private_key_); + case kNone: // Suppress compiler warnings. + break; + } + LOGE("Unexpected error key type: type = %d", static_cast(key_type())); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +// Constructor and destructor do not perform anything special, but +// must be declared within a scope which defines OemPublicCertificate. +OemCertificate::OemCertificate() {} +OemCertificate::~OemCertificate() {} + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_oem_cert.h b/oemcrypto/ref/src/oemcrypto_oem_cert.h new file mode 100644 index 0000000..70c7fff --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_oem_cert.h @@ -0,0 +1,104 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef OEMCRYPTO_OEM_CERT_H_ +#define OEMCRYPTO_OEM_CERT_H_ + +#include +#include + +#include "OEMCryptoCENCCommon.h" + +namespace wvoec_ref { + +class OemPublicCertificate; + +// An OEM Certificate is a factory provisioned root of trust +// certificate which consists of a public certificate and its +// matching private key. +// The public certificate must be an ASN.1 DER encoded PKCS #7 +// ContentInfo of type signedData (RFC2315). The device's X.509 +// certificate must be the first certificate in the chain of +// SignedContent |certificates|. +// The certificates are X.509 Certificate as defined in RFC 5280 +// signed by the device manufacturers certificate which is signed +// by Google. +// The OEM Public Cert should only contain the device's certificate +// and the OEM's intermediate certificate. +// The private key storage format is at the discretion of the OEM; +// the reference implementation uses PKCS8 PrivateKeyInfo. +class OemCertificate { + public: + enum KeyType { + kNone = 0, + // Private key is an ASN.1 DER encoded PrivateKeyInfo specifying + // an RSA encryption key. + kRsa = 1 + }; + + // Creates a new OEM Certificate and performs basic validation + // to ensure that the private key and public cert are well-formed. + // The |public_cert| provided is parsed as an X.509 Certificate + // and the public key is verified against the private key. + // The |private_key| is parsed depending on the key type. + // If any error occurs or if the provided data is malformed, an + // empty pointer is returned. + static std::unique_ptr Create(const uint8_t* private_key, + size_t private_key_size, + const uint8_t* public_cert, + size_t public_cert_size); + static std::unique_ptr Create( + const std::vector& private_key, + const std::vector& public_cert); + + // Returns the key type of the OEM Public key and private key. + // As of OEMCrypto v16, the only supported key type is RSA. + KeyType key_type() const; + + // Returns the private key data. Intended to be used for calls + // to OEMCrypto_LoadOEMPrivateKey(). + const std::vector& GetPrivateKey() const { return private_key_; } + + // Returns a copy of the ASN.1 DER encoded PKCS #7 certificate chain. + // If |*public_cert_length| is large enough, the complete + // certificate is copied to the buffer specified by |public_cert|, + // |*public_cert_length| is adjusted to the actual size of the + // certificate data, and SUCCESS is returned. + // If |*public_cert_length| is not large enough, then it is + // set to size of the certificate and ERROR_SHORT_BUFFER is + // returned. + OEMCryptoResult GetPublicCertificate(uint8_t* public_cert, + size_t* public_cert_length) const; + // Returns the certificate directly. Intended to be used for + // testing. + const std::vector& GetPublicCertificate() const; + + // Verifies that the RSA key included in the OEM Cert is valid. + // The existence of an OemCertificate already ensures that the + // OEM Public Certificate and private key data are well-formed. + // This takes the check another step further and ensures that + // the private key matches the public key in the public cert + // (ie, same modulos and public exponent). + OEMCryptoResult IsCertificateValid() const; + + ~OemCertificate(); + + OemCertificate(const OemCertificate&) = delete; + OemCertificate(OemCertificate&&) = delete; + const OemCertificate& operator=(const OemCertificate&) = delete; + OemCertificate& operator=(OemCertificate&&) = delete; + + private: + OemCertificate(); + + // Serialized private key matching the OEM certificate. + std::vector private_key_; + // Serialized OEM Certificate. + std::unique_ptr public_cert_; +}; +} // namespace wvoec_ref + +#endif // OEMCRYPTO_OEM_CERT_H_ diff --git a/oemcrypto/ref/src/oemcrypto_ref.cpp b/oemcrypto/ref/src/oemcrypto_ref.cpp index d974422..bb5bcc2 100644 --- a/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -25,7 +25,6 @@ #include "file_store.h" #include "log.h" -#include "odk.h" #include "oemcrypto_engine_ref.h" #include "oemcrypto_session.h" #include "oemcrypto_usage_table_ref.h" @@ -48,33 +47,12 @@ const size_t kMaxInputMessageBuferLength = 1024 * 1024; // Maximum signature length used by reference implementation for performance // reasons. This is not mandated by specification. const size_t kMaxInputSignatureLength = 10 * 1024; - -// Return uint32 referenced through a potentially unaligned pointer. -// If the pointer is nullptr, return 0. -uint32_t unaligned_dereference_uint32(const void* unaligned_ptr) { - if (unaligned_ptr == nullptr) return 0; - uint32_t value; - const uint8_t* src = reinterpret_cast(unaligned_ptr); - uint8_t* dest = reinterpret_cast(&value); - for (unsigned long i = 0; i < sizeof(value); i++) { - dest[i] = src[i]; - } - return value; -} - } // namespace namespace wvoec_ref { static std::unique_ptr crypto_engine; -typedef struct { - uint8_t signature[wvoec::MAC_KEY_SIZE]; - uint8_t context[wvoec::MAC_KEY_SIZE]; - uint8_t iv[wvoec::KEY_IV_SIZE]; - uint8_t enc_rsa_key[]; -} WrappedRSAKey; - OEMCRYPTO_API OEMCryptoResult OEMCrypto_Initialize(void) { if (crypto_engine != nullptr) { LOGE("------------------------- Calling Initialize without Terminate\n"); @@ -172,11 +150,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateDerivedKeys( enc_key_context, enc_key_context + enc_key_context_length); // Generate mac and encryption keys for current session context - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), mac_ctx_str, - enc_ctx_str)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; + return session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), mac_ctx_str, + enc_ctx_str); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, @@ -278,15 +253,15 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_PrepAndSignProvisioningRequest( signature_length); } -bool RangeCheck(const uint8_t* message, uint32_t message_length, - const uint8_t* field, uint32_t field_length, bool allow_null) { +bool RangeCheck(const uint8_t* message, size_t message_length, + const uint8_t* field, size_t field_length, bool allow_null) { if (field == nullptr) return allow_null; if (field < message) return false; if (field + field_length > message + message_length) return false; return true; } -bool RangeCheck(uint32_t message_length, const OEMCrypto_Substring& substring, +bool RangeCheck(size_t message_length, const OEMCrypto_Substring& substring, bool allow_null) { if (!substring.length) return allow_null; if (substring.offset > message_length) return false; @@ -554,9 +529,12 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl( return OEMCrypto_ERROR_UNKNOWN_FAILURE; } uint32_t* block = reinterpret_cast(key_control_block); - if ((key_control_block_length == nullptr) || - (*key_control_block_length < wvoec::KEY_CONTROL_SIZE)) { + if (key_control_block_length == nullptr) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (*key_control_block_length < wvoec::KEY_CONTROL_SIZE) { LOGE("[OEMCrypto_QueryKeyControl(): OEMCrypto_ERROR_SHORT_BUFFER]"); + *key_control_block_length = wvoec::KEY_CONTROL_SIZE; return OEMCrypto_ERROR_SHORT_BUFFER; } *key_control_block_length = wvoec::KEY_CONTROL_SIZE; @@ -572,6 +550,9 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_QueryKeyControl( LOGE("[OEMCrypto_QueryKeyControl(): ERROR_INVALID_SESSION]"); return OEMCrypto_ERROR_INVALID_SESSION; } + if (key_id_length > wvoec::KEY_ID_SIZE || key_id_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } const std::vector key_id_str = std::vector(key_id, key_id + key_id_length); if (!session_ctx->QueryKeyControlBlock(key_id_str, block)) { @@ -596,7 +577,9 @@ OEMCrypto_SelectKey(const OEMCrypto_SESSION session, const uint8_t* key_id, LOGE("[OEMCrypto_SelectKey(): ERROR_INVALID_SESSION]"); return OEMCrypto_ERROR_INVALID_SESSION; } - + if (key_id_length > wvoec::KEY_ID_SIZE || key_id_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } const std::vector key_id_str = std::vector(key_id, key_id + key_id_length); return session_ctx->SelectContentKey(key_id_str, cipher_mode); @@ -631,7 +614,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_DecryptCENC( } #endif // The maximum subsample and sample sizes we use -- if 0, we just pick a - // very large size for a sanity check. + // very large size for a validity check. const size_t max_subsample_size = crypto_engine->max_subsample_size() > 0 ? crypto_engine->max_subsample_size() : 100 * 1024 * 1024; @@ -733,7 +716,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert( } OEMCRYPTO_API OEMCryptoResult -OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* keybox, size_t keyBoxLength) { +OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* keybox, size_t keybox_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_InstallKeyboxOrOEMCert: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -741,10 +724,7 @@ OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* keybox, size_t keyBoxLength) { if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - if (crypto_engine->InstallKeybox(keybox, keyBoxLength)) { - return OEMCrypto_SUCCESS; - } - return OEMCrypto_ERROR_WRITE_KEYBOX; + return crypto_engine->InstallKeybox(keybox, keybox_length); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, @@ -756,10 +736,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - if (crypto_engine->UseTestKeybox(buffer, length)) { - return OEMCrypto_SUCCESS; - } - return OEMCrypto_ERROR_UNKNOWN_FAILURE; + return crypto_engine->InstallTestKeybox(buffer, length); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { @@ -771,22 +748,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { case OEMCrypto_DrmCertificate: return OEMCrypto_SUCCESS; case OEMCrypto_Keybox: - switch (crypto_engine->ValidateKeybox()) { - case NO_ERROR: - return OEMCrypto_SUCCESS; - case BAD_CRC: - return OEMCrypto_ERROR_BAD_CRC; - case BAD_MAGIC: - return OEMCrypto_ERROR_BAD_MAGIC; - default: - case OTHER_ERROR: - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - break; case OEMCrypto_OEMCertificate: - // TODO(fredgc): verify that the certificate exists and is valid. - return OEMCrypto_SUCCESS; - break; + return crypto_engine->IsKeyboxOrOemCertValid(); default: LOGE("Invalid provisioning method: %d.", crypto_engine->config_provisioning_method()); @@ -818,7 +781,7 @@ OEMCrypto_LoadOEMPrivateKey(OEMCrypto_SESSION session) { LOGE("OEMCrypto_ERROR_INVALID_SESSION"); return OEMCrypto_ERROR_INVALID_SESSION; } - return crypto_engine->load_oem_private_key(session_ctx); + return session_ctx->LoadOemPrivateKey(); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( @@ -832,35 +795,21 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( crypto_engine->config_provisioning_method()); return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - return crypto_engine->get_oem_certificate(public_cert, public_cert_length); + return crypto_engine->GetOemPublicCertificate(public_cert, + public_cert_length); } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, - size_t* idLength) { +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, + size_t* device_id_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_GetDeviceID: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - const std::vector& dev_id_string = crypto_engine->DeviceRootId(); - if (dev_id_string.empty()) { - LOGE("[OEMCrypto_GetDeviceId(): Keybox Invalid]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - - size_t dev_id_len = dev_id_string.size(); - if (*idLength < dev_id_len) { - *idLength = dev_id_len; - LOGE("[OEMCrypto_GetDeviceId(): ERROR_SHORT_BUFFER]"); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - memset(deviceID, 0, *idLength); - memcpy(deviceID, &dev_id_string[0], dev_id_len); - *idLength = dev_id_len; - return OEMCrypto_SUCCESS; + return crypto_engine->GetDeviceRootId(device_id, device_id_length); } -OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, - size_t* keyDataLength) { +OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* key_data, + size_t* key_data_length) { if (crypto_engine == nullptr) { LOGE("OEMCrypto_GetKeyData: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; @@ -868,24 +817,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - size_t length = crypto_engine->DeviceRootTokenLength(); - if (keyDataLength == nullptr) { - LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (*keyDataLength < length) { - *keyDataLength = length; - LOGE("[OEMCrypto_GetKeyData(): ERROR_SHORT_BUFFER]"); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (keyData == nullptr) { - LOGE("[OEMCrypto_GetKeyData(): null pointer. ERROR_UNKNOWN_FAILURE]"); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - memset(keyData, 0, *keyDataLength); - memcpy(keyData, crypto_engine->DeviceRootToken(), length); - *keyDataLength = length; - return OEMCrypto_SUCCESS; + return crypto_engine->GetRootKeyData(key_data, key_data_length); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, @@ -897,207 +829,12 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, if (!randomData) { return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (RAND_bytes(randomData, dataLength) == 1) { + if (RAND_bytes(randomData, static_cast(dataLength)) == 1) { return OEMCrypto_SUCCESS; } return OEMCrypto_ERROR_UNKNOWN_FAILURE; } -// This function is no longer exported -- it is only used by LoadProvisioning. -static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey30( - OEMCrypto_SESSION session, const uint32_t* unaligned_nonce, - const uint8_t* encrypted_message_key, size_t encrypted_message_key_length, - const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, - size_t* wrapped_rsa_key_length) { - uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce); - if (unaligned_nonce == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_RewrapDeviceRSAKey30: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (wrapped_rsa_key_length == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (encrypted_message_key == nullptr || encrypted_message_key_length == 0 || - enc_rsa_key == nullptr || enc_rsa_key_iv == nullptr || - unaligned_nonce == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // Validate nonce - if (!session_ctx->CheckNonce(nonce)) { - return OEMCrypto_ERROR_INVALID_NONCE; - } - - if (!session_ctx->InstallRSAEncryptedKey(encrypted_message_key, - encrypted_message_key_length)) { - LOGE( - "OEMCrypto_RewrapDeviceRSAKey30: " - "Error loading encrypted_message_key."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Decrypt RSA key. - std::vector pkcs8_rsa_key(enc_rsa_key_length); - if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, &pkcs8_rsa_key[0])) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey30(): Failed to LoadRSAKey."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - // Now we generate a wrapped keybox. - WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); - // Pick a random context and IV for generating keys. - if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) { - LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) { - LOGE("[_RewrapDeviceRSAKey30(): RAND_bytes failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const std::vector context( - wrapped->context, wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, - context)) { - LOGE("[_RewrapDeviceRSAKey30(): DeriveKeys failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Encrypt rsa key with keybox. - if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - LOGE("[_RewrapDeviceRSAKey30(): EncrypteRSAKey failed."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey); - // The wrapped keybox must be signed with the same key we verify with. I'll - // pick the server key, so I don't have to modify LoadRSAKey. - unsigned int sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - session_ctx->mac_key_server().size(), wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - -// This function is no longer exported -- it is only used by LoadProvisioning. -static OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( - OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, - const uint8_t* signature, size_t signature_length, - const uint32_t* unaligned_nonce, const uint8_t* enc_rsa_key, - size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, - uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) { - uint32_t nonce = unaligned_dereference_uint32(unaligned_nonce); - if (unaligned_nonce == nullptr) { - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (crypto_engine == nullptr) { - LOGE("OEMCrypto_RewrapDeviceRSAKey: OEMCrypto Not Initialized."); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (wrapped_rsa_key_length == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_KEYBOX_INVALID]"); - return OEMCrypto_ERROR_KEYBOX_INVALID; - } - SessionContext* session_ctx = crypto_engine->FindSession(session); - if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): ERROR_INVALID_SESSION]"); - return OEMCrypto_ERROR_INVALID_SESSION; - } - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0 || unaligned_nonce == nullptr || - enc_rsa_key == nullptr) { - LOGE("[OEMCrypto_RewrapDeviceRSAKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - // verify signature. - if (!session_ctx->ValidateMessage(message, message_length, signature, - signature_length)) { - LOGE("[RewrapDeviceRSAKey(): Could not verify signature]"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - - // Range check performed by ODK library. - - // Validate nonce - if (!session_ctx->CheckNonce(nonce)) { - return OEMCrypto_ERROR_INVALID_NONCE; - } - - // Decrypt RSA key and verify it. - std::vector pkcs8_rsa_key(enc_rsa_key_length); - if (!session_ctx->DecryptRSAKey(enc_rsa_key, enc_rsa_key_length, - enc_rsa_key_iv, &pkcs8_rsa_key[0])) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length)) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - // Now we generate a wrapped keybox. - WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key); - // Pick a random context and IV for generating keys. - if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const std::vector context( - wrapped->context, wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, - context)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Encrypt rsa key with keybox. - if (!session_ctx->EncryptRSAKey(&pkcs8_rsa_key[0], enc_rsa_key_length, - wrapped->iv, wrapped->enc_rsa_key)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - const size_t buffer_size = enc_rsa_key_length + sizeof(WrappedRSAKey); - // The wrapped keybox must be signed with the same key we verify with. I'll - // pick the server key, so I don't have to modify LoadRSAKey. - unsigned int sig_length = sizeof(wrapped->signature); - if (!HMAC(EVP_sha256(), &session_ctx->mac_key_server()[0], - session_ctx->mac_key_server().size(), wrapped->context, - buffer_size - sizeof(wrapped->signature), wrapped->signature, - &sig_length)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; -} - OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, size_t core_message_length, const uint8_t* signature, @@ -1107,11 +844,6 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning( LOGE("OEMCrypto Not Initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (wrapped_private_key_length == nullptr || message == nullptr || - message_length == 0 || signature == nullptr || signature_length == 0) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } if (!crypto_engine->ValidRootOfTrust()) { LOGE("OEMCrypto_ERROR_KEYBOX_INVALID"); return OEMCrypto_ERROR_KEYBOX_INVALID; @@ -1121,132 +853,50 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadProvisioning( LOGE("OEMCrypto_ERROR_INVALID_SESSION"); return OEMCrypto_ERROR_INVALID_SESSION; } - std::vector device_id = crypto_engine->DeviceRootId(); - ODK_ParsedProvisioning parsed_response; - const uint32_t nonce = session_ctx->nonce(); - const OEMCryptoResult result = - ODK_ParseProvisioning(message, message_length, core_message_length, - &(session_ctx->nonce_values()), device_id.data(), - device_id.size(), &parsed_response); - if (result != OEMCrypto_SUCCESS) { - LOGE("ODK Error %d", result); - return result; - } - - // For the reference implementation, the wrapped key and the encrypted - // key are the same size -- just encrypted with different keys. - // We add 32 bytes for a context, 32 for iv, and 32 bytes for a signature. - // Important: This layout must match OEMCrypto_LoadDRMPrivateKey below. - const size_t buffer_size = - parsed_response.enc_private_key.length + sizeof(WrappedRSAKey); - - if (wrapped_private_key == nullptr || - *wrapped_private_key_length < buffer_size) { - *wrapped_private_key_length = buffer_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *wrapped_private_key_length = - buffer_size; // Tell caller how much space we used. - const uint8_t* message_body = message + core_message_length; - if (crypto_engine->config_provisioning_method() == OEMCrypto_Keybox) { - return OEMCrypto_RewrapDeviceRSAKey( - session, message, message_length, signature, signature_length, &nonce, - message_body + parsed_response.enc_private_key.offset, - parsed_response.enc_private_key.length, - message_body + parsed_response.enc_private_key_iv.offset, - wrapped_private_key, wrapped_private_key_length); - } else if (crypto_engine->config_provisioning_method() == - OEMCrypto_OEMCertificate) { - return OEMCrypto_RewrapDeviceRSAKey30( - session, &nonce, - message_body + parsed_response.encrypted_message_key.offset, - parsed_response.encrypted_message_key.length, - message_body + parsed_response.enc_private_key.offset, - parsed_response.enc_private_key.length, - message_body + parsed_response.enc_private_key_iv.offset, - wrapped_private_key, wrapped_private_key_length); - } else { - LOGE("Invalid provisioning method: %d.", - crypto_engine->config_provisioning_method()); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } + return session_ctx->LoadProvisioning( + message, message_length, core_message_length, signature, signature_length, + wrapped_private_key, wrapped_private_key_length); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadDRMPrivateKey( OEMCrypto_SESSION session, OEMCrypto_PrivateKeyType key_type, - const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length) { - if (wrapped_rsa_key == nullptr) { + const uint8_t* wrapped_drm_key, size_t wrapped_drm_key_length) { + if (wrapped_drm_key == nullptr) { LOGE("OEMCrypto_ERROR_INVALID_CONTEXT nullptr"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (crypto_engine == nullptr) { - LOGE("OEMCrypto Not Initialized."); + LOGE("OEMCrypto not initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (key_type != OEMCrypto_RSA_Private_Key) { - LOGE("ECC keys not yet supported in reference code."); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + if (key_type != OEMCrypto_RSA_Private_Key && + key_type != OEMCrypto_ECC_Private_Key) { + LOGE("Unknown key type: type = %x", static_cast(key_type)); + return OEMCrypto_ERROR_INVALID_CONTEXT; } if (crypto_engine->config_provisioning_method() == OEMCrypto_DrmCertificate) { - // If we are using a baked in cert, the "wrapped RSA key" should actually be + // If we are using a baked in cert, |wrapped_drm_key| should actually be // the magic value for baked-in certificates. - if (wrapped_rsa_key_length != sizeof(kBakedInCertificateMagicBytes) || - memcmp(kBakedInCertificateMagicBytes, wrapped_rsa_key, - wrapped_rsa_key_length) != 0) { - LOGE("Baked in Cert has wrong size."); + if (wrapped_drm_key_length != sizeof(kBakedInCertificateMagicBytes) || + memcmp(kBakedInCertificateMagicBytes, wrapped_drm_key, + wrapped_drm_key_length) != 0) { + LOGE("Baked in Cert has wrong size"); return OEMCrypto_ERROR_INVALID_RSA_KEY; - } else { - return OEMCrypto_SUCCESS; } + return OEMCrypto_SUCCESS; } - if (wrapped_rsa_key_length < sizeof(WrappedRSAKey)) { - LOGE("RSA Key has wrong size."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - const WrappedRSAKey* wrapped = - reinterpret_cast(wrapped_rsa_key); if (!crypto_engine->ValidRootOfTrust()) { LOGE("ERROR_KEYBOX_INVALID"); return OEMCrypto_ERROR_KEYBOX_INVALID; } - SessionContext* session_ctx = crypto_engine->FindSession(session); if (session_ctx == nullptr || !session_ctx->isValid()) { LOGE("ERROR_INVALID_SESSION"); return OEMCrypto_ERROR_INVALID_SESSION; } - const std::vector context( - wrapped->context, wrapped->context + sizeof(wrapped->context)); - // Generate mac and encryption keys for encrypting the signature. - if (!session_ctx->DeriveKeys(crypto_engine->DeviceRootKey(), context, - context)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - // verify signature. - if (!session_ctx->ValidateMessage( - wrapped->context, wrapped_rsa_key_length - sizeof(wrapped->signature), - wrapped->signature, sizeof(wrapped->signature))) { - LOGE("Could not verify signature"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - // Decrypt RSA key. - std::vector pkcs8_rsa_key(wrapped_rsa_key_length - - sizeof(wrapped->signature)); - size_t enc_rsa_key_length = wrapped_rsa_key_length - sizeof(WrappedRSAKey); - if (!session_ctx->DecryptRSAKey(wrapped->enc_rsa_key, enc_rsa_key_length, - wrapped->iv, &pkcs8_rsa_key[0])) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - size_t padding = pkcs8_rsa_key[enc_rsa_key_length - 1]; - if (padding > 16) { - // Do not return an error at this point, to avoid a padding oracle attack. - padding = 0; - } - size_t rsa_key_length = enc_rsa_key_length - padding; - if (!session_ctx->LoadRSAKey(&pkcs8_rsa_key[0], rsa_key_length)) { - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - return OEMCrypto_SUCCESS; + return session_ctx->LoadWrappedDrmKey(crypto_engine->DeviceRootKey(), + key_type, wrapped_drm_key, + wrapped_drm_key_length); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey() { @@ -1254,8 +904,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey() { LOGE("OEMCrypto_LoadTestRSAKey: OEMCrypto Not Initialized."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (crypto_engine->LoadTestRsaKey()) return OEMCrypto_SUCCESS; - return OEMCrypto_ERROR_UNKNOWN_FAILURE; + return crypto_engine->LoadTestRsaKey(); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( @@ -1267,7 +916,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - if (signature_length == 0) { + if (signature_length == nullptr) { LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]"); return OEMCrypto_ERROR_INVALID_CONTEXT; } @@ -1277,67 +926,46 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( LOGE("[OEMCrypto_GenerateRSASignature(): ERROR_INVALID_SESSION]"); return OEMCrypto_ERROR_INVALID_SESSION; } - - size_t required_size = session_ctx->RSASignatureSize(); - if (*signature_length < required_size) { - *signature_length = required_size; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("[OEMCrypto_GenerateRSASignature(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - - OEMCryptoResult sts = session_ctx->GenerateRSASignature( - message, message_length, signature, signature_length, padding_scheme); - return sts; + return session_ctx->GenerateRsaSignature(message, message_length, signature, + signature_length, padding_scheme); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( - OEMCrypto_SESSION session, const uint8_t* enc_session_key, - size_t enc_session_key_length, const uint8_t* mac_key_context, + OEMCrypto_SESSION session, const uint8_t* session_key_source, + size_t session_key_source_length, const uint8_t* mac_key_context, size_t mac_key_context_length, const uint8_t* enc_key_context, size_t enc_key_context_length) { if (crypto_engine == nullptr) { - LOGE("OEMCrypto_DeriveKeysFromSessionKey: OEMCrypto Not Initialized."); + LOGE("OEMCrypto_DeriveKeysFromSessionKey: OEMCrypto not initialized"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } if (!crypto_engine->ValidRootOfTrust()) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_KEYBOX_INVALID]"); + LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_KEYBOX_INVALID]"); return OEMCrypto_ERROR_KEYBOX_INVALID; } if (mac_key_context_length > kMaxContextKeyLength || enc_key_context_length > kMaxContextKeyLength || - enc_session_key_length > kMaxContextKeyLength) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_BUFFER_TOO_LARGE]"); + session_key_source_length > kMaxContextKeyLength) { + LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_BUFFER_TOO_LARGE]"); return OEMCrypto_ERROR_BUFFER_TOO_LARGE; } SessionContext* session_ctx = crypto_engine->FindSession(session); if (session_ctx == nullptr || !session_ctx->isValid()) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): ERROR_INVALID_SESSION]"); + LOGE("[OEMCrypto_DeriveKeysFromSessionKey(): ERROR_INVALID_SESSION]"); return OEMCrypto_ERROR_INVALID_SESSION; } - if (session_ctx->allowed_schemes() != kSign_RSASSA_PSS) { - LOGE("[OEMCrypto_GenerateDerivedKeys(): x509 key used to derive keys]"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - const std::vector ssn_key_str( - enc_session_key, enc_session_key + enc_session_key_length); - const std::vector mac_ctx_str( + const std::vector session_key_source_vec( + session_key_source, session_key_source + session_key_source_length); + const std::vector mac_ctx_vec( mac_key_context, mac_key_context + mac_key_context_length); - const std::vector enc_ctx_str( + const std::vector enc_ctx_vec( enc_key_context, enc_key_context + enc_key_context_length); - // Generate mac and encryption keys for current session context - if (!session_ctx->RSADeriveKeys(ssn_key_str, mac_ctx_str, enc_ctx_str)) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; + // Generate mac and encryption keys for current session context. + return session_ctx->DeriveKeysWithSessionKey(session_key_source_vec, + mac_ctx_vec, enc_ctx_vec); } OEMCRYPTO_API uint32_t OEMCrypto_APIVersion() { @@ -1349,13 +977,19 @@ OEMCRYPTO_API uint32_t OEMCrypto_MinorAPIVersion() { } OEMCRYPTO_API uint8_t OEMCrypto_Security_Patch_Level() { - uint8_t security_patch_level = crypto_engine->config_security_patch_level(); - return security_patch_level; + if (!crypto_engine) { + LOGE("OEMCrypto_Security_Patch_Level: OEMCrypto Not Initialized."); + return 0; + } + return crypto_engine->config_security_patch_level(); } OEMCRYPTO_API const char* OEMCrypto_SecurityLevel() { - const char* security_level = crypto_engine->config_security_level(); - return security_level; + if (!crypto_engine) { + LOGE("OEMCrypto_SecurityLevel: OEMCrypto Not Initialized."); + return nullptr; + } + return crypto_engine->config_security_level(); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetHDCPCapability( @@ -1445,7 +1079,7 @@ OEMCRYPTO_API uint32_t OEMCrypto_SupportedCertificates() { return 0; } return OEMCrypto_Supports_RSA_2048bit | OEMCrypto_Supports_RSA_3072bit | - OEMCrypto_Supports_RSA_CAST; + OEMCrypto_Supports_RSA_CAST | OEMCrypto_Supports_ECC_secp256r1; } OEMCRYPTO_API OEMCryptoResult OEMCrypto_Generic_Encrypt( @@ -1832,4 +1466,23 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_FreeSecureBuffer( return OEMCrypto_ERROR_NOT_IMPLEMENTED; } +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_GenerateOTARequest(OEMCrypto_SESSION session, uint8_t* buffer, + size_t* buffer_length, uint32_t use_test_key) { + LOGW("Keybox OTA functionality not yet implemented."); + if (buffer_length == nullptr) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + +OEMCRYPTO_API OEMCryptoResult +OEMCrypto_ProcessOTAKeybox(OEMCrypto_SESSION session, const uint8_t* buffer, + size_t buffer_length, uint32_t use_test_key) { + LOGW("Keybox OTA functionality not yet implemented."); + if (buffer == nullptr || buffer_length == 0) { + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} } // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_rsa_key.cpp b/oemcrypto/ref/src/oemcrypto_rsa_key.cpp new file mode 100644 index 0000000..f341a5a --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_rsa_key.cpp @@ -0,0 +1,1174 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include "oemcrypto_rsa_key.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oemcrypto_types.h" +#include "scoped_object.h" + +namespace wvoec_ref { +namespace { +// Estimated size of an RSA private key. +// The private key constists of: +// n : Modulos : byteSize(n) ~= bitSize(n)/8 +// e : Public exponent : 4 bytes +// d : Private exponent : ~byteSize(n) +// p : Prime 1 : ~byteSize(n)/2 +// q : Prime 2 : ~byteSize(n)/2 +// d (mod p-1) : Exponent 1 : ~byteSize(n)/2 +// d (mod q-1) : Exponent 2 : ~byteSize(n)/2 +// q^-1 (mod p) : Coefficient : ~byteSize(n)/2 +// And the ASN.1 tags for each component (roughly 25 bytes). +constexpr size_t kPrivateKeySize = (3072 / 8) * 5 + 25; +// Estimated size of an RSA public key. +// The public key constists of: +// The private key constists of: +// n : Modulos : byteSize(n) ~= bitSize(n)/8 +// e : Public exponent : 4 bytes +// And the ASN.1 tags + outer structure. +constexpr size_t kPublicKeySize = (3072 / 8) + 100; + +// 128 bit key, intended to be used with CMAC-AES-128. +constexpr size_t kRsaSessionKeySize = 16; +// Encryption key used by OEMCrypto session for encrypting and +// decrypting data. +constexpr size_t kEncryptionKeySize = wvoec::KEY_SIZE; + +// Salt length used by OEMCrypto's RSASSA-PSS implementation. +// See description of kRsaPssDefault for more information. +constexpr size_t kPssSaltLength = 20; +// Requirement of CAST receivers. +constexpr size_t kRsaPkcs1CastMaxMessageSize = 83; + +using ScopedBigNum = ScopedObject; +using ScopedBio = ScopedObject; +using ScopedEvpMdCtx = ScopedObject; +using ScopedEvpPkey = ScopedObject; +using ScopedPrivateKeyInfo = + ScopedObject; +using ScopedRsaKey = ScopedObject; + +// Estimates the RSA rough field size from the real bit size of the +// RSA modulos. The actual bit length could vary by a few bits. +RsaFieldSize RealBitSizeToFieldSize(int bits) { + if (bits > 1800 && bits < 2200) { + return kRsa2048Bit; + } + if (bits > 2800 && bits < 3200) { + return kRsa3072Bit; + } + return kRsaFieldUnknown; +} +} // namespace + +std::string RsaFieldSizeToString(RsaFieldSize field_size) { + switch (field_size) { + case kRsa2048Bit: + return "RSA-2048"; + case kRsa3072Bit: + return "RSA-3072"; + case kRsaFieldUnknown: + return "Unknown"; + } + return "Unknown(" + std::to_string(static_cast(field_size)) + ")"; +} + +bool RsaKeysAreMatchingPair(const RSA* public_key, const RSA* private_key) { + if (public_key == nullptr) { + LOGE("Public key is null"); + return false; + } + if (private_key == nullptr) { + LOGE("Private key is null"); + return false; + } + // Step 1: Extract public key components. + const BIGNUM* public_n = nullptr; + const BIGNUM* public_e = nullptr; + const BIGNUM* d = nullptr; + RSA_get0_key(public_key, &public_n, &public_e, &d); + if (public_n == nullptr || public_e == nullptr) { + LOGE("Failed to get RSA public key components"); + return false; + } + // Step 2: Extract private key components. + const BIGNUM* private_n = nullptr; + const BIGNUM* private_e = nullptr; + RSA_get0_key(private_key, &private_n, &private_e, &d); + if (private_n == nullptr || private_e == nullptr) { + LOGE("Failed to get RSA private key components"); + return false; + } + // Step 3: Compare RSA components. + if (BN_cmp(public_n, private_n)) { + LOGD("RSA modulos do not match"); + return false; + } + if (BN_cmp(public_e, private_e)) { + LOGD("RSA exponents do not match"); + return false; + } + return true; +} + +// ===== ===== ===== RSA Public Key ===== ===== ===== + +// static +std::unique_ptr RsaPublicKey::New( + const RsaPrivateKey& private_key) { + std::unique_ptr key(new RsaPublicKey()); + if (!key->InitFromPrivateKey(private_key)) { + LOGE("Failed to initialize public key from private key"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr RsaPublicKey::Load(const uint8_t* buffer, + size_t length) { + std::unique_ptr key; + if (buffer == nullptr) { + LOGE("Provided public key buffer is null"); + return key; + } + if (length == 0) { + LOGE("Provided public key buffer is zero length"); + return key; + } + key.reset(new RsaPublicKey()); + if (!key->InitFromBuffer(buffer, length)) { + LOGE("Failed to initialize public key from buffer"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr RsaPublicKey::Load(const std::string& buffer) { + if (buffer.empty()) { + LOGE("Provided public key buffer is empty"); + return std::unique_ptr(); + } + return Load(reinterpret_cast(buffer.data()), buffer.size()); +} + +// static +std::unique_ptr RsaPublicKey::Load( + const std::vector& buffer) { + std::unique_ptr key; + if (buffer.empty()) { + LOGE("Provided public key buffer is empty"); + return std::unique_ptr(); + } + return Load(buffer.data(), buffer.size()); +} + +bool RsaPublicKey::IsMatchingPrivateKey( + const RsaPrivateKey& private_key) const { + if (private_key.field_size() != field_size_) { + return false; + } + return RsaKeysAreMatchingPair(GetRsaKey(), private_key.GetRsaKey()); +} + +OEMCryptoResult RsaPublicKey::Serialize(uint8_t* buffer, + size_t* buffer_size) const { + if (buffer_size == nullptr) { + LOGE("Output buffer size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (buffer == nullptr && *buffer_size > 0) { + LOGE("Output buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + + uint8_t* der_key = nullptr; + const int der_res = i2d_RSA_PUBKEY(key_, &der_key); + if (der_res < 0) { + LOGE("Public key serialization failed"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (der_key == nullptr) { + LOGE("Encoded key is unexpectedly null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (der_res == 0) { + LOGE("Unexpected DER encoded size"); + OPENSSL_free(der_key); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + const size_t required_size = static_cast(der_res); + if (buffer == nullptr || *buffer_size < required_size) { + *buffer_size = required_size; + OPENSSL_free(der_key); + return OEMCrypto_ERROR_SHORT_BUFFER; + } + memcpy(buffer, der_key, required_size); + *buffer_size = required_size; + OPENSSL_free(der_key); + return OEMCrypto_SUCCESS; +} + +std::vector RsaPublicKey::Serialize() const { + size_t key_size = kPublicKeySize; + std::vector key_data(key_size, 0); + const OEMCryptoResult res = Serialize(key_data.data(), &key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to serialize public key: result = %d", static_cast(res)); + key_data.clear(); + } else { + key_data.resize(key_size); + } + return key_data; +} + +OEMCryptoResult RsaPublicKey::VerifySignature( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length, RsaSignatureAlgorithm algorithm) const { + if (signature == nullptr || signature_length == 0) { + LOGE("Signature is missing"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (message == nullptr && message_length > 0) { + LOGE("Bad message data"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + switch (algorithm) { + case kRsaPssDefault: + return VerifySignaturePss(message, message_length, signature, + signature_length); + case kRsaPkcs1Cast: + return VerifySignaturePkcs1Cast(message, message_length, signature, + signature_length); + } + LOGE("Unknown RSA signature algorithm: %d", static_cast(algorithm)); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +OEMCryptoResult RsaPublicKey::VerifySignature( + const std::string& message, const std::string& signature, + RsaSignatureAlgorithm algorithm) const { + if (signature.empty()) { + LOGE("Signature should not be empty"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return VerifySignature(reinterpret_cast(message.data()), + message.size(), + reinterpret_cast(signature.data()), + signature.size(), algorithm); +} + +OEMCryptoResult RsaPublicKey::VerifySignature( + const std::vector& message, const std::vector& signature, + RsaSignatureAlgorithm algorithm) const { + if (signature.empty()) { + LOGE("Signature should not be empty"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return VerifySignature(message.data(), message.size(), signature.data(), + signature.size(), algorithm); +} + +OEMCryptoResult RsaPublicKey::EncryptSessionKey( + const uint8_t* session_key, size_t session_key_size, + uint8_t* enc_session_key, size_t* enc_session_key_size) const { + if (session_key == nullptr) { + LOGE("Session key is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (session_key_size != kRsaSessionKeySize) { + LOGE("Unexpected session key size: expected = %zu, actual = %zu", + kRsaSessionKeySize, session_key_size); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (enc_session_key_size == nullptr) { + LOGE("Output encrypted session key size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (enc_session_key == nullptr && *enc_session_key_size > 0) { + LOGE("Output encrypted session key is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return EncryptOaep(session_key, session_key_size, enc_session_key, + enc_session_key_size); +} + +std::vector RsaPublicKey::EncryptSessionKey( + const std::vector& session_key) const { + if (session_key.empty()) { + LOGE("Session key is empty"); + return std::vector(); + } + size_t enc_session_key_size = static_cast(RSA_size(key_)); + std::vector enc_session_key(enc_session_key_size); + const OEMCryptoResult res = + EncryptSessionKey(session_key.data(), session_key.size(), + enc_session_key.data(), &enc_session_key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to encrypt session key: result = %d", static_cast(res)); + enc_session_key.clear(); + } else { + enc_session_key.resize(enc_session_key_size); + } + return enc_session_key; +} + +std::vector RsaPublicKey::EncryptSessionKey( + const std::string& session_key) const { + if (session_key.empty()) { + LOGE("Session key is empty"); + return std::vector(); + } + size_t enc_session_key_size = static_cast(RSA_size(key_)); + std::vector enc_session_key(enc_session_key_size); + const OEMCryptoResult res = EncryptSessionKey( + reinterpret_cast(session_key.data()), session_key.size(), + enc_session_key.data(), &enc_session_key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to encrypt session key: result = %d", static_cast(res)); + enc_session_key.clear(); + } else { + enc_session_key.resize(enc_session_key_size); + } + return enc_session_key; +} + +OEMCryptoResult RsaPublicKey::EncryptEncryptionKey( + const uint8_t* encryption_key, size_t encryption_key_size, + uint8_t* enc_encryption_key, size_t* enc_encryption_key_size) const { + if (encryption_key == nullptr) { + LOGE("Encryption key is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (encryption_key_size != kEncryptionKeySize) { + LOGE("Unexpected encryption key size: expected = %zu, actual = %zu", + kEncryptionKeySize, encryption_key_size); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (enc_encryption_key_size == nullptr) { + LOGE("Output encrypted encryption key size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (enc_encryption_key == nullptr && *enc_encryption_key_size > 0) { + LOGE("Output encrypted encryption key is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + return EncryptOaep(encryption_key, encryption_key_size, enc_encryption_key, + enc_encryption_key_size); +} + +std::vector RsaPublicKey::EncryptEncryptionKey( + const std::vector& encryption_key) const { + if (encryption_key.empty()) { + LOGE("Session key is empty"); + return std::vector(); + } + size_t enc_encryption_key_size = static_cast(RSA_size(key_)); + std::vector enc_encryption_key(enc_encryption_key_size); + const OEMCryptoResult res = + EncryptSessionKey(encryption_key.data(), encryption_key.size(), + enc_encryption_key.data(), &enc_encryption_key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to encrypt encryption key: result = %d", + static_cast(res)); + enc_encryption_key.clear(); + } else { + enc_encryption_key.resize(enc_encryption_key_size); + } + return enc_encryption_key; +} + +std::vector RsaPublicKey::EncryptEncryptionKey( + const std::string& encryption_key) const { + if (encryption_key.empty()) { + LOGE("Session key is empty"); + return std::vector(); + } + size_t enc_encryption_key_size = static_cast(RSA_size(key_)); + std::vector enc_encryption_key(enc_encryption_key_size); + const OEMCryptoResult res = + EncryptSessionKey(reinterpret_cast(encryption_key.data()), + encryption_key.size(), enc_encryption_key.data(), + &enc_encryption_key_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to encrypt encryption key: result = %d", + static_cast(res)); + enc_encryption_key.clear(); + } else { + enc_encryption_key.resize(enc_encryption_key_size); + } + return enc_encryption_key; +} + +RsaPublicKey::~RsaPublicKey() { + if (key_ != nullptr) { + RSA_free(key_); + key_ = nullptr; + } + allowed_schemes_ = 0; + field_size_ = kRsaFieldUnknown; +} + +bool RsaPublicKey::InitFromBuffer(const uint8_t* buffer, size_t length) { + // Step 1: Deserialize SubjectPublicKeyInfo as RSA key. + const uint8_t* tp = buffer; + ScopedRsaKey key(d2i_RSA_PUBKEY(nullptr, &tp, length)); + if (!key) { + LOGE("Failed to parse key"); + return false; + } + // Step 2: Verify key. + const int bits = RSA_bits(key.get()); + field_size_ = RealBitSizeToFieldSize(bits); + if (field_size_ == kRsaFieldUnknown) { + LOGE("Unsupported RSA key size: bits = %d", bits); + return false; + } + allowed_schemes_ = kSign_RSASSA_PSS; + key_ = key.release(); + return true; +} + +bool RsaPublicKey::InitFromPrivateKey(const RsaPrivateKey& private_key) { + ScopedRsaKey key(RSA_new()); + if (!key) { + LOGE("Failed to allocate key"); + return false; + } + const BIGNUM* n = nullptr; + const BIGNUM* e = nullptr; + const BIGNUM* d = nullptr; + RSA_get0_key(private_key.GetRsaKey(), &n, &e, &d); + if (n == nullptr || e == nullptr) { + LOGE("Failed to get RSA private key components"); + return false; + } + ScopedBigNum dub_n(BN_dup(n)); + ScopedBigNum dub_e(BN_dup(e)); + if (!dub_n || !dub_e) { + LOGE("Failed to duplicate RSA public key components"); + return false; + } + if (!RSA_set0_key(key.get(), dub_n.get(), dub_e.get(), nullptr)) { + LOGE("Failed to RSA public key components"); + return false; + } + // Ownership has transferred to the RSA key. + dub_n.release(); + dub_e.release(); + + key_ = key.release(); + allowed_schemes_ = private_key.allowed_schemes(); + field_size_ = private_key.field_size(); + return true; +} + +OEMCryptoResult RsaPublicKey::VerifySignaturePss( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length) const { + // Step 0: Ensure the signature algorithm is supported by key. + if (!(allowed_schemes_ & kSign_RSASSA_PSS)) { + LOGE("RSA key cannot verify using PSS"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + // Step 1: Create a high-level key from RSA key. + ScopedEvpPkey pkey(EVP_PKEY_new()); + if (!pkey) { + LOGE("Failed to allocate PKEY"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!EVP_PKEY_set1_RSA(pkey.get(), key_)) { + LOGE("Failed to set PKEY RSA key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2a: Setup a EVP MD CTX for PSS Verification. + ScopedEvpMdCtx md_ctx = EVP_MD_CTX_new(); + if (!md_ctx) { + LOGE("Failed to allocate MD CTX"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + EVP_PKEY_CTX* pkey_ctx = nullptr; // Ownership is maintained by |md_ctx| + int res = EVP_DigestVerifyInit(md_ctx.get(), &pkey_ctx, EVP_sha1(), nullptr, + pkey.get()); + if (res != 1) { + LOGE("Failed to initialize MD CTX for verification"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (pkey_ctx == nullptr) { + LOGE("PKEY CTX is unexpectedly null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2b: Configure OEMCrypto RSASSA-PSS options. + res = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING); + if (res != 1) { + LOGE("Failed to set PSS padding"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + res = EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, kPssSaltLength); + if (res != 1) { + LOGE("Failed to set PSS salt length"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + res = EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha1()); + if (res != 1) { + LOGE("Failed to set PSS MGF1 MD"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 3: Digest message. + if (message_length > 0) { + res = EVP_DigestVerifyUpdate(md_ctx.get(), message, message_length); + if (res != 1) { + LOGE("Failed to update MD"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + // Step 4: Verify message. + res = EVP_DigestVerifyFinal(md_ctx.get(), signature, signature_length); + if (res < 0) { + LOGE("Failed to perform RSASSA-PSS-VERIFY"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return res ? OEMCrypto_SUCCESS : OEMCrypto_ERROR_SIGNATURE_FAILURE; +} + +OEMCryptoResult RsaPublicKey::VerifySignaturePkcs1Cast( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length) const { + // Step 0: Ensure the signature algorithm is supported by key. + if (!(allowed_schemes_ & kSign_PKCS1_Block1)) { + LOGE("RSA key cannot verify using PKCS1"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + if (message_length > kRsaPkcs1CastMaxMessageSize) { + LOGE("Message is too large for CAST PKCS1 signature: size = %zu", + message_length); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + // Step 1: Convert encrypted blob into digest. + std::vector digest(RSA_size(key_)); + const int res = + RSA_public_decrypt(static_cast(signature_length), signature, + digest.data(), key_, RSA_PKCS1_PADDING); + if (res <= 0) { + LOGE("Failed to perform public decryption"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2: Compare digests. + const size_t digest_size = static_cast(res); + if (digest_size != message_length) { + LOGD("Digest size does not match"); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + digest.resize(digest_size); + for (size_t i = 0; i < digest_size; i++) { + if (message[i] != digest[i]) { + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult RsaPublicKey::EncryptOaep(const uint8_t* message, + size_t message_size, + uint8_t* enc_message, + size_t* enc_message_length) const { + // Step 1: Encrypt using RSAES-OAEP. + std::vector encrypt_buffer(RSA_size(key_)); + const int enc_res = + RSA_public_encrypt(static_cast(message_size), message, + encrypt_buffer.data(), key_, RSA_PKCS1_OAEP_PADDING); + if (enc_res < 0) { + LOGE("Failed to perform RSAES-OAEP encrypt"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2: Copy encrypted data key. + const size_t enc_size = static_cast(enc_res); + if (*enc_message_length < enc_size) { + *enc_message_length = enc_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *enc_message_length = enc_size; + memcpy(enc_message, encrypt_buffer.data(), enc_size); + return OEMCrypto_SUCCESS; +} + +// ===== ===== ===== RSA Private Key ===== ===== ===== + +// static +std::unique_ptr RsaPrivateKey::New(RsaFieldSize field_size) { + std::unique_ptr key(new RsaPrivateKey()); + if (!key->InitFromFieldSize(field_size)) { + LOGE("Failed to initialize private key from field size"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr RsaPrivateKey::Load(const uint8_t* buffer, + size_t length) { + std::unique_ptr key; + if (buffer == nullptr) { + LOGE("Provided private key buffer is null"); + return key; + } + if (length == 0) { + LOGE("Provided private key buffer is zero length"); + return key; + } + key.reset(new RsaPrivateKey()); + if (!key->InitFromBuffer(buffer, length)) { + LOGE("Failed to initialize private key from buffer"); + key.reset(); + } + return key; +} + +// static +std::unique_ptr RsaPrivateKey::Load(const std::string& buffer) { + if (buffer.empty()) { + LOGE("Provided private key buffer is empty"); + return std::unique_ptr(); + } + return Load(reinterpret_cast(buffer.data()), buffer.size()); +} + +// static +std::unique_ptr RsaPrivateKey::Load( + const std::vector& buffer) { + if (buffer.empty()) { + LOGE("Provided private key buffer is empty"); + return std::unique_ptr(); + } + return Load(buffer.data(), buffer.size()); +} + +std::unique_ptr RsaPrivateKey::MakePublicKey() const { + return RsaPublicKey::New(*this); +} + +bool RsaPrivateKey::IsMatchingPublicKey(const RsaPublicKey& public_key) const { + return RsaKeysAreMatchingPair(public_key.GetRsaKey(), GetRsaKey()); +} + +OEMCryptoResult RsaPrivateKey::Serialize(uint8_t* buffer, + size_t* buffer_size) const { + if (buffer_size == nullptr) { + LOGE("Output buffer size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (buffer == nullptr && *buffer_size > 0) { + LOGE("Output buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // Step 1: Convert RSA key to EVP. + ScopedEvpPkey pkey(EVP_PKEY_new()); + if (!pkey) { + LOGE("Failed to allocate EVP"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!EVP_PKEY_set1_RSA(pkey.get(), key_)) { + LOGE("Failed to set EVP RSA key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2: Convert RSA EVP to PKCS8 format. + ScopedPrivateKeyInfo priv_info(EVP_PKEY2PKCS8(pkey.get())); + if (!priv_info) { + LOGE("Failed to convert RSA key to PKCS8 info"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 3: Serialize PKCS8 to DER encoding. + ScopedBio bio(BIO_new(BIO_s_mem())); + if (!bio) { + LOGE("Failed to allocate IO buffer for RSA key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio.get(), priv_info.get())) { + LOGE("Failed to serialize RSA key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 4: Determine key size and copy. + char* key_ptr = nullptr; + const long key_size = BIO_get_mem_data(bio.get(), &key_ptr); + if (key_size < 0) { + LOGE("Failed to get RSA key size"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (key_ptr == nullptr) { + LOGE("Encoded key is unexpectedly null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + const size_t required_size = + static_cast(key_size) + (explicit_schemes_ ? 8 : 0); + if (*buffer_size < required_size) { + *buffer_size = required_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *buffer_size = required_size; + if (explicit_schemes_) { + memcpy(buffer, "SIGN", 4); + const uint32_t allowed_schemes = htonl(allowed_schemes_); + memcpy(&buffer[4], &allowed_schemes, 4); + memcpy(&buffer[8], key_ptr, required_size - 8); + } else { + memcpy(buffer, key_ptr, required_size); + } + return OEMCrypto_SUCCESS; +} + +std::vector RsaPrivateKey::Serialize() const { + size_t key_size = kPrivateKeySize; + std::vector key_data(key_size, 0); + OEMCryptoResult res = Serialize(key_data.data(), &key_size); + if (res == OEMCrypto_ERROR_SHORT_BUFFER) { + LOGD( + "Actual RSA private key size is larger than expected: " + "expected = %zu, actual = %zu", + kPrivateKeySize, key_size); + key_data.resize(key_size); + res = Serialize(key_data.data(), &key_size); + } + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to serialize private key: result = %d", static_cast(res)); + key_data.clear(); + } else { + key_data.resize(key_size); + } + return key_data; +} + +OEMCryptoResult RsaPrivateKey::GenerateSignature( + const uint8_t* message, size_t message_length, + RsaSignatureAlgorithm algorithm, uint8_t* signature, + size_t* signature_length) const { + if (signature_length == nullptr) { + LOGE("Output signature size is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (signature == nullptr && *signature_length > 0) { + LOGE("Output signature is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (message == nullptr && message_length > 0) { + LOGE("Invalid message data"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + switch (algorithm) { + case kRsaPssDefault: + return GenerateSignaturePss(message, message_length, signature, + signature_length); + case kRsaPkcs1Cast: + return GenerateSignaturePkcs1Cast(message, message_length, signature, + signature_length); + } + LOGE("Unknown RSA signature algorithm: %d", static_cast(algorithm)); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; +} + +std::vector RsaPrivateKey::GenerateSignature( + const std::string& message, RsaSignatureAlgorithm algorithm) const { + size_t signature_size = SignatureSize(); + std::vector signature(signature_size); + const OEMCryptoResult res = GenerateSignature( + reinterpret_cast(message.data()), message.size(), + algorithm, signature.data(), &signature_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to generate signature: result = %d", static_cast(res)); + signature.clear(); + } else { + signature.resize(signature_size); + } + return signature; +} + +std::vector RsaPrivateKey::GenerateSignature( + const std::vector& message, + RsaSignatureAlgorithm algorithm) const { + size_t signature_size = SignatureSize(); + std::vector signature(signature_size, 0); + const OEMCryptoResult res = + GenerateSignature(message.data(), message.size(), algorithm, + signature.data(), &signature_size); + if (res != OEMCrypto_SUCCESS) { + LOGE("Failed to generate signature: result = %d", static_cast(res)); + signature.clear(); + } else { + signature.resize(signature_size); + } + return signature; +} + +size_t RsaPrivateKey::SignatureSize() const { return RSA_size(key_); } + +OEMCryptoResult RsaPrivateKey::DecryptSessionKey( + const uint8_t* enc_session_key, size_t enc_session_key_size, + uint8_t* session_key, size_t* session_key_size) const { + if (enc_session_key == nullptr || enc_session_key_size == 0) { + LOGE("Encrypted session key is %s", enc_session_key ? "empty" : "null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (session_key_size == nullptr) { + LOGE("Output session key size buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (session_key == nullptr && *session_key_size > 0) { + LOGE("Output session key buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (*session_key_size < kRsaSessionKeySize) { + *session_key_size = kRsaSessionKeySize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + const OEMCryptoResult result = DecryptOaep( + enc_session_key, enc_session_key_size, session_key, kRsaSessionKeySize); + if (result == OEMCrypto_SUCCESS) { + *session_key_size = kRsaSessionKeySize; + } else { + LOGE("Failed to decrypt session key"); + } + return result; +} + +std::vector RsaPrivateKey::DecryptSessionKey( + const std::vector& enc_session_key) const { + size_t session_key_size = kRsaSessionKeySize; + std::vector session_key(session_key_size, 0); + const OEMCryptoResult res = + DecryptSessionKey(enc_session_key.data(), enc_session_key.size(), + session_key.data(), &session_key_size); + if (res != OEMCrypto_SUCCESS) { + session_key.clear(); + } else { + session_key.resize(session_key_size); + } + return session_key; +} + +std::vector RsaPrivateKey::DecryptSessionKey( + const std::string& enc_session_key) const { + size_t session_key_size = kRsaSessionKeySize; + std::vector session_key(session_key_size, 0); + const OEMCryptoResult res = DecryptSessionKey( + reinterpret_cast(enc_session_key.data()), + enc_session_key.size(), session_key.data(), &session_key_size); + if (res != OEMCrypto_SUCCESS) { + session_key.clear(); + } else { + session_key.resize(session_key_size); + } + return session_key; +} + +size_t RsaPrivateKey::SessionKeyLength() const { return kRsaSessionKeySize; } + +OEMCryptoResult RsaPrivateKey::DecryptEncryptionKey( + const uint8_t* enc_encryption_key, size_t enc_encryption_key_size, + uint8_t* encryption_key, size_t* encryption_key_size) const { + if (enc_encryption_key == nullptr || enc_encryption_key_size == 0) { + LOGE("Encrypted encryption key is %s", + enc_encryption_key ? "empty" : "null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (encryption_key_size == nullptr) { + LOGE("Output encryption key size buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (encryption_key == nullptr && *encryption_key_size > 0) { + LOGE("Output encryption key buffer is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (*encryption_key_size < kEncryptionKeySize) { + *encryption_key_size = kEncryptionKeySize; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + const OEMCryptoResult result = + DecryptOaep(enc_encryption_key, enc_encryption_key_size, encryption_key, + kEncryptionKeySize); + if (result == OEMCrypto_SUCCESS) { + *encryption_key_size = kEncryptionKeySize; + } else { + LOGE("Failed to decrypt encryption key"); + } + return result; +} + +std::vector RsaPrivateKey::DecryptEncryptionKey( + const std::vector& enc_encryption_key) const { + size_t encryption_key_size = kEncryptionKeySize; + std::vector encryption_key(encryption_key_size, 0); + const OEMCryptoResult res = + DecryptEncryptionKey(enc_encryption_key.data(), enc_encryption_key.size(), + encryption_key.data(), &encryption_key_size); + if (res != OEMCrypto_SUCCESS) { + encryption_key.clear(); + } else { + encryption_key.resize(encryption_key_size); + } + return encryption_key; +} + +std::vector RsaPrivateKey::DecryptEncryptionKey( + const std::string& enc_encryption_key) const { + size_t encryption_key_size = kEncryptionKeySize; + std::vector encryption_key(encryption_key_size, 0); + const OEMCryptoResult res = DecryptEncryptionKey( + reinterpret_cast(enc_encryption_key.data()), + enc_encryption_key.size(), encryption_key.data(), &encryption_key_size); + if (res != OEMCrypto_SUCCESS) { + encryption_key.clear(); + } else { + encryption_key.resize(encryption_key_size); + } + return encryption_key; +} + +RsaPrivateKey::~RsaPrivateKey() { + if (key_ != nullptr) { + RSA_free(key_); + key_ = nullptr; + } + allowed_schemes_ = 0; + explicit_schemes_ = false; + field_size_ = kRsaFieldUnknown; +} + +bool RsaPrivateKey::InitFromBuffer(const uint8_t* buffer, size_t length) { + if (length < 8) { + LOGE("Public key is too small: length = %zu", length); + return false; + } + ScopedBio bio; + // Check allowed scheme type. + if (!memcmp("SIGN", buffer, 4)) { + uint32_t allowed_schemes; + memcpy(&allowed_schemes, reinterpret_cast(&buffer[4]), 4); + allowed_schemes_ = ntohl(allowed_schemes); + bio.reset(BIO_new_mem_buf(&buffer[8], static_cast(length - 8))); + explicit_schemes_ = true; + } else { + allowed_schemes_ = kSign_RSASSA_PSS; + bio.reset(BIO_new_mem_buf(buffer, static_cast(length))); + } + if (!bio) { + LOGE("Failed to allocate BIO buffer"); + return false; + } + // Step 1: Deserializes PKCS8 PrivateKeyInfo containing an RSA key. + ScopedPrivateKeyInfo priv_info( + d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); + if (!priv_info) { + LOGE("Failed to parse private key"); + return false; + } + // Step 2: Convert to RSA key. + ScopedEvpPkey pkey(EVP_PKCS82PKEY(priv_info.get())); + if (!pkey) { + LOGE("Failed to convert PKCS8 to EVP"); + return false; + } + ScopedRsaKey key(EVP_PKEY_get1_RSA(pkey.get())); + if (!key) { + LOGE("Failed to get RSA key"); + return false; + } + // Step 3: Verify key parameters and field width. + const int check = RSA_check_key(key.get()); + if (check == 0) { + LOGE("RSA key parameters are invalid"); + return false; + } else if (check == -1) { + LOGE("Failed to check RSA key"); + return false; + } + const int bits = RSA_bits(key.get()); + field_size_ = RealBitSizeToFieldSize(bits); + if (field_size_ == kRsaFieldUnknown) { + LOGE("Unsupported RSA key size: bits = %d", bits); + return false; + } + key_ = key.release(); + return true; +} + +bool RsaPrivateKey::InitFromFieldSize(RsaFieldSize field_size) { + if (field_size != kRsa2048Bit && field_size != kRsa3072Bit) { + LOGE("Unsupported RSA field size: bits = %d", static_cast(field_size)); + return false; + } + // Step 1: Create exponent. + ScopedBigNum exp(BN_new()); + if (!exp) { + LOGE("Failed to allocate RSA exponent"); + return false; + } + if (!BN_set_word(exp.get(), RSA_F4)) { + LOGE("Failed to set RSA exponent"); + return false; + } + // Step 2: Generate RSA key. + ScopedRsaKey key(RSA_new()); + if (!key) { + LOGE("Failed to allocate RSA key"); + return false; + } + if (!RSA_generate_key_ex(key.get(), static_cast(field_size), exp.get(), + nullptr)) { + LOGE("Failed to generate RSA key"); + return false; + } + key_ = key.release(); + allowed_schemes_ = kSign_RSASSA_PSS; + field_size_ = field_size; + return true; +} + +OEMCryptoResult RsaPrivateKey::GenerateSignaturePss( + const uint8_t* message, size_t message_length, uint8_t* signature, + size_t* signature_length) const { + // Step 0: Ensure the signature algorithm is supported by key. + if (!(allowed_schemes_ & kSign_RSASSA_PSS)) { + LOGE("RSA key cannot sign using PSS"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + // Step 1: Create a high-level key from RSA key. + ScopedEvpPkey pkey(EVP_PKEY_new()); + if (!pkey) { + LOGE("Failed to allocate PKEY"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (!EVP_PKEY_set1_RSA(pkey.get(), key_)) { + LOGE("Failed to set PKEY RSA key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2a: Setup a EVP MD CTX for PSS Signature Generation. + ScopedEvpMdCtx md_ctx(EVP_MD_CTX_new()); + if (!md_ctx) { + LOGE("Failed to allocate MD CTX"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + EVP_PKEY_CTX* pkey_ctx = nullptr; // Ownership is maintained by |md_ctx| + int res = EVP_DigestSignInit(md_ctx.get(), &pkey_ctx, EVP_sha1(), nullptr, + pkey.get()); + if (res != 1) { + LOGE("Failed to initialize MD CTX for signing"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (pkey_ctx == nullptr) { + LOGE("PKEY CTX is unexpectedly null"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2b: Configure OEMCrypto RSASSA-PSS options. + res = EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING); + if (res != 1) { + LOGE("Failed to set PSS padding"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + res = EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_ctx, kPssSaltLength); + if (res != 1) { + LOGE("Failed to set PSS salt length"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + res = EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha1()); + if (res != 1) { + LOGE("Failed to set PSS MGF1 MD"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 3: Digest message. + if (message_length > 0) { + res = EVP_DigestSignUpdate(md_ctx.get(), message, message_length); + if (res != 1) { + LOGE("Failed to update MD"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + // Step 4a: Determine size of signature. + size_t actual_signature_length = 0; + res = EVP_DigestSignFinal(md_ctx.get(), nullptr, &actual_signature_length); + if (res != 1) { + LOGE("Failed to determine signature length"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (*signature_length < actual_signature_length) { + *signature_length = actual_signature_length; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + // Step 4b: Generate signature. + res = EVP_DigestSignFinal(md_ctx.get(), signature, signature_length); + if (res != 1) { + LOGE("Failed to perform RSASSA-PSS-SIGN"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult RsaPrivateKey::GenerateSignaturePkcs1Cast( + const uint8_t* message, size_t message_length, uint8_t* signature, + size_t* signature_length) const { + // Step 0: Ensure the signature algorithm is supported by key. + if (!(allowed_schemes_ & kSign_PKCS1_Block1)) { + LOGE("RSA key cannot sign PKCS1"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + if (message_length > kRsaPkcs1CastMaxMessageSize) { + LOGE("Message is too large for CAST PKCS1 signature: size = %zu", + message_length); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + // Step 1: Ensure signature buffer is large enough. + const size_t expected_signature_size = static_cast(RSA_size(key_)); + if (*signature_length < expected_signature_size) { + *signature_length = expected_signature_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + // Step 2: Encrypt with PKCS1 padding. + const int enc_res = + RSA_private_encrypt(static_cast(message_length), message, signature, + key_, RSA_PKCS1_PADDING); + if (enc_res < 0) { + LOGE("Failed to perform private encryption"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + *signature_length = expected_signature_size; + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult RsaPrivateKey::DecryptOaep( + const uint8_t* enc_message, size_t enc_message_size, uint8_t* message, + size_t expected_message_length) const { + // Step 1: Decrypt using RSAES-OAEP. + std::vector decrypt_buffer(RSA_size(key_)); + const int dec_res = + RSA_private_decrypt(static_cast(enc_message_size), enc_message, + decrypt_buffer.data(), key_, RSA_PKCS1_OAEP_PADDING); + if (dec_res < 0) { + LOGE("Failed to perform RSAES-OAEP decrypt"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (static_cast(dec_res) != expected_message_length) { + LOGE("Unexpected key size: expected = %zu, actual = %d", + expected_message_length, dec_res); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + // Step 2: Copy decrypted data key. + memcpy(message, decrypt_buffer.data(), expected_message_length); + return OEMCrypto_SUCCESS; +} + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_rsa_key.h b/oemcrypto/ref/src/oemcrypto_rsa_key.h new file mode 100644 index 0000000..c0aa343 --- /dev/null +++ b/oemcrypto/ref/src/oemcrypto_rsa_key.h @@ -0,0 +1,359 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef OEMCRYPTO_RSA_KEY_H_ +#define OEMCRYPTO_RSA_KEY_H_ + +#include +#include + +#include +#include +#include + +#include + +#include "OEMCryptoCENCCommon.h" + +namespace wvoec_ref { + +enum RsaFieldSize { + kRsaFieldUnknown = 0, + kRsa2048Bit = 2048, + kRsa3072Bit = 3084 +}; + +// Identifies the RSA signature algorithm to be used when signing +// messages or verifying message signatures. +// The two standard signing algorithms specified by PKCS1 RSA V2.1 +// are RSASSA-PKCS1 and RSASSA-PSS. Each require agreement on a +// set of options. For OEMCrypto, only one set of options are agreed +// upon for each RSA signature scheme. CAST receivers specify a +// special implementation of PKCS1 where the message is already +// digested and encoded when provided. +enum RsaSignatureAlgorithm { + // RSASSA-PSS with default options: + // Hash algorithm: SHA-1 + // MGF: MGF1 with SHA-1 + // Salt length: 20 bytes + // Trailer field: 0xbc + kRsaPssDefault = 0, + // RSASSA-PKCS1 for CAST receivers. + // Assumes message is already digested & encoded. Max message length + // is 83 bytes. + kRsaPkcs1Cast = 1 +}; + +// Returns the string representation of the provided RSA field size. +// Intended for logging purposes. +std::string RsaFieldSizeToString(RsaFieldSize field_size); + +// Compares two OpenSSL/BoringSSL RSA keys to see if their public RSA +// components are matching. +// This function assumes both keys are valid. +// Returns true if they are matching, false otherwise. +bool RsaKeysAreMatchingPair(const RSA* public_key, const RSA* private_key); + +class RsaPrivateKey; + +class RsaPublicKey { + public: + // Creates a new public key equivalent of the provided private key. + static std::unique_ptr New(const RsaPrivateKey& private_key); + + // Loads a serialized RSA public key. + // The provided |buffer| must contain a valid ASN.1 DER encoded + // SubjectPublicKey. This API will reject any RSA key that is not + // approximately to 2048bits or 3072bits. + // + // buffer: SubjectPublicKeyInfo = { + // algorithm: AlgorithmIdentifier = { + // algorithm: OID = rsaEncryption, + // parameters: NULL = null + // }, + // subjectPublicKey: BIT STRING = ... -- ASN.1 DER encoded RSAPublicKey + // } + // + // Failure will occur if the provided |buffer| does not contain a + // valid SubjectPublicKey, or if the specified curve is not + // supported. + static std::unique_ptr Load(const uint8_t* buffer, + size_t length); + static std::unique_ptr Load(const std::string& buffer); + static std::unique_ptr Load(const std::vector& buffer); + + RsaFieldSize field_size() const { return field_size_; } + uint32_t allowed_schemes() const { return allowed_schemes_; } + const RSA* GetRsaKey() const { return key_; } + + // Checks if the provided |private_key| is the RSA private key of this + // public key. + bool IsMatchingPrivateKey(const RsaPrivateKey& private_key) const; + + // Serializes the public key into an ASN.1 DER encoded SubjectPublicKey + // representation. + // On success, |buffer_size| is populated with the number of bytes + // written to |buffer|, and OEMCrypto_SUCCESS is returned. + // If the provided |buffer_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is set + // to the required buffer size. + OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const; + // Same as above, except directly returns the serialized key. + // Returns an empty vector on error. + std::vector Serialize() const; + + // Verifies the |signature| matches the provided |message| by the + // private equivalent of this public key. + // The signature algorithm can be specified via the |algorithm| field. + // See RsaSignatureAlgorithm for details on each algorithm. + // + // Returns: + // OEMCrypto_SUCCESS if signature is valid + // OEMCrypto_ERROR_SIGNATURE_FAILURE if the signature is invalid + // OEMCrypto_ERROR_UNKNOWN_FAILURE if any error occurs + OEMCryptoResult VerifySignature( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length, + RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + OEMCryptoResult VerifySignature( + const std::string& message, const std::string& signature, + RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + OEMCryptoResult VerifySignature( + const std::vector& message, + const std::vector& signature, + RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + + // Encrypts the OEMCrypto session key used for deriving other keys. + // On success, |enc_session_key_size| is populated with the number + // of bytes written to |enc_session_key|, and OEMCrypto_SUCCESS is + // returned. If the provided |enc_session_key_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and + // |enc_session_key_size| is set to the required buffer size. + OEMCryptoResult EncryptSessionKey(const uint8_t* session_key, + size_t session_key_size, + uint8_t* enc_session_key, + size_t* enc_session_key_size) const; + // Same as above, except directly returns the encrypted key. + std::vector EncryptSessionKey( + const std::vector& session_key) const; + std::vector EncryptSessionKey(const std::string& session_key) const; + + // Encrypts the OEMCrypto encryption key used for encrypting the + // DRM private key. + // On success, |enc_encryption_key_size| is populated with the + // number of bytes written to |enc_encryption_key|, and + // OEMCrypto_SUCCESS is returned. + // If the provided |enc_encryption_key_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and + // |enc_encryption_key_size| is set to the required buffer size. + OEMCryptoResult EncryptEncryptionKey(const uint8_t* encryption_key, + size_t encryption_key_size, + uint8_t* enc_encryption_key, + size_t* enc_encryption_key_size) const; + // Same as above, except directly returns the encrypted key. + std::vector EncryptEncryptionKey( + const std::vector& encryption_key) const; + std::vector EncryptEncryptionKey( + const std::string& encryption_key) const; + + ~RsaPublicKey(); + + RsaPublicKey(const RsaPublicKey&) = delete; + RsaPublicKey(RsaPublicKey&&) = delete; + const RsaPublicKey& operator=(const RsaPublicKey&) = delete; + RsaPublicKey& operator=(RsaPublicKey&&) = delete; + + private: + RsaPublicKey() {} + + // Initializes the public key object using the provided |buffer|. + // In case of any failure, false is return and the key should be + // discarded. + bool InitFromBuffer(const uint8_t* buffer, size_t length); + // Initializes the public key object from a private. + bool InitFromPrivateKey(const RsaPrivateKey& private_key); + + // Signature specialization functions. + OEMCryptoResult VerifySignaturePss(const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length) const; + OEMCryptoResult VerifySignaturePkcs1Cast(const uint8_t* message, + size_t message_length, + const uint8_t* signature, + size_t signature_length) const; + + // RSAES-OAEP encrypt. + OEMCryptoResult EncryptOaep(const uint8_t* message, size_t message_size, + uint8_t* enc_message, + size_t* enc_message_length) const; + + // OpenSSL/BoringSSL implementation of an RSA key. + // Will only include components of an RSA public key. + RSA* key_ = nullptr; + uint32_t allowed_schemes_ = 0; + RsaFieldSize field_size_ = kRsaFieldUnknown; +}; + +class RsaPrivateKey { + public: + // Creates a new, pseudorandom RSA private key. + static std::unique_ptr New(RsaFieldSize field_size); + + // Loads a serialized RSA private key. + // The provided |buffer| must contain a valid ASN.1 DER encoded + // PrivateKeyInfo (RFC 5208). + // + // buffer: PrivateKeyInfo = { + // version: INTEGER = v1(0), + // privateKeyAlgorithm: OID = rsaEncryption, + // privateKey: OCTET STRING = ..., + // -- BER encoding of RSAPrivateKey (RFC 3447) + // attributes: Attributes = ... -- Optional, not used by OEMCrypto + // } + // Note: If the public key is not included, then it is computed from + // the private. + // + // Failure will occur if the provided |buffer| does not contain a + // valid RSAPrivateKey, or if the specified curve is not supported. + static std::unique_ptr Load(const uint8_t* buffer, + size_t length); + static std::unique_ptr Load(const std::string& buffer); + static std::unique_ptr Load( + const std::vector& buffer); + + // Creates a new RSA public key of this private key. + // Equivalent to calling RsaPublicKey::New with this private + // key. + std::unique_ptr MakePublicKey() const; + + RsaFieldSize field_size() const { return field_size_; } + uint32_t allowed_schemes() const { return allowed_schemes_; } + const RSA* GetRsaKey() const { return key_; } + + // Checks if the provided |public_key| is the RSA public key of this + // private key. + bool IsMatchingPublicKey(const RsaPublicKey& public_key) const; + + // Serializes the private key into an ASN.1 DER encoded X + // representation. + // On success, |buffer_size| is populated with the number of bytes + // written to |buffer|, and OEMCrypto_SUCCESS is returned. + // If the provided |buffer_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |buffer_size| is + // set to the required buffer size. + OEMCryptoResult Serialize(uint8_t* buffer, size_t* buffer_size) const; + // Same as above, except directly returns the serialized key. + // Returns an empty vector on error. + std::vector Serialize() const; + + // Signs the provided |message| using the RSA signing algorithm + // specified by |algorithm|. See RsaSignatureAlgorithm for + // details on each algorithm. + // + // On success, |signature_length| is populated with the number of + // bytes written to |signature|, and OEMCrypto_SUCCESS is returned. + // If the provided |signature_length| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |signature_length| + // is set to the required signature size. + OEMCryptoResult GenerateSignature(const uint8_t* message, + size_t message_length, + RsaSignatureAlgorithm algorithm, + uint8_t* signature, + size_t* signature_length) const; + // Same as above, except directly returns the serialized signature. + // Returns an empty vector on error. + std::vector GenerateSignature( + const std::vector& message, + RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + std::vector GenerateSignature( + const std::string& message, + RsaSignatureAlgorithm algorithm = kRsaPssDefault) const; + // Returns an upper bound for the signature size. May be larger than + // the actual signature generated by GenerateSignature(). + size_t SignatureSize() const; + + // Decrypts the OEMCrypto session key used for deriving other keys. + // On success, |session_key_size| is populated with the number of + // bytes written to |session_key|, and OEMCrypto_SUCCESS is returned. + // If the provided |session_key_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |session_key_size| + // is set to the required buffer size. + OEMCryptoResult DecryptSessionKey(const uint8_t* enc_session_key, + size_t enc_session_key_size, + uint8_t* session_key, + size_t* session_key_size) const; + // Same as above, except directly returns the decrypted key. + std::vector DecryptSessionKey( + const std::vector& enc_session_key) const; + std::vector DecryptSessionKey( + const std::string& enc_session_key) const; + // Returns the byte length of the symmetric key that would be derived + // by DecryptSessionKey(). + size_t SessionKeyLength() const; + + // Decrypts the OEMCrypto encryption key used for decrypting DRM + // private key. + // On success, |encryption_key_size| is populated with the number of + // bytes written to |encryption_key|, and OEMCrypto_SUCCESS is + // returned. + // If the provided |encryption_key_size| is too small, + // OEMCrypto_ERROR_SHORT_BUFFER is returned and |encryption_key_size| + // is set to the required buffer size. + OEMCryptoResult DecryptEncryptionKey(const uint8_t* enc_encryption_key, + size_t enc_encryption_key_size, + uint8_t* encryption_key, + size_t* encryption_key_size) const; + // Same as above, except directly returns the decrypted key. + std::vector DecryptEncryptionKey( + const std::vector& enc_encryption_key) const; + std::vector DecryptEncryptionKey( + const std::string& enc_encryption_key) const; + + ~RsaPrivateKey(); + + RsaPrivateKey(const RsaPrivateKey&) = delete; + RsaPrivateKey(RsaPrivateKey&&) = delete; + const RsaPrivateKey& operator=(const RsaPrivateKey&) = delete; + RsaPrivateKey& operator=(RsaPrivateKey&&) = delete; + + private: + RsaPrivateKey() {} + + // Initializes the public key object using the provided |buffer|. + // In case of any failure, false is return and the key should be + // discarded. + bool InitFromBuffer(const uint8_t* buffer, size_t length); + // Generates a new key based on the provided field size. + bool InitFromFieldSize(RsaFieldSize field_size); + + // Signature specialization functions. + OEMCryptoResult GenerateSignaturePss(const uint8_t* message, + size_t message_length, + uint8_t* signature, + size_t* signature_length) const; + OEMCryptoResult GenerateSignaturePkcs1Cast(const uint8_t* message, + size_t message_length, + uint8_t* signature, + size_t* signature_length) const; + + // RSAES-OAEP decrypt. + OEMCryptoResult DecryptOaep(const uint8_t* enc_message, + size_t enc_message_size, uint8_t* message, + size_t expected_message_length) const; + + // OpenSSL/BoringSSL implementation of an RSA key. + // Will include all components of an RSA private key. + RSA* key_ = nullptr; + uint32_t allowed_schemes_ = 0; + // Set true if the deserialized key contained an allowed schemes. + bool explicit_schemes_ = false; + RsaFieldSize field_size_ = kRsaFieldUnknown; +}; + +} // namespace wvoec_ref + +#endif // OEMCRYPTO_RSA_KEY_H_ diff --git a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.cpp b/oemcrypto/ref/src/oemcrypto_rsa_key_shared.cpp deleted file mode 100644 index 83cd52f..0000000 --- a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.cpp +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#include "oemcrypto_rsa_key_shared.h" - -#include - -#include -#include -#include -#include -#include - -#include "log.h" - -namespace wvoec_ref { - -void dump_boringssl_error() { - int count = 0; - while (unsigned long err = ERR_get_error()) { - count++; - char buffer[120]; - ERR_error_string_n(err, buffer, sizeof(buffer)); - LOGE("BoringSSL Error %d -- %lu -- %s", count, err, buffer); - } - LOGE("Reported %d BoringSSL Errors", count); -} - -void RSA_shared_ptr::reset() { - if (rsa_key_ && key_owned_) { - RSA_free(rsa_key_); - } - key_owned_ = false; - rsa_key_ = nullptr; -} - -bool RSA_shared_ptr::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) { - assert(buffer != nullptr); - reset(); - uint8_t* pkcs8_rsa_key = const_cast(buffer); - BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length); - if (bio == nullptr) { - LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]"); - return false; - } - bool success = true; - PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr); - if (pkcs8_pki == nullptr) { - BIO_reset(bio); - pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, nullptr); - if (pkcs8_pki == nullptr) { - LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned nullptr]"); - dump_boringssl_error(); - success = false; - } - } - EVP_PKEY* evp = nullptr; - if (success) { - evp = EVP_PKCS82PKEY(pkcs8_pki); - if (evp == nullptr) { - LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned nullptr]"); - dump_boringssl_error(); - success = false; - } - } - if (success) { - rsa_key_ = EVP_PKEY_get1_RSA(evp); - if (rsa_key_ == nullptr) { - LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]"); - success = false; - } - key_owned_ = true; - } - if (evp != nullptr) { - EVP_PKEY_free(evp); - } - if (pkcs8_pki != nullptr) { - PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); - } - BIO_free(bio); - if (!success) { - return false; - } - switch (RSA_check_key(rsa_key_)) { - case 1: // valid. - return true; - case 0: // not valid. - LOGE("[LoadPkcs8RsaKey(): rsa key not valid]"); - dump_boringssl_error(); - return false; - default: // -1 == check failed. - LOGE("[LoadPkcs8RsaKey(): error checking rsa key]"); - dump_boringssl_error(); - return false; - } -} - -} // namespace wvoec_ref diff --git a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.h b/oemcrypto/ref/src/oemcrypto_rsa_key_shared.h deleted file mode 100644 index 5f832cd..0000000 --- a/oemcrypto/ref/src/oemcrypto_rsa_key_shared.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine -// License Agreement. -// -// Reference implementation of OEMCrypto APIs -// -#ifndef OEMCRYPTO_RSA_KEY_SHARED_H_ -#define OEMCRYPTO_RSA_KEY_SHARED_H_ - -#include - -#include - -namespace wvoec_ref { - -// Shared pointer with specialized destructor. This pointer is only shared -// from a CryptoEngine to a Session -- so we don't have to use full reference -// counting. -class RSA_shared_ptr { - public: - RSA_shared_ptr() : rsa_key_(nullptr), key_owned_(false) {} - ~RSA_shared_ptr() { reset(); }; - // Explicitly allow copy as share. - explicit RSA_shared_ptr(const RSA_shared_ptr& other) : - rsa_key_(other.rsa_key_), key_owned_(false) {} - RSA* get() { return rsa_key_; } - void reset(); - bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length); - - private: - void operator=(const RSA_shared_ptr); // disallow assign. - - RSA* rsa_key_; - bool key_owned_; -}; - -// Log errors from BoringSSL. -void dump_boringssl_error(); - -} // namespace wvoec_ref - -#endif // OEMCRYPTO_RSA_KEY_SHARED_H_ diff --git a/oemcrypto/ref/src/oemcrypto_session.cpp b/oemcrypto/ref/src/oemcrypto_session.cpp index 9a1ab8e..cce1714 100644 --- a/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/oemcrypto/ref/src/oemcrypto_session.cpp @@ -7,38 +7,34 @@ #include "oemcrypto_session.h" #include + #include #include #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include "advance_iv_ctr.h" -#include "disallow_copy_and_assign.h" #include "keys.h" #include "log.h" #include "odk.h" #include "oemcrypto_engine_ref.h" +#include "oemcrypto_key_deriver.h" #include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" #include "oemcrypto_types.h" #include "platform.h" #include "string_conversions.h" #include "wvcrc32.h" -static const int kPssSaltLength = 20; - +namespace wvoec_ref { namespace { // Increment counter for AES-CTR. The CENC spec specifies we increment only @@ -67,10 +63,23 @@ void advance_dest_buffer(OEMCrypto_DestBufferDesc* dest_buffer, size_t bytes) { } } +// Checks that the provided |key| contains the allowed RSA schemes. +// This validation only checks the known schemes, and does not validate +// against undocumented schemes. +bool ValidateRsaKeySchemes(const RsaPrivateKey* key) { + if (key == nullptr) return false; + constexpr uint32_t kAllSchemes = kSign_RSASSA_PSS | kSign_PKCS1_Block1; + // Must specify exactly one scheme, not multiple. + if (key->allowed_schemes() == 0 || + (key->allowed_schemes() & kAllSchemes) == kAllSchemes) { + LOGD("RSA DRM key has invalid set of schemes: allowed_schemes = 0x%08x", + key->allowed_schemes()); + return false; + } + return true; +} } // namespace -namespace wvoec_ref { - /***************************************/ class ContentKeysContext : public SessionContextKeys { @@ -181,163 +190,290 @@ EntitlementKey* EntitlementKeysContext::GetEntitlementKey( /***************************************/ -SessionContext::SessionContext(CryptoEngine* ce, SessionId sid, - const RSA_shared_ptr& rsa_key) - : valid_(true), - ce_(ce), - id_(sid), - current_content_key_(nullptr), - session_keys_(nullptr), - license_request_hash_(), - rsa_key_(rsa_key), - allowed_schemes_(kSign_RSASSA_PSS), - decrypt_started_(false), - timer_limits_(), - clock_values_(), - usage_entry_(nullptr), - srm_requirements_status_(NoSRMVersion), - usage_entry_status_(kNoUsageEntry), - compute_hash_(false), - current_hash_(0), - bad_frame_number_(0), - hash_error_(OEMCrypto_SUCCESS), - state_nonce_created_(false), - state_request_signed_(false), - state_response_loaded_(false) { +SessionContext::SessionContext(CryptoEngine* ce, SessionId sid) + : valid_(ce != nullptr), ce_(ce), id_(sid) { ODK_InitializeSessionValues(&timer_limits_, &clock_values_, &nonce_values_, CryptoEngine::kApiVersion, sid); + memset(license_request_hash_, 0, sizeof(license_request_hash_)); +} + +SessionContext::SessionContext(CryptoEngine* ce, SessionId sid, + std::shared_ptr&& rsa_key) + : SessionContext(ce, sid) { + drm_key_ = DrmPrivateKey::Create(std::move(rsa_key)); } SessionContext::~SessionContext() {} -// Internal utility function to derive key using CMAC-128 -bool SessionContext::DeriveKey(const std::vector& key, - const std::vector& context, int counter, - std::vector* out) { - if (key.empty() || counter > 4 || context.empty() || out == nullptr) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_INVALID_CONTEXT]"); - return false; - } - - const EVP_CIPHER* cipher = EVP_aes_128_cbc(); - CMAC_CTX* cmac_ctx = CMAC_CTX_new(); - - if (!cmac_ctx) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - return false; - } - - if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, 0)) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - CMAC_CTX_free(cmac_ctx); - return false; - } - - std::vector message; - message.push_back(counter); - message.insert(message.end(), context.begin(), context.end()); - - if (!CMAC_Update(cmac_ctx, &message[0], message.size())) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - CMAC_CTX_free(cmac_ctx); - return false; - } - - size_t reslen; - uint8_t res[128]; - if (!CMAC_Final(cmac_ctx, res, &reslen)) { - LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]"); - CMAC_CTX_free(cmac_ctx); - return false; - } - - out->assign(res, res + reslen); - - CMAC_CTX_free(cmac_ctx); - - return true; -} - -bool SessionContext::DeriveKeys(const std::vector& master_key, - const std::vector& mac_key_context, - const std::vector& enc_key_context) { - // Generate derived key for mac key - std::vector mac_key_server; - std::vector mac_key_client; - std::vector mac_key_part2; - if (!DeriveKey(master_key, mac_key_context, 1, &mac_key_server)) { - return false; - } - if (!DeriveKey(master_key, mac_key_context, 2, &mac_key_part2)) { - return false; - } - mac_key_server.insert(mac_key_server.end(), mac_key_part2.begin(), - mac_key_part2.end()); - - if (!DeriveKey(master_key, mac_key_context, 3, &mac_key_client)) { - return false; - } - if (!DeriveKey(master_key, mac_key_context, 4, &mac_key_part2)) { - return false; - } - mac_key_client.insert(mac_key_client.end(), mac_key_part2.begin(), - mac_key_part2.end()); - - // Generate derived key for encryption key - std::vector enc_key; - if (!DeriveKey(master_key, enc_key_context, 1, &enc_key)) { - return false; - } - - set_mac_key_server(mac_key_server); - set_mac_key_client(mac_key_client); - set_encryption_key(enc_key); - return true; -} - -bool SessionContext::RSADeriveKeys( - const std::vector& enc_session_key, +OEMCryptoResult SessionContext::DeriveKeys( + const std::vector& master_key, const std::vector& mac_key_context, const std::vector& enc_key_context) { - if (!rsa_key()) { - LOGE("[RSADeriveKeys(): no RSA key set]"); - return false; + // Generate derived key for mac key + std::unique_ptr key_deriver = KeyDeriver::Create(master_key); + if (!key_deriver) { + LOGE("Failed to initialization key deriver: master_key_size = %zu", + master_key.size()); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - const size_t actual_key_size = static_cast(RSA_size(rsa_key())); - if (enc_session_key.size() != actual_key_size) { - LOGE( - "[RSADeriveKeys(): encrypted session key wrong size: %zu, expected " - "%zu]", - enc_session_key.size(), actual_key_size); - dump_boringssl_error(); - return false; + + std::vector mac_key_server; + if (!key_deriver->DeriveServerMacKey(mac_key_context, &mac_key_server)) { + LOGE("Failed to derive server MAC key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - session_key_.resize(RSA_size(rsa_key())); - const int decrypted_size = - RSA_private_decrypt(enc_session_key.size(), &enc_session_key[0], - &session_key_[0], rsa_key(), RSA_PKCS1_OAEP_PADDING); - if (-1 == decrypted_size) { - LOGE("[RSADeriveKeys(): error decrypting session key.]"); - dump_boringssl_error(); - return false; + + std::vector mac_key_client; + if (!key_deriver->DeriveClientMacKey(mac_key_context, &mac_key_client)) { + LOGE("Failed to derive client MAC key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - session_key_.resize(decrypted_size); - if (decrypted_size != static_cast(wvoec::KEY_SIZE)) { - LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]", - decrypted_size); - dump_boringssl_error(); - session_key_.clear(); - return false; + + std::vector enc_key; + if (!key_deriver->DeriveEncryptionKey(enc_key_context, &enc_key)) { + LOGE("Failed to derive encryption key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } + + mac_key_server_ = std::move(mac_key_server); + mac_key_client_ = std::move(mac_key_client); + encryption_key_ = std::move(enc_key); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SessionContext::DeriveKeysWithSessionKey( + const std::vector& session_key_source, + const std::vector& mac_key_context, + const std::vector& enc_key_context) { + if (!drm_key_) { + LOGE("No DRM key set"); + return OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED; + } + const OEMCryptoResult res = drm_key_->GetSessionKey( + session_key_source.data(), session_key_source.size(), &session_key_); + if (res != OEMCrypto_SUCCESS) return res; return DeriveKeys(session_key_, mac_key_context, enc_key_context); } +OEMCryptoResult SessionContext::LoadOemPrivateKey() { + if (!ce_->HasOemPrivateKey()) { + LOGE("No OEM private key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + drm_key_ = DrmPrivateKey::Create(ce_->ShareOemPrivateKey()); + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SessionContext::LoadWrappedDrmKey( + const std::vector& master_key, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_drm_key, size_t wrapped_drm_key_length) { + std::vector drm_key; + const OEMCryptoResult unwrap_result = UnwrapDrmKey( + master_key, wrapped_drm_key, wrapped_drm_key_length, &drm_key); + if (unwrap_result != OEMCrypto_SUCCESS) { + return unwrap_result; + } + switch (key_type) { + case OEMCrypto_RSA_Private_Key: { + if (!LoadRsaDrmKey(drm_key)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + } break; + case OEMCrypto_ECC_Private_Key: { + if (!LoadEccDrmKey(drm_key)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + } break; + default: { + LOGE("Unknown key type: %x", static_cast(key_type)); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SessionContext::RewrapDeviceDrmKey( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length, uint32_t nonce, + OEMCrypto_PrivateKeyType drm_key_type, const uint8_t* enc_drm_key, + size_t enc_drm_key_length, const uint8_t* enc_drm_key_iv, + uint8_t* wrapped_drm_key, size_t* wrapped_drm_key_length) { + if (message == nullptr || message_length == 0 || signature == nullptr || + signature_length == 0 || enc_drm_key == nullptr || + enc_drm_key_length == 0 || enc_drm_key_iv == nullptr || + wrapped_drm_key_length == nullptr) { + LOGE("Input argument is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // Verify signature. + if (!ValidateMessage(message, message_length, signature, signature_length)) { + LOGE("Could not verify signature"); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + // Validate nonce. + if (!CheckNonce(nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + + const size_t expected_size = ExpectedWrappedDrmKeySize(enc_drm_key_length); + if (wrapped_drm_key == nullptr || expected_size < *wrapped_drm_key_length) { + *wrapped_drm_key_length = expected_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + // Do not set actual size here, handled by WrapDrmKey(). + + // Decrypt DRM key and verify it. + std::vector drm_key; + if (!DecryptDrmKey(enc_drm_key, enc_drm_key_length, enc_drm_key_iv, + &drm_key)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + switch (drm_key_type) { + case OEMCrypto_RSA_Private_Key: { + if (!TestRsaDrmKey(drm_key)) { + LOGE("Invalid RSA DRM key"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + } break; + case OEMCrypto_ECC_Private_Key: { + if (!TestEccDrmKey(drm_key)) { + LOGE("Invalid ECC DRM key"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + } break; + default: { + LOGE("Unknown key type: %x", static_cast(drm_key_type)); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + + return WrapDrmKey(ce_->DeviceRootKey(), std::move(drm_key), wrapped_drm_key, + wrapped_drm_key_length); +} + +OEMCryptoResult SessionContext::RewrapDeviceDrmKey30( + uint32_t nonce, const uint8_t* encrypted_message_key, + size_t encrypted_message_key_length, OEMCrypto_PrivateKeyType drm_key_type, + const uint8_t* enc_drm_key, size_t enc_drm_key_length, + const uint8_t* enc_drm_key_iv, uint8_t* wrapped_drm_key, + size_t* wrapped_drm_key_length) { + if (encrypted_message_key == nullptr || encrypted_message_key_length == 0 || + enc_drm_key == nullptr || enc_drm_key_length == 0 || + enc_drm_key_iv == nullptr || wrapped_drm_key_length == nullptr) { + LOGE("Input argument is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + // Validate nonce. + if (!CheckNonce(nonce)) { + return OEMCrypto_ERROR_INVALID_NONCE; + } + + const size_t expected_size = ExpectedWrappedDrmKeySize(enc_drm_key_length); + if (wrapped_drm_key == nullptr || expected_size < *wrapped_drm_key_length) { + *wrapped_drm_key_length = expected_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + // Do not set actual size here, handled by WrapDrmKey(). + + const std::vector enc_encryption_key( + encrypted_message_key, + encrypted_message_key + encrypted_message_key_length); + if (!InstallRsaEncryptedKey(enc_encryption_key)) { + LOGE("Error loading encrypted_message_key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + + // Decrypt DRM key. + std::vector drm_key; + if (!DecryptDrmKey(enc_drm_key, enc_drm_key_length, enc_drm_key_iv, + &drm_key)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + switch (drm_key_type) { + case OEMCrypto_RSA_Private_Key: { + if (!TestRsaDrmKey(drm_key)) { + LOGE("Invalid RSA DRM key"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + } break; + case OEMCrypto_ECC_Private_Key: { + if (!TestEccDrmKey(drm_key)) { + LOGE("Invalid ECC DRM key"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + } break; + default: { + LOGE("Unknown key type: %x", static_cast(drm_key_type)); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + } + + return WrapDrmKey(ce_->DeviceRootKey(), std::move(drm_key), wrapped_drm_key, + wrapped_drm_key_length); +} + +OEMCryptoResult SessionContext::LoadProvisioning( + const uint8_t* message, size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_length) { + if (message == nullptr || message_length == 0 || signature == nullptr || + signature_length == 0 || wrapped_private_key_length == nullptr) { + LOGE("Input argument is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + const std::vector device_id = ce_->DeviceRootId(); + // Range check performed by ODK library. + ODK_ParsedProvisioning parsed_response; + const OEMCryptoResult odk_result = ODK_ParseProvisioning( + message, message_length, core_message_length, &nonce_values_, + device_id.data(), device_id.size(), &parsed_response); + if (odk_result != OEMCrypto_SUCCESS) { + LOGE("ODK Error %d", odk_result); + return odk_result; + } + if (parsed_response.enc_private_key_iv.length != wvoec::KEY_IV_SIZE) { + LOGE("Encrypted private key iv has invalid length: %zu", + parsed_response.enc_private_key_iv.length); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + const uint32_t nonce = nonce_values_.nonce; + const uint8_t* message_body = message + core_message_length; + switch (ce_->config_provisioning_method()) { + case OEMCrypto_Keybox: + return RewrapDeviceDrmKey( + message, message_length, signature, signature_length, nonce, + parsed_response.key_type, + message_body + parsed_response.enc_private_key.offset, + parsed_response.enc_private_key.length, + message_body + parsed_response.enc_private_key_iv.offset, + wrapped_private_key, wrapped_private_key_length); + case OEMCrypto_OEMCertificate: + return RewrapDeviceDrmKey30( + nonce, message_body + parsed_response.encrypted_message_key.offset, + parsed_response.encrypted_message_key.length, + parsed_response.key_type, + message_body + parsed_response.enc_private_key.offset, + parsed_response.enc_private_key.length, + message_body + parsed_response.enc_private_key_iv.offset, + wrapped_private_key, wrapped_private_key_length); + default: + LOGE("Invalid provisioning method: %d.", + ce_->config_provisioning_method()); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } +} + OEMCryptoResult SessionContext::PrepAndSignLicenseRequest( uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length) { if (signature_length == nullptr || core_message_length == nullptr) { + LOGE("Output length parameters are null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (!drm_key_) { + LOGE("No DRM key available for signature"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } const size_t required_signature_size = CertSignatureSize(); OEMCryptoResult result = ODK_PrepareCoreLicenseRequest( message, message_length, core_message_length, &nonce_values_); @@ -424,13 +560,17 @@ OEMCryptoResult SessionContext::PrepAndSignProvisioningRequest( if (signature_length == nullptr || core_message_length == nullptr) { return OEMCrypto_ERROR_INVALID_CONTEXT; } + if (!drm_key_ && mac_key_client_.empty()) { + LOGE("Session cannot sign request"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } if (state_request_signed_) { LOGE("Attempt to sign prov request after license request"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } const size_t required_signature_size = ROTSignatureSize(); if (required_signature_size == 0) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - const std::vector& device_id = ce_->DeviceRootId(); + const std::vector device_id = ce_->DeviceRootId(); OEMCryptoResult result = ODK_PrepareCoreProvisioningRequest( message, message_length, core_message_length, &nonce_values_, device_id.data(), device_id.size()); @@ -479,7 +619,7 @@ OEMCryptoResult SessionContext::GenerateSignature(const uint8_t* message, *signature_length = SHA256_DIGEST_LENGTH; return OEMCrypto_ERROR_SHORT_BUFFER; } - unsigned int md_len = *signature_length; + unsigned int md_len = static_cast(*signature_length); if (HMAC(EVP_sha256(), &mac_key_client_[0], wvoec::MAC_KEY_SIZE, message, message_length, signature, &md_len)) { *signature_length = md_len; @@ -488,29 +628,20 @@ OEMCryptoResult SessionContext::GenerateSignature(const uint8_t* message, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } -// This is ussd when the device is a cast receiver. -size_t SessionContext::RSASignatureSize() { - if (!rsa_key()) { - LOGE("no RSA key set"); +size_t SessionContext::CertSignatureSize() const { + if (!drm_key_) { + LOGE("No DRM key set"); return 0; } - return static_cast(RSA_size(rsa_key())); + return drm_key_->SignatureSize(); } -size_t SessionContext::CertSignatureSize() { - // TODO(b/67735947): Add ECC cert support. - if (!rsa_key()) { - LOGE("No private key set"); - return 0; - } - return static_cast(RSA_size(rsa_key())); -} - -size_t SessionContext::ROTSignatureSize() { +size_t SessionContext::ROTSignatureSize() const { if (ce_->config_provisioning_method() == OEMCrypto_Keybox) return SHA256_DIGEST_LENGTH; - if (ce_->config_provisioning_method() == OEMCrypto_OEMCertificate) + if (ce_->config_provisioning_method() == OEMCrypto_OEMCertificate) { return CertSignatureSize(); + } LOGE("Bad prov method = %d", static_cast(ce_->config_provisioning_method())); return 0; @@ -519,92 +650,27 @@ size_t SessionContext::ROTSignatureSize() { OEMCryptoResult SessionContext::GenerateCertSignature( const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length) { - // TODO(b/67735947): Add ECC cert support. - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); - return OEMCrypto_ERROR_INVALID_CONTEXT; - } - if (!rsa_key()) { - LOGE("No RSA key set"); + if (!drm_key_) { + LOGE("No DRM key set"); return OEMCrypto_ERROR_INVALID_RSA_KEY; } - if (*signature_length < static_cast(RSA_size(rsa_key()))) { - *signature_length = CertSignatureSize(); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (allowed_schemes_ != kSign_RSASSA_PSS) { - LOGE("Message signing not allowed"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - - // Hash the message using SHA1. - uint8_t hash[SHA_DIGEST_LENGTH]; - if (!SHA1(message, message_length, hash)) { - LOGE("Error creating signature hash"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Add PSS padding. - std::vector padded_digest(*signature_length); - int status = RSA_padding_add_PKCS1_PSS_mgf1( - rsa_key(), &padded_digest[0], hash, EVP_sha1(), nullptr, kPssSaltLength); - if (status == -1) { - LOGE("Error padding hash"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - - // Encrypt PSS padded digest. - status = RSA_private_encrypt(*signature_length, &padded_digest[0], signature, - rsa_key(), RSA_NO_PADDING); - if (status == -1) { - LOGE("Error in private encrypt"); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - return OEMCrypto_SUCCESS; + return drm_key_->GenerateSignature(message, message_length, signature, + signature_length); } -OEMCryptoResult SessionContext::GenerateRSASignature( +OEMCryptoResult SessionContext::GenerateRsaSignature( const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme) { - if (message == nullptr || message_length == 0 || signature == nullptr || - signature_length == 0) { - LOGE("OEMCrypto_ERROR_INVALID_CONTEXT"); + if (padding_scheme != kSign_PKCS1_Block1) { + LOGE("Only PKCS1 block1 padding scheme allowed"); return OEMCrypto_ERROR_INVALID_CONTEXT; } - if (!rsa_key()) { - LOGE("No RSA key set"); + if (!drm_key_ || !drm_key_->IsRsaKey()) { + LOGE("No RSA DRM key set"); return OEMCrypto_ERROR_INVALID_RSA_KEY; } - if (*signature_length < static_cast(RSA_size(rsa_key()))) { - *signature_length = RSA_size(rsa_key()); - return OEMCrypto_ERROR_SHORT_BUFFER; - } - if (((padding_scheme & allowed_schemes_) != padding_scheme) || - (padding_scheme != kSign_PKCS1_Block1)) { - LOGE("padding_scheme not allowed"); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - // This is the maximum digest size possible for PKCS1 block type 1, - // as used for a CAST receiver. - const size_t max_digest_size = 83u; - if (message_length > max_digest_size) { - LOGE("RSA digest too large"); - return OEMCrypto_ERROR_SIGNATURE_FAILURE; - } - // Pad the message with PKCS1 padding, and then encrypt. - const int status = RSA_private_encrypt(message_length, message, signature, - rsa_key(), RSA_PKCS1_PADDING); - if (status < 0) { - LOGE("Error in RSA private encrypt. status = %d", status); - dump_boringssl_error(); - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - *signature_length = static_cast(RSA_size(rsa_key())); - return OEMCrypto_SUCCESS; + return drm_key_->GenerateRsaSignature(message, message_length, signature, + signature_length); } // Validate message signature @@ -618,8 +684,9 @@ bool SessionContext::ValidateMessage(const uint8_t* given_message, uint8_t computed_signature[SHA256_DIGEST_LENGTH]; memset(computed_signature, 0, SHA256_DIGEST_LENGTH); unsigned int md_len = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), mac_key_server_.data(), mac_key_server_.size(), - given_message, message_length, computed_signature, &md_len)) { + if (!HMAC(EVP_sha256(), mac_key_server_.data(), + static_cast(mac_key_server_.size()), given_message, + message_length, computed_signature, &md_len)) { LOGE("ValidateMessage: Could not compute signature"); return false; } @@ -799,8 +866,10 @@ OEMCryptoResult SessionContext::LoadKeysNoSignature( message + srm_restriction_data.offset); return OEMCrypto_ERROR_INVALID_CONTEXT; } - const uint32_t minimum_version = htonl(*reinterpret_cast( - message + srm_restriction_data.offset + 8)); + uint32_t minimum_version_nbo; + memcpy(&minimum_version_nbo, message + srm_restriction_data.offset + 8, + sizeof(uint32_t)); + const uint32_t minimum_version = htonl(minimum_version_nbo); uint16_t current_version = 0; if (OEMCrypto_SUCCESS != ce_->current_srm_version(¤t_version)) { LOGW("[LoadKeys: SRM Version not available"); @@ -1033,25 +1102,19 @@ OEMCryptoResult SessionContext::InstallKey( return OEMCrypto_SUCCESS; } -bool SessionContext::InstallRSAEncryptedKey( - const uint8_t* encrypted_message_key, size_t encrypted_message_key_length) { - encryption_key_.resize(RSA_size(rsa_key())); - const int decrypted_size = RSA_private_decrypt( - encrypted_message_key_length, encrypted_message_key, &encryption_key_[0], - rsa_key(), RSA_PKCS1_OAEP_PADDING); - if (-1 == decrypted_size) { - LOGE("[RSADeriveKeys(): error decrypting session key.]"); - dump_boringssl_error(); +bool SessionContext::InstallRsaEncryptedKey( + const std::vector& enc_encryption_key) { + if (!drm_key_ || !drm_key_->IsRsaKey()) { + LOGE("Session does not have an OEM cert key"); return false; } - encryption_key_.resize(decrypted_size); - if (decrypted_size != static_cast(wvoec::KEY_SIZE)) { - LOGE("[RSADeriveKeys(): error. Session key is wrong size: %d.]", - decrypted_size); - dump_boringssl_error(); - encryption_key_.clear(); + std::vector encryption_key = + drm_key_->GetEncryptionKey(enc_encryption_key); + if (encryption_key.empty()) { + LOGE("Failed to decrypt session encryption key"); return false; } + encryption_key_ = std::move(encryption_key); return true; } @@ -1126,59 +1189,171 @@ OEMCryptoResult SessionContext::RefreshKey( return result; } -bool SessionContext::DecryptRSAKey(const uint8_t* enc_rsa_key, - size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, - uint8_t* pkcs8_rsa_key) { - if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) { - LOGE("[DecryptRSAKey(): bad buffer size]"); +bool SessionContext::DecryptDrmKey(const uint8_t* enc_drm_key, + size_t enc_drm_key_length, + const uint8_t* enc_drm_key_iv, + std::vector* drm_key) const { + if (enc_drm_key_length % AES_BLOCK_SIZE != 0 || enc_drm_key_length == 0) { + LOGE("DRM key size is not block aligned"); return false; } - // Decrypt rsa key with keybox. + if (encryption_key_.empty()) { + LOGE("No encryption key"); + return false; + } + // Decrypt DRM key session's encryption key. uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE); + memcpy(iv_buffer, enc_drm_key_iv, wvoec::KEY_IV_SIZE); AES_KEY aes_key; - AES_set_decrypt_key(&encryption_key_[0], 128, &aes_key); - AES_cbc_encrypt(enc_rsa_key, pkcs8_rsa_key, enc_rsa_key_length, &aes_key, + AES_set_decrypt_key(encryption_key_.data(), 128, &aes_key); + drm_key->resize(enc_drm_key_length); + AES_cbc_encrypt(enc_drm_key, drm_key->data(), enc_drm_key_length, &aes_key, iv_buffer, AES_DECRYPT); + // Check padding, ignore if bad, the key will fail to parse. + const size_t padding = drm_key->back(); + if (padding <= AES_BLOCK_SIZE) { + drm_key->resize(drm_key->size() - padding); + } return true; } -bool SessionContext::EncryptRSAKey(const uint8_t* pkcs8_rsa_key, - size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, - uint8_t* enc_rsa_key) { - if (enc_rsa_key_length % AES_BLOCK_SIZE != 0) { - LOGE("[EncryptRSAKey(): bad buffer size]"); - return false; +size_t SessionContext::ExpectedWrappedDrmKeySize( + size_t enc_drm_key_length) const { + return enc_drm_key_length + sizeof(WrappedDrmKey); +} + +OEMCryptoResult SessionContext::WrapDrmKey( + const std::vector& master_key, std::vector&& drm_key, + uint8_t* wrapped_drm_key, size_t* wrapped_drm_key_length) { + if (wrapped_drm_key_length == nullptr) { + LOGE("Wrapped DRM key length is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; } - // Encrypt rsa key with keybox. + std::vector padded_drm_key = std::move(drm_key); + // Add padding. + const uint8_t padding = + AES_BLOCK_SIZE - (padded_drm_key.size() % AES_BLOCK_SIZE); + padded_drm_key.insert(padded_drm_key.end(), padding, padding); + // Check that output is large enough. + const size_t final_size = sizeof(WrappedDrmKey) + padded_drm_key.size(); + if (wrapped_drm_key == nullptr || *wrapped_drm_key_length < final_size) { + *wrapped_drm_key_length = final_size; + return OEMCrypto_ERROR_SHORT_BUFFER; + } + *wrapped_drm_key_length = final_size; + // Setup wrapper and message keys. + WrappedDrmKey* wrapped = reinterpret_cast(wrapped_drm_key); + if (RAND_bytes(wrapped->context, sizeof(wrapped->context)) != 1) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (RAND_bytes(wrapped->iv, sizeof(wrapped->iv)) != 1) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + const std::vector context( + wrapped->context, wrapped->context + sizeof(wrapped->context)); + const OEMCryptoResult derive_key_result = + DeriveKeys(master_key, context, context); + if (derive_key_result != OEMCrypto_SUCCESS) { + LOGE("DeriveKeys failed"); + return derive_key_result; + } + // Encrypt DRM key. uint8_t iv_buffer[wvoec::KEY_IV_SIZE]; - memcpy(iv_buffer, enc_rsa_key_iv, wvoec::KEY_IV_SIZE); + memcpy(iv_buffer, wrapped->iv, sizeof(iv_buffer)); AES_KEY aes_key; - AES_set_encrypt_key(&encryption_key_[0], 128, &aes_key); - AES_cbc_encrypt(pkcs8_rsa_key, enc_rsa_key, enc_rsa_key_length, &aes_key, - iv_buffer, AES_ENCRYPT); + AES_set_encrypt_key(encryption_key_.data(), 128, &aes_key); + AES_cbc_encrypt(padded_drm_key.data(), wrapped->enc_drm_key, + padded_drm_key.size(), &aes_key, iv_buffer, AES_ENCRYPT); + // Sign. + unsigned int sig_length = sizeof(wrapped->signature); + if (!HMAC(EVP_sha256(), mac_key_server_.data(), + static_cast(mac_key_server_.size()), wrapped->context, + final_size - sizeof(wrapped->signature), wrapped->signature, + &sig_length)) { + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return OEMCrypto_SUCCESS; +} + +OEMCryptoResult SessionContext::UnwrapDrmKey( + const std::vector& master_key, const uint8_t* wrapped_drm_key, + size_t wrapped_drm_key_length, std::vector* drm_key) { + if (wrapped_drm_key == nullptr) { + LOGE("Wrapped DRM key is null"); + return OEMCrypto_ERROR_INVALID_CONTEXT; + } + if (wrapped_drm_key_length < sizeof(WrappedDrmKey)) { + LOGE("DRM Key is too small"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + const WrappedDrmKey* wrapped = + reinterpret_cast(wrapped_drm_key); + // Derive message keys. + const std::vector context( + wrapped->context, wrapped->context + sizeof(wrapped->context)); + const OEMCryptoResult derive_key_result = + DeriveKeys(master_key, context, context); + if (derive_key_result != OEMCrypto_SUCCESS) { + LOGE("DeriveKeys failed"); + return derive_key_result; + } + // Verify message. + if (!ValidateMessage(wrapped->context, + wrapped_drm_key_length - sizeof(wrapped->signature), + wrapped->signature, sizeof(wrapped->signature))) { + LOGE("Could not verify signature"); + return OEMCrypto_ERROR_SIGNATURE_FAILURE; + } + // Decrypt DRM key. + const size_t enc_drm_key_length = + wrapped_drm_key_length - sizeof(WrappedDrmKey); + if (!DecryptDrmKey(wrapped->enc_drm_key, enc_drm_key_length, wrapped->iv, + drm_key)) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + return OEMCrypto_SUCCESS; +} + +bool SessionContext::TestRsaDrmKey( + const std::vector& pkcs8_rsa_key) const { + std::unique_ptr key = RsaPrivateKey::Load(pkcs8_rsa_key); + if (!key) { + LOGE("Failed to parse RSA key"); + return false; + } + return ValidateRsaKeySchemes(key.get()); +} + +bool SessionContext::LoadRsaDrmKey(const std::vector& pkcs8_rsa_key) { + std::unique_ptr key = RsaPrivateKey::Load(pkcs8_rsa_key); + if (!key) { + LOGE("Failed to parse RSA key"); + return false; + } + if (!ValidateRsaKeySchemes(key.get())) return false; + drm_key_ = DrmPrivateKey::Create(std::move(key)); return true; } -bool SessionContext::LoadRSAKey(const uint8_t* pkcs8_rsa_key, - size_t rsa_key_length) { - rsa_key_.reset(); - if (rsa_key_length < 8) { - LOGE("[LoadRSAKey(): Very Short Buffer]"); +bool SessionContext::TestEccDrmKey( + const std::vector& ecc_private_key) const { + std::unique_ptr key = EccPrivateKey::Load(ecc_private_key); + if (!key) { + LOGE("Failed to parse ECC key"); return false; } - if ((memcmp(pkcs8_rsa_key, "SIGN", 4) == 0)) { - uint32_t schemes_n; - memcpy((uint8_t*)&schemes_n, pkcs8_rsa_key + 4, sizeof(uint32_t)); - allowed_schemes_ = htonl(schemes_n); - pkcs8_rsa_key += 8; - rsa_key_length -= 8; - } else { - allowed_schemes_ = kSign_RSASSA_PSS; + return true; +} + +bool SessionContext::LoadEccDrmKey( + const std::vector& ecc_private_key) { + std::unique_ptr key = EccPrivateKey::Load(ecc_private_key); + if (!key) { + LOGE("Failed to parse ECC key"); + return false; } - return rsa_key_.LoadPkcs8RsaKey(pkcs8_rsa_key, rsa_key_length); + drm_key_ = DrmPrivateKey::Create(std::move(key)); + return true; } OEMCryptoResult SessionContext::CheckKeyUse(const std::string& log_string, @@ -1354,14 +1529,13 @@ OEMCryptoResult SessionContext::Generic_Sign(const uint8_t* in_buffer, LOGE("[Generic_Sign(): bad algorithm"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - unsigned int md_len = *signature_length; - if (HMAC(EVP_sha256(), &key[0], key.size(), in_buffer, buffer_length, - signature, &md_len)) { + unsigned int md_len = static_cast(*signature_length); + if (HMAC(EVP_sha256(), &key[0], static_cast(key.size()), in_buffer, + buffer_length, signature, &md_len)) { *signature_length = md_len; return OEMCrypto_SUCCESS; } LOGE("[Generic_Sign(): hmac failed"); - dump_boringssl_error(); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -1390,10 +1564,10 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer, LOGE("[Generic_Verify(): bad algorithm"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - unsigned int md_len = signature_length; + unsigned int md_len = static_cast(signature_length); uint8_t computed_signature[SHA256_DIGEST_LENGTH]; - if (HMAC(EVP_sha256(), &key[0], key.size(), in_buffer, buffer_length, - computed_signature, &md_len)) { + if (HMAC(EVP_sha256(), &key[0], static_cast(key.size()), in_buffer, + buffer_length, computed_signature, &md_len)) { if (0 == CRYPTO_memcmp(signature, computed_signature, SHA256_DIGEST_LENGTH)) { return OEMCrypto_SUCCESS; @@ -1402,7 +1576,6 @@ OEMCryptoResult SessionContext::Generic_Verify(const uint8_t* in_buffer, } } LOGE("[Generic_Verify(): HMAC failed"); - dump_boringssl_error(); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -1783,7 +1956,7 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8, return OEMCrypto_ERROR_DECRYPT_FAILED; } AES_encrypt(aes_iv_u8, ecount_buf, &aes_key); - for (int n = block_offset; n < AES_BLOCK_SIZE && l < cipher_data_length; + for (size_t n = block_offset; n < AES_BLOCK_SIZE && l < cipher_data_length; ++n, ++l) { clear_data[l] = cipher_data[l] ^ ecount_buf[n]; } @@ -1818,7 +1991,7 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8, } if (!EVP_DecryptUpdate(evp_cipher_ctx, &clear_data[l], &out_len, - &cipher_data[l], decrypt_length)) { + &cipher_data[l], static_cast(decrypt_length))) { LOGE("[DecryptCTR(): EVP_UPDATE_ERROR]"); EVP_CIPHER_CTX_free(evp_cipher_ctx); return OEMCrypto_ERROR_DECRYPT_FAILED; @@ -1858,7 +2031,7 @@ OEMCryptoResult SessionContext::SetDecryptHash(uint32_t frame_number, } compute_hash_ = true; current_frame_number_ = frame_number; - given_hash_ = *reinterpret_cast(hash); + memcpy(&given_hash_, hash, sizeof(uint32_t)); return OEMCrypto_SUCCESS; } diff --git a/oemcrypto/ref/src/oemcrypto_session.h b/oemcrypto/ref/src/oemcrypto_session.h index cd768b9..04ef712 100644 --- a/oemcrypto/ref/src/oemcrypto_session.h +++ b/oemcrypto/ref/src/oemcrypto_session.h @@ -17,14 +17,21 @@ #include "OEMCryptoCENC.h" #include "odk_structs.h" #include "oemcrypto_auth_ref.h" +#include "oemcrypto_drm_key.h" #include "oemcrypto_key_ref.h" -#include "oemcrypto_rsa_key_shared.h" #include "oemcrypto_session_key_table.h" #include "oemcrypto_types.h" #include "oemcrypto_usage_table_ref.h" namespace wvoec_ref { +typedef struct { + uint8_t signature[wvoec::MAC_KEY_SIZE]; + uint8_t context[wvoec::MAC_KEY_SIZE]; + uint8_t iv[wvoec::KEY_IV_SIZE]; + uint8_t enc_drm_key[]; +} WrappedDrmKey; + class CryptoEngine; typedef uint32_t SessionId; @@ -59,21 +66,54 @@ class SessionContextKeys { }; class SessionContext { - public: + SessionContext(CryptoEngine* ce, SessionId sid); SessionContext(CryptoEngine* ce, SessionId sid, - const RSA_shared_ptr& rsa_key); + std::shared_ptr&& rsa_key); SessionContext() = delete; virtual ~SessionContext(); - bool isValid() { return valid_; } + bool isValid() const { return valid_; } + + // Message key operations. + + virtual OEMCryptoResult DeriveKeys(const std::vector& master_key, + const std::vector& mac_context, + const std::vector& enc_context); + virtual OEMCryptoResult DeriveKeysWithSessionKey( + const std::vector& session_key_source, + const std::vector& mac_context, + const std::vector& enc_context); + + virtual OEMCryptoResult LoadOemPrivateKey(); + virtual OEMCryptoResult LoadWrappedDrmKey( + const std::vector& master_key, OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_drm_key, size_t wrapped_drm_key_length); + + // Provisioning. + virtual OEMCryptoResult PrepAndSignProvisioningRequest( + uint8_t* message, size_t message_length, size_t* core_message_length, + uint8_t* signature, size_t* signature_length); + + virtual OEMCryptoResult RewrapDeviceDrmKey( + const uint8_t* message, size_t message_length, const uint8_t* signature, + size_t signature_length, uint32_t nonce, + OEMCrypto_PrivateKeyType drm_key_type, const uint8_t* enc_drm_key, + size_t enc_drm_key_length, const uint8_t* enc_drm_key_iv, + uint8_t* wrapped_drm_key, size_t* wrapped_drm_key_length); + + virtual OEMCryptoResult RewrapDeviceDrmKey30( + uint32_t nonce, const uint8_t* encrypted_message_key, + size_t encrypted_message_key_length, + OEMCrypto_PrivateKeyType drm_key_type, const uint8_t* enc_drm_key, + size_t enc_drm_key_length, const uint8_t* enc_drm_key_iv, + uint8_t* wrapped_drm_key, size_t* wrapped_drm_key_length); + + virtual OEMCryptoResult LoadProvisioning( + const uint8_t* message, size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length, + uint8_t* wrapped_private_key, size_t* wrapped_private_key_length); - virtual bool DeriveKeys(const std::vector& master_key, - const std::vector& mac_context, - const std::vector& enc_context); - virtual bool RSADeriveKeys(const std::vector& enc_session_key, - const std::vector& mac_context, - const std::vector& enc_context); virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message, size_t message_length, size_t* core_message_length, @@ -84,15 +124,12 @@ class SessionContext { size_t* core_message_length, uint8_t* signature, size_t* signature_length); - virtual OEMCryptoResult PrepAndSignProvisioningRequest( - uint8_t* message, size_t message_length, size_t* core_message_length, - uint8_t* signature, size_t* signature_length); - // The size of an RSA signature. This is used when signing as a CAST - // receiver. - size_t RSASignatureSize(); - virtual OEMCryptoResult GenerateRSASignature( + + // Restricted to CAST receivers using PKCS1 block padding only. + virtual OEMCryptoResult GenerateRsaSignature( const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme); + virtual bool ValidateMessage(const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length); @@ -141,13 +178,7 @@ class SessionContext { const std::vector& key_data_iv, const std::vector& key_control, const std::vector& key_control_iv); - bool InstallRSAEncryptedKey(const uint8_t* encrypted_message_key, - size_t encrypted_message_key_length); - bool DecryptRSAKey(const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, - const uint8_t* wrapped_rsa_key_iv, uint8_t* pkcs8_rsa_key); - bool EncryptRSAKey(const uint8_t* pkcs8_rsa_key, size_t enc_rsa_key_length, - const uint8_t* enc_rsa_key_iv, uint8_t* enc_rsa_key); - bool LoadRSAKey(const uint8_t* pkcs8_rsa_key, size_t rsa_key_length); + virtual OEMCryptoResult LoadRenewal(const uint8_t* message, size_t message_length, size_t core_message_length, @@ -179,7 +210,6 @@ class SessionContext { encryption_key_ = enc_key; } const std::vector& encryption_key() { return encryption_key_; } - uint32_t allowed_schemes() const { return allowed_schemes_; } // Return true if nonce was set. bool set_nonce(uint32_t nonce); @@ -204,10 +234,30 @@ class SessionContext { bool usage_entry_present() const { return usage_entry_ != nullptr; } protected: + bool InstallRsaEncryptedKey(const std::vector& enc_encryption_key); + + bool TestRsaDrmKey(const std::vector& pkcs8_rsa_key) const; + bool LoadRsaDrmKey(const std::vector& pkcs8_rsa_key); + bool TestEccDrmKey(const std::vector& ecc_private_key) const; + bool LoadEccDrmKey(const std::vector& ecc_private_key); + + bool DecryptDrmKey(const uint8_t* enc_drm_key, size_t enc_drm_key_length, + const uint8_t* enc_drm_key_iv, + std::vector* drm_key) const; + size_t ExpectedWrappedDrmKeySize(size_t enc_drm_key_length) const; + OEMCryptoResult WrapDrmKey(const std::vector& master_key, + std::vector&& drm_key, + uint8_t* wrapped_drm_key, + size_t* wrapped_drm_key_length); + OEMCryptoResult UnwrapDrmKey(const std::vector& master_key, + const uint8_t* wrapped_drm_key, + size_t wrapped_drm_key_length, + std::vector* drm_key); + // Signature size of the currently loaded private key. - size_t CertSignatureSize(); + size_t CertSignatureSize() const; // Signature size when using a keybox or OEM Cert's private key. - size_t ROTSignatureSize(); + size_t ROTSignatureSize() const; virtual OEMCryptoResult GenerateCertSignature(const uint8_t* message, size_t message_length, uint8_t* signature, @@ -216,9 +266,6 @@ class SessionContext { size_t message_length, uint8_t* signature, size_t* signature_length); - bool DeriveKey(const std::vector& key, - const std::vector& context, int counter, - std::vector* out); bool DecryptMessage(const std::vector& key, const std::vector& iv, const std::vector& message, @@ -257,46 +304,52 @@ class SessionContext { // entry, it also checks the usage entry. OEMCryptoResult CheckKeyUse(const std::string& log_string, uint32_t use_type, OEMCryptoBufferType buffer_type); - RSA* rsa_key() { return rsa_key_.get(); } - bool valid_; - CryptoEngine* ce_; + bool valid_ = false; + CryptoEngine* ce_ = nullptr; SessionId id_; + + // Message keys. + std::unique_ptr drm_key_; std::vector mac_key_server_; std::vector mac_key_client_; std::vector encryption_key_; std::vector session_key_; - const Key* current_content_key_; - std::unique_ptr session_keys_; + ODK_NonceValues nonce_values_; uint8_t license_request_hash_[ODK_SHA256_HASH_SIZE]; - RSA_shared_ptr rsa_key_; - uint32_t allowed_schemes_; // for RSA signatures. - bool decrypt_started_; // If the license has been used in this session. + + // Content/entitlement keys. + const Key* current_content_key_ = nullptr; + std::unique_ptr session_keys_; + + bool decrypt_started_ = + false; // If the license has been used in this session. ODK_TimerLimits timer_limits_; ODK_ClockValues clock_values_; std::unique_ptr usage_entry_; - SRMVersionStatus srm_requirements_status_; + SRMVersionStatus srm_requirements_status_ = NoSRMVersion; enum UsageEntryStatus { kNoUsageEntry, // No entry loaded for this session. kUsageEntryNew, // After entry was created. kUsageEntryLoaded, // After loading entry or loading keys. }; - UsageEntryStatus usage_entry_status_; + UsageEntryStatus usage_entry_status_ = kNoUsageEntry; // These are used when doing full decrypt path testing. - bool compute_hash_; // True if the current frame needs a hash. - uint32_t current_hash_; // Running CRC hash of frame. - uint32_t given_hash_; // True CRC hash of frame. - uint32_t current_frame_number_; // Current frame for CRC hash. - uint32_t bad_frame_number_; // Frame number with bad hash. - OEMCryptoResult hash_error_; // Error code for first bad frame. + bool compute_hash_ = false; // True if the current frame needs a hash. + uint32_t current_hash_ = 0; // Running CRC hash of frame. + uint32_t given_hash_ = 0; // True CRC hash of frame. + uint32_t current_frame_number_ = 0; // Current frame for CRC hash. + uint32_t bad_frame_number_ = 0; // Frame number with bad hash. + OEMCryptoResult hash_error_ = + OEMCrypto_SUCCESS; // Error code for first bad frame. // The bare minimum state machine is to only call each of these function // categories at most once. - bool state_nonce_created_; - bool state_request_signed_; - bool state_response_loaded_; + bool state_nonce_created_ = false; + bool state_request_signed_ = false; + bool state_response_loaded_ = false; CORE_DISALLOW_COPY_AND_ASSIGN(SessionContext); }; diff --git a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp b/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp index b3750c1..f9d4976 100644 --- a/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp +++ b/oemcrypto/ref/src/oemcrypto_usage_table_ref.cpp @@ -6,6 +6,7 @@ // #include "oemcrypto_usage_table_ref.h" +#include #include #include @@ -223,7 +224,7 @@ OEMCryptoResult UsageTableEntry::SaveData(CryptoEngine* ce, // Sign the entry. unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), + if (!HMAC(EVP_sha256(), &key[0], static_cast(key.size()), &signed_buffer[SHA256_DIGEST_LENGTH], buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature, &sig_length)) { @@ -256,9 +257,9 @@ OEMCryptoResult UsageTableEntry::LoadData(CryptoEngine* ce, uint32_t index, // Verify the signature of the usage entry. Sign encrypted into clear buffer. unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH], - buffer.size() - SHA256_DIGEST_LENGTH, clear->signature, - &sig_length)) { + if (!HMAC(EVP_sha256(), &key[0], static_cast(key.size()), + &buffer[SHA256_DIGEST_LENGTH], buffer.size() - SHA256_DIGEST_LENGTH, + clear->signature, &sig_length)) { LOGE("LoadUsageEntry: Could not sign entry."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -362,10 +363,10 @@ OEMCryptoResult UsageTable::CreateNewUsageEntry( } if (!entry) return OEMCrypto_ERROR_UNKNOWN_FAILURE; if (!usage_entry_number) return OEMCrypto_ERROR_UNKNOWN_FAILURE; - const size_t index = generation_numbers_.size(); + const uint32_t index = static_cast(generation_numbers_.size()); const size_t max = ce_->max_usage_table_size(); if (max > 0 && index >= max) { - LOGE("Too many usage entries: %zu/%zu", index, max); + LOGE("Too many usage entries: %u/%zu", index, max); return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; } UsageTableEntry* new_entry = MakeEntry(index); @@ -405,13 +406,14 @@ OEMCryptoResult UsageTable::LoadUsageEntry( return status; } if (new_entry->generation_number() != generation_numbers_[index]) { - LOGE("Generation SKEW: %ld -> %ld", new_entry->generation_number(), - generation_numbers_[index]); - if ((new_entry->generation_number() + 1 < generation_numbers_[index]) || - (new_entry->generation_number() - 1 > generation_numbers_[index])) { + LOGE("Generation SKEW: %" PRId64 " -> %" PRId64, + new_entry->generation_number(), generation_numbers_[index]); + if ((new_entry->generation_number() + 1 == generation_numbers_[index]) || + (new_entry->generation_number() - 1 == generation_numbers_[index])) { + status = OEMCrypto_WARNING_GENERATION_SKEW; + } else { return OEMCrypto_ERROR_GENERATION_SKEW; } - status = OEMCrypto_WARNING_GENERATION_SKEW; } sessions_[index] = session; *entry = std::move(new_entry); @@ -496,7 +498,7 @@ OEMCryptoResult UsageTable::SaveUsageTableHeader(uint8_t* signed_buffer, // Sign the entry. unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), + if (!HMAC(EVP_sha256(), &key[0], static_cast(key.size()), &signed_buffer[SHA256_DIGEST_LENGTH], buffer_size - SHA256_DIGEST_LENGTH, encrypted->signature, &sig_length)) { @@ -533,9 +535,9 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader( // Verify the signature of the usage entry. Sign encrypted into clear buffer. unsigned int sig_length = SHA256_DIGEST_LENGTH; - if (!HMAC(EVP_sha256(), &key[0], key.size(), &buffer[SHA256_DIGEST_LENGTH], - buffer.size() - SHA256_DIGEST_LENGTH, clear->signature, - &sig_length)) { + if (!HMAC(EVP_sha256(), &key[0], static_cast(key.size()), + &buffer[SHA256_DIGEST_LENGTH], buffer.size() - SHA256_DIGEST_LENGTH, + clear->signature, &sig_length)) { LOGE("LoadUsageTableHeader: Could not sign entry."); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } @@ -581,13 +583,14 @@ OEMCryptoResult UsageTable::LoadUsageTableHeader( OEMCryptoResult status = OEMCrypto_SUCCESS; if (clear->master_generation != master_generation_number_) { - LOGE("Generation SKEW: %ld -> %ld", clear->master_generation, + LOGE("Generation SKEW: %" PRId64 " -> %" PRId64, clear->master_generation, master_generation_number_); - if ((clear->master_generation + 1 < master_generation_number_) || - (clear->master_generation - 1 > master_generation_number_)) { + if ((clear->master_generation + 1 == master_generation_number_) || + (clear->master_generation - 1 == master_generation_number_)) { + status = OEMCrypto_WARNING_GENERATION_SKEW; + } else { return OEMCrypto_ERROR_GENERATION_SKEW; } - status = OEMCrypto_WARNING_GENERATION_SKEW; } int64_t* stored_generations = reinterpret_cast(&clear_buffer[0] + sizeof(SignedHeaderBlock)); @@ -615,7 +618,7 @@ OEMCryptoResult UsageTable::MoveEntry(UsageTableEntry* entry, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } sessions_[new_index] = sessions_[entry->index()]; - sessions_[entry->index()] = 0; + sessions_[entry->index()] = nullptr; entry->set_index(new_index); generation_numbers_[new_index] = master_generation_number_; diff --git a/oemcrypto/ref/src/oemcrypto_usage_table_ref.h b/oemcrypto/ref/src/oemcrypto_usage_table_ref.h index 7fdd178..18c0cfc 100644 --- a/oemcrypto/ref/src/oemcrypto_usage_table_ref.h +++ b/oemcrypto/ref/src/oemcrypto_usage_table_ref.h @@ -107,7 +107,7 @@ class UsageTable { OEMCryptoResult ShrinkUsageTableHeader(uint32_t new_table_size, uint8_t* header_buffer, size_t* header_buffer_length); - void ReleaseEntry(uint32_t index) { sessions_[index] = 0; } + void ReleaseEntry(uint32_t index) { sessions_[index] = nullptr; } void IncrementGeneration(); static size_t SignedHeaderSize(size_t count); diff --git a/oemcrypto/ref/src/scoped_object.h b/oemcrypto/ref/src/scoped_object.h new file mode 100644 index 0000000..5acdc0a --- /dev/null +++ b/oemcrypto/ref/src/scoped_object.h @@ -0,0 +1,71 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef SCOPED_OBJECT_H_ +#define SCOPED_OBJECT_H_ + +namespace wvoec_ref { + +// A generic wrapper around pointer. This allows for automatic +// memory clean up when the ScopedObject variable goes out of scope. +// This is intended to be used with OpenSSL/BoringSSL structs. +template +class ScopedObject { + public: + ScopedObject() : ptr_(nullptr) {} + ScopedObject(Type* ptr) : ptr_(ptr) {} + ~ScopedObject() { + if (ptr_) { + Destructor(ptr_); + ptr_ = nullptr; + } + } + + // Copy construction and assignment are not allowed. + ScopedObject(const ScopedObject& other) = delete; + ScopedObject& operator=(const ScopedObject& other) = delete; + + // Move construction and assignment are allowed. + ScopedObject(ScopedObject&& other) : ptr_(other.ptr_) { + other.ptr_ = nullptr; + } + ScopedObject& operator=(ScopedObject&& other) { + if (ptr_) { + Destructor(ptr_); + } + ptr_ = other.ptr_; + other.ptr_ = nullptr; + return *this; + } + + explicit operator bool() const { return ptr_ != nullptr; } + + Type& operator*() { return *ptr_; } + Type* get() const { return ptr_; } + Type* operator->() const { return ptr_; } + + // Releasing the pointer will remove the responsibility of the + // ScopedObject to clean up the pointer. + Type* release() { + Type* temp = ptr_; + ptr_ = nullptr; + return temp; + } + + void reset(Type* ptr = nullptr) { + if (ptr_) { + Destructor(ptr_); + } + ptr_ = ptr; + } + + private: + Type* ptr_ = nullptr; +}; + +} // namespace wvoec_ref + +#endif // SCOPED_OBJECT_H_ diff --git a/oemcrypto/ref/src/wvcrc.cpp b/oemcrypto/ref/src/wvcrc.cpp index f357ad8..27e838c 100644 --- a/oemcrypto/ref/src/wvcrc.cpp +++ b/oemcrypto/ref/src/wvcrc.cpp @@ -2,7 +2,7 @@ // source code may only be used and distributed under the Widevine // License Agreement. // -// Compute CRC32 Checksum. Needed for verification of WV Keybox. +// Compute CRC32/MPEG2 Checksum. Needed for verification of WV Keybox. // #include "platform.h" #include "wvcrc32.h" diff --git a/oemcrypto/ref/test/cmac_unittest.cpp b/oemcrypto/ref/test/cmac_unittest.cpp new file mode 100644 index 0000000..1dcae00 --- /dev/null +++ b/oemcrypto/ref/test/cmac_unittest.cpp @@ -0,0 +1,128 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include + +#include "cmac.h" + +namespace wvoec_ref { +namespace { +// Test vectors are from NIST Special Publication 800-38B for +// CMAC-AES-128 and CMAC-AES-256. The same data chunks are used +// for both tests. +const uint8_t kDataChunk1[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a}; +const uint8_t kDataChunk2[] = {0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11}; +const uint8_t kDataChunk3[] = {0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}; + +const uint8_t kKey128[16] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; +const uint8_t kKey256[32] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; +} // namespace + +TEST(OEMCryptoCmacTest, BadInit) { + // If the parameters to the Create() function are invalid, the + // Cmac instance is not created. + std::unique_ptr cmac = Cmac::Create(nullptr, sizeof(kKey128)); + EXPECT_FALSE(cmac); + cmac = Cmac::Create(nullptr, sizeof(kKey256)); + EXPECT_FALSE(cmac); + cmac = Cmac::Create(kKey128, 0); + EXPECT_FALSE(cmac); + cmac = Cmac::Create(kKey256, (sizeof(kKey128) + sizeof(kKey256)) / 2); + EXPECT_FALSE(cmac); +} + +TEST(OEMCryptoCmacTest, CmacAes128) { + std::unique_ptr cmac = Cmac::Create(kKey128, sizeof(kKey128)); + ASSERT_TRUE(cmac); + + std::vector digest; + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedEmptyDigest = { + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46}; + EXPECT_EQ(kExpectedEmptyDigest, digest); + cmac->Reset(); + + ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1))); + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedDigest1 = { + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c}; + EXPECT_EQ(kExpectedDigest1, digest); + cmac->Reset(); + + ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1))); + ASSERT_TRUE(cmac->Update(kDataChunk2, sizeof(kDataChunk2))); + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedDigest2 = { + 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27}; + EXPECT_EQ(kExpectedDigest2, digest); + cmac->Reset(); + + ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1))); + for (size_t i = 0; i < sizeof(kDataChunk2); i++) { + ASSERT_TRUE(cmac->Update(kDataChunk2[i])) << " i = " << i; + } + ASSERT_TRUE(cmac->Update(kDataChunk3, sizeof(kDataChunk3))); + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedDigest3 = { + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe}; + EXPECT_EQ(kExpectedDigest3, digest); +} + +TEST(OEMCryptoCmacTest, CmacAes256) { + std::unique_ptr cmac = Cmac::Create(kKey256, sizeof(kKey256)); + ASSERT_TRUE(cmac); + + std::vector digest; + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedEmptyDigest = { + 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, + 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83}; + EXPECT_EQ(kExpectedEmptyDigest, digest); + cmac->Reset(); + + ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1))); + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedDigest1 = { + 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, + 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c}; + EXPECT_EQ(kExpectedDigest1, digest); + cmac->Reset(); + + ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1))); + ASSERT_TRUE(cmac->Update(kDataChunk2, sizeof(kDataChunk2))); + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedDigest2 = { + 0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, + 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6}; + EXPECT_EQ(kExpectedDigest2, digest); + cmac->Reset(); + + ASSERT_TRUE(cmac->Update(kDataChunk1, sizeof(kDataChunk1))); + for (size_t i = 0; i < sizeof(kDataChunk2); i++) { + ASSERT_TRUE(cmac->Update(kDataChunk2[i])) << " i = " << i; + } + ASSERT_TRUE(cmac->Update(kDataChunk3, sizeof(kDataChunk3))); + ASSERT_TRUE(cmac->Finalize(&digest)); + const std::vector kExpectedDigest3 = { + 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, + 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10}; + EXPECT_EQ(kExpectedDigest3, digest); +} + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/test/oem_cert_test.cpp b/oemcrypto/ref/test/oem_cert_test.cpp new file mode 100644 index 0000000..e7e4ffc --- /dev/null +++ b/oemcrypto/ref/test/oem_cert_test.cpp @@ -0,0 +1,536 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. + +#include "oem_cert.h" + +namespace wvoec_ref { +namespace { +const uint32_t kTestOemSystemId = 7913; + +// clang-format off + +// OEM Certificate private key. +// RSA Private-Key: (2048 bit, 2 primes). +const uint8_t kTestOemPrivateKey[] = { + 0x30, 0x82, 0x04, 0xbd, 0x02, 0x01, 0x00, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x04, 0xa7, 0x30, 0x82, 0x04, 0xa3, 0x02, 0x01, + 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xa8, 0x75, + 0xd5, 0x3d, 0xd3, 0xf3, 0x59, 0xd1, 0x63, 0x0f, + 0x5d, 0x5f, 0x2c, 0xaf, 0x80, 0x4e, 0x9a, 0xef, + 0x9a, 0x8f, 0x88, 0x37, 0xe5, 0x56, 0xf8, 0x66, + 0xcb, 0xa6, 0x61, 0xab, 0xc1, 0xa9, 0x04, 0xc2, + 0x12, 0x9d, 0xa6, 0x0c, 0x2c, 0xcb, 0x42, 0x09, + 0xd0, 0x36, 0xf0, 0x85, 0x01, 0xdf, 0xd5, 0xbd, + 0xaf, 0x82, 0xbb, 0x25, 0xa1, 0x61, 0x17, 0xfe, + 0xa1, 0x65, 0x34, 0xda, 0x91, 0xee, 0x91, 0x46, + 0xd6, 0x63, 0x47, 0x6a, 0xa5, 0x32, 0x62, 0xe2, + 0x4c, 0x7c, 0xf7, 0x76, 0x59, 0xe1, 0x2b, 0x47, + 0x8d, 0x1c, 0xe6, 0xa0, 0xbd, 0xc3, 0xc9, 0x36, + 0x0e, 0x90, 0x75, 0xba, 0x1c, 0xbd, 0xca, 0x85, + 0x0a, 0x4e, 0xcc, 0xfe, 0x91, 0x3f, 0x22, 0x42, + 0x96, 0xae, 0xa0, 0x87, 0x82, 0x63, 0x3b, 0x22, + 0x54, 0xbc, 0x28, 0xa3, 0x45, 0x4b, 0x34, 0x12, + 0x4e, 0xeb, 0x04, 0x4d, 0x29, 0xb3, 0x05, 0x62, + 0x0d, 0x51, 0x16, 0x46, 0x98, 0x21, 0xc8, 0x59, + 0x96, 0x53, 0x43, 0x38, 0x95, 0x1a, 0x42, 0x94, + 0x8b, 0x49, 0x5d, 0x1b, 0x8a, 0xd5, 0x82, 0x6a, + 0x32, 0x6f, 0x0e, 0x5a, 0x85, 0x3b, 0xd5, 0x42, + 0xc0, 0x4c, 0x34, 0x43, 0x7c, 0x4f, 0xef, 0xca, + 0x02, 0x99, 0x38, 0xf9, 0xa5, 0xc0, 0xd8, 0x1d, + 0xe7, 0x9e, 0x8c, 0x4d, 0x9c, 0x40, 0xcd, 0x4b, + 0x5e, 0x44, 0x37, 0x8d, 0xc5, 0x96, 0xd4, 0xf7, + 0xb3, 0x37, 0x4c, 0x2e, 0x2d, 0x30, 0xca, 0x97, + 0x39, 0xed, 0xe8, 0x73, 0xc5, 0xe7, 0xcb, 0x95, + 0xf0, 0x84, 0x4a, 0x5a, 0x9e, 0x13, 0x19, 0x5f, + 0x98, 0xe5, 0xbe, 0x31, 0x5b, 0xff, 0xed, 0x29, + 0x26, 0xc4, 0x93, 0x54, 0x49, 0x84, 0xd2, 0xeb, + 0x21, 0x40, 0x19, 0x5f, 0xf7, 0x32, 0x67, 0x93, + 0xe0, 0xda, 0x77, 0xfc, 0xda, 0x5e, 0xc4, 0x5b, + 0x95, 0x2e, 0x46, 0xf3, 0xce, 0xfd, 0x02, 0x03, + 0x01, 0x00, 0x01, 0x02, 0x82, 0x01, 0x01, 0x00, + 0x9e, 0x6d, 0x82, 0xc8, 0x0c, 0xc6, 0xb5, 0xd7, + 0xa7, 0xb3, 0xd1, 0x7a, 0x2a, 0x8a, 0x3a, 0xbe, + 0xb2, 0x13, 0x58, 0x66, 0x58, 0x13, 0x49, 0x4a, + 0x0b, 0x7e, 0x91, 0x53, 0xbe, 0x53, 0x4b, 0x63, + 0xeb, 0x27, 0xa1, 0x5e, 0x45, 0xc4, 0xf9, 0x73, + 0x86, 0x7d, 0xb8, 0x25, 0x92, 0xf9, 0x63, 0x93, + 0xe0, 0x6d, 0xed, 0xdb, 0xa2, 0xa9, 0x77, 0x25, + 0xda, 0xed, 0x0b, 0x58, 0x24, 0xe6, 0xd1, 0x8b, + 0x6d, 0x71, 0x13, 0x3a, 0x76, 0xf5, 0xa2, 0xba, + 0xca, 0x28, 0x4d, 0x0a, 0xd1, 0xa7, 0xaa, 0x4b, + 0x8a, 0xea, 0x55, 0x99, 0xb2, 0x83, 0xc5, 0x33, + 0x95, 0xcd, 0x92, 0xd0, 0xe5, 0x06, 0xcc, 0xf4, + 0xe8, 0xbb, 0x49, 0xc0, 0x66, 0x25, 0x9a, 0xef, + 0xa7, 0x06, 0xbc, 0xb3, 0x2a, 0x21, 0x86, 0xcc, + 0x4f, 0xd6, 0xaf, 0x9d, 0xed, 0x11, 0xef, 0x9f, + 0x14, 0x2f, 0x8b, 0xac, 0x96, 0x75, 0x03, 0x1a, + 0xe4, 0x5c, 0x48, 0x81, 0x3a, 0x4b, 0x21, 0x6e, + 0xad, 0xb3, 0x27, 0x51, 0xe9, 0x35, 0xbe, 0xed, + 0x42, 0x5f, 0x8f, 0x83, 0xf0, 0x99, 0xb0, 0xaf, + 0xa9, 0x9c, 0x2f, 0xee, 0x5f, 0xee, 0x39, 0x2b, + 0x1d, 0xb0, 0xb1, 0xf8, 0x7b, 0x69, 0x38, 0x68, + 0xae, 0xa0, 0x36, 0x2a, 0xf5, 0xed, 0x96, 0xfa, + 0x7c, 0x1c, 0x59, 0x29, 0xbf, 0xb3, 0x9e, 0x14, + 0x97, 0x06, 0xc2, 0x40, 0x30, 0x00, 0x6a, 0x95, + 0xd3, 0x86, 0x86, 0xb9, 0x4c, 0xf5, 0x51, 0xa3, + 0x6d, 0x5a, 0xd1, 0x46, 0x43, 0x24, 0xa4, 0xa9, + 0x59, 0xcf, 0xa2, 0xa7, 0x4e, 0x50, 0x7a, 0xa3, + 0x14, 0xe4, 0x4e, 0x32, 0x4d, 0xd4, 0xc2, 0xcf, + 0x2d, 0x74, 0xfb, 0x51, 0x34, 0x98, 0x68, 0xc3, + 0xd2, 0xb1, 0xd9, 0x38, 0x94, 0x91, 0x28, 0xb1, + 0x69, 0x9a, 0xbf, 0xbf, 0x1a, 0xdf, 0xd3, 0xb6, + 0x21, 0x38, 0x94, 0x1b, 0x81, 0x00, 0xb5, 0x39, + 0x02, 0x81, 0x81, 0x00, 0xdb, 0xe4, 0x83, 0xc5, + 0x7a, 0xe0, 0xcf, 0xeb, 0x07, 0x37, 0xfb, 0xf6, + 0xfe, 0xb3, 0x62, 0x72, 0x86, 0xd0, 0x12, 0x96, + 0x9d, 0xf4, 0x93, 0x90, 0xdc, 0xf6, 0xc6, 0x03, + 0x0c, 0x46, 0xb8, 0x66, 0x60, 0xf3, 0x46, 0x5b, + 0xab, 0x9f, 0x9d, 0x81, 0xac, 0x26, 0x8f, 0xd7, + 0xa3, 0xbd, 0x16, 0xbb, 0xb4, 0x4e, 0xf6, 0xc0, + 0x12, 0xb6, 0x99, 0x4a, 0xf5, 0xc1, 0x6c, 0x40, + 0x72, 0x18, 0x71, 0x02, 0x65, 0x77, 0xb1, 0xfb, + 0xec, 0x19, 0xbb, 0x8c, 0x03, 0xea, 0x7b, 0x17, + 0x63, 0xc9, 0xb9, 0x3b, 0x10, 0x56, 0x19, 0xef, + 0x86, 0x69, 0x4d, 0x61, 0x03, 0xac, 0x30, 0x65, + 0x63, 0xe5, 0xe1, 0x0f, 0xd6, 0xf6, 0x5b, 0xc9, + 0x7c, 0xde, 0x9b, 0x26, 0xca, 0x98, 0xda, 0x0c, + 0x5b, 0x6f, 0x91, 0x88, 0xbf, 0x98, 0xc3, 0xbc, + 0x72, 0x21, 0xa0, 0x07, 0x0a, 0x5e, 0xc7, 0x61, + 0x4a, 0xb3, 0x32, 0xc7, 0x02, 0x81, 0x81, 0x00, + 0xc4, 0x1f, 0x4a, 0x23, 0xa6, 0x0b, 0xb9, 0xd5, + 0xc7, 0xe9, 0x1a, 0x24, 0xe8, 0x2b, 0xf2, 0x1f, + 0x17, 0xc3, 0xe6, 0x14, 0x76, 0x71, 0x11, 0x76, + 0x8f, 0xfc, 0x66, 0xb8, 0x8c, 0xe2, 0xf5, 0x46, + 0x89, 0x0d, 0xd7, 0xe3, 0x56, 0x19, 0xd7, 0x1a, + 0xfe, 0x1c, 0xd4, 0x0f, 0x8b, 0x72, 0xd1, 0x20, + 0xb0, 0xa4, 0xbe, 0x6b, 0x6b, 0x01, 0x57, 0xe8, + 0x6b, 0xdf, 0x89, 0x55, 0x3f, 0x10, 0x41, 0x63, + 0xb0, 0x62, 0xa5, 0x7f, 0x4f, 0xe7, 0x42, 0x54, + 0xe4, 0x0e, 0x55, 0xae, 0xa2, 0x53, 0x3d, 0xb8, + 0x4a, 0xff, 0xeb, 0xe2, 0x8a, 0x71, 0x17, 0x54, + 0x20, 0x05, 0x51, 0xed, 0xae, 0xb0, 0xca, 0x7e, + 0xc6, 0xd7, 0x09, 0xa8, 0x39, 0x88, 0xac, 0x7f, + 0x4b, 0xe0, 0x49, 0xd5, 0x6c, 0x89, 0xf0, 0xbc, + 0xe4, 0xe9, 0xb0, 0x29, 0x73, 0x6c, 0x55, 0x7d, + 0x8f, 0xbe, 0x32, 0x31, 0x14, 0xd2, 0xec, 0x1b, + 0x02, 0x81, 0x80, 0x67, 0xf6, 0x55, 0x5a, 0xa3, + 0xaa, 0xf0, 0x82, 0x75, 0x2a, 0x41, 0xe5, 0x58, + 0x2c, 0x65, 0xaa, 0x32, 0x14, 0xe4, 0x04, 0xf3, + 0xef, 0x33, 0x69, 0x75, 0x1e, 0xf3, 0x25, 0x73, + 0xc3, 0x67, 0xe1, 0x77, 0x8a, 0xed, 0x43, 0xe0, + 0x13, 0x99, 0xfb, 0x39, 0xf2, 0x0d, 0x65, 0xed, + 0x93, 0x33, 0xd1, 0x51, 0x01, 0x58, 0x66, 0x1d, + 0x32, 0xd9, 0xac, 0xf8, 0x1e, 0x17, 0xd9, 0x2c, + 0x58, 0x63, 0xed, 0xb7, 0x1d, 0x6d, 0x37, 0xe7, + 0x3b, 0x8f, 0x51, 0x36, 0x74, 0xc0, 0xf7, 0xa1, + 0x05, 0x39, 0x9f, 0x34, 0x2d, 0x11, 0x1c, 0x0e, + 0xd7, 0x70, 0x6f, 0x22, 0xb6, 0x61, 0x37, 0x3e, + 0x90, 0xeb, 0xe4, 0x7a, 0x44, 0x85, 0xc6, 0xf0, + 0x53, 0xaa, 0xd5, 0x1f, 0x4a, 0x3f, 0x25, 0x42, + 0x81, 0xb0, 0x34, 0x10, 0x29, 0xe0, 0xb9, 0x12, + 0xd8, 0xd4, 0xf9, 0x1f, 0x2d, 0x0a, 0x64, 0xf4, + 0x55, 0x5e, 0xf7, 0x02, 0x81, 0x80, 0x3d, 0x06, + 0x1f, 0x63, 0x88, 0x3f, 0x0d, 0xcb, 0xdf, 0x30, + 0x40, 0xda, 0x4b, 0x03, 0xa1, 0x8a, 0xdb, 0x32, + 0x31, 0x5d, 0x1c, 0x9d, 0x81, 0xf9, 0x8a, 0x43, + 0xd7, 0x12, 0x85, 0x83, 0xf9, 0x1d, 0xc1, 0x77, + 0x75, 0x3d, 0x5f, 0x85, 0x1a, 0xd1, 0x63, 0x50, + 0x45, 0x0b, 0xb1, 0x30, 0x40, 0xb2, 0x13, 0x44, + 0xaf, 0x9b, 0x6c, 0xe8, 0x36, 0x1a, 0x33, 0xb6, + 0x92, 0x5c, 0xdc, 0x0a, 0x8a, 0xce, 0x22, 0x0c, + 0x0f, 0xc2, 0xd5, 0x71, 0xf7, 0xc9, 0xc2, 0x4c, + 0x53, 0x8c, 0xcb, 0x25, 0x6b, 0x86, 0xf4, 0x8f, + 0x3d, 0x2e, 0x78, 0x35, 0x48, 0x34, 0xfc, 0xe1, + 0xaa, 0xe4, 0x71, 0xfe, 0xc0, 0x83, 0x42, 0x0b, + 0x97, 0x0d, 0xa9, 0x19, 0x45, 0xd3, 0x36, 0x20, + 0xcb, 0xd8, 0x84, 0xb5, 0x47, 0x1a, 0xff, 0x7f, + 0x57, 0x39, 0x0e, 0x99, 0x1e, 0xe0, 0xba, 0xe1, + 0x4b, 0x6c, 0xca, 0x35, 0xf7, 0x11, 0x02, 0x81, + 0x80, 0x5a, 0x59, 0xf0, 0x8e, 0x07, 0x9c, 0x1a, + 0x83, 0x2b, 0x28, 0xc4, 0x82, 0xcc, 0xb7, 0x9e, + 0x41, 0xa5, 0x15, 0xa2, 0x37, 0xa7, 0x0c, 0x77, + 0x09, 0x73, 0xf5, 0xb1, 0x3f, 0x7a, 0x55, 0x9f, + 0x15, 0x90, 0xa3, 0x5e, 0x6e, 0x19, 0x46, 0x6d, + 0x1f, 0x28, 0x64, 0xad, 0xa0, 0xb5, 0xca, 0x7d, + 0x06, 0x44, 0x88, 0xae, 0x2b, 0x80, 0x21, 0x84, + 0x3d, 0x8d, 0xa5, 0x09, 0x4f, 0xa1, 0xd9, 0x7d, + 0x7c, 0x9a, 0x8b, 0x64, 0x8f, 0xf6, 0xa5, 0xce, + 0x56, 0x65, 0xba, 0xcb, 0x30, 0x38, 0x53, 0xf8, + 0x1b, 0x89, 0x8f, 0xdf, 0xb5, 0xc3, 0x86, 0x3c, + 0x24, 0xef, 0xbc, 0xc0, 0xfc, 0x6c, 0xa4, 0xc6, + 0x74, 0xbb, 0xeb, 0x79, 0xa9, 0x8e, 0xe5, 0x25, + 0xc0, 0x0a, 0xe5, 0x90, 0x08, 0x43, 0x82, 0xec, + 0x17, 0x5e, 0x9e, 0xa2, 0x05, 0xc5, 0x03, 0x20, + 0x12, 0xf7, 0x86, 0x2e, 0x7e, 0x8e, 0x11, 0xf7, + 0x14 +}; + +const size_t kTestOemPrivateKeySize = sizeof(kTestOemPrivateKey); + +// OEM Certificate public cert data. +// Leaf (device) certificate: +// version: 2 +// serialNumber: 61412119066269531030714093834591281593 +// signature algorithm: sha256WithRSAEncryption (1.2.840.113549.1.1.11) +// issuer: +// C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine, CN=system id: 7913 +// validity: +// notBefore: Jan 27 15:55:47 2021 GMT +// notAfter: Jan 25 15:55:47 2031 GMT +// subject: +// CN=7913-leaf, C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine +// key: RSA Public key +// extensions: +// - object: Widevine System Id (1.3.6.1.4.1.11129.4.1.1) +// critical: BOOL ABSENT +// value: 02 02 1e e9 (7913) +// sig_alg: sha256WithRSAEncryption (1.2.840.113549.1.1.11) +// signature: ... +// +// Intermediate (manufacturer) certificate: +// version: 2 +// serialNumber: 4911737327617104025470773024969385060 +// signature: sha256WithRSAEncryption (1.2.840.113549.1.1.11) +// issuer: +// C=US, ST=Washington, L=Kirkland, O=Google, OU=Widevine, +// CN=widevine.com/oem-root-prod +// validity: +// notBefore: Nov 18 01:13:35 2017 GMT +// notAfter: Nov 18 01:13:13 2027 GMT +// subject: +// C=US, ST=WA, L=Kirkland, O=Google, OU=Widevine, CN=system id: 7913 +// key: RSA Public key +// extensions: +// - object: X509v3 Basic Constraints (2.5.29.19) +// critical: TRUE +// value: 30 06 01 01 ff 02 01 00 +// - object: X509v3 Key Usage (2.5.29.15) +// critical: TRUE +// value: 03 02 02 04 +// - object: X509v3 Subject Key Identifier (2.5.29.14) +// critical: BOOL ABSENT +// value: +// 04 14 4b cb df aa 02 de 8d c3 e7 e5 85 db 2e 8a be 75 6b 8a 67-58 +// - object: X509v3 Authority Key Identifier (2.5.29.35) +// critical: BOOL ABSENT +// value: ... +// - object: Widevine System Id (1.3.6.1.4.1.11129.4.1.1) +// critical: BOOL ABSENT +// value: 02 02 1e e9 (7913) +// sig_alg: sha256WithRSAEncryption (1.2.840.113549.1.1.11) +// signature: ... +const uint8_t kTestOemPublicCert[] = { + 0x30, 0x82, 0x09, 0x28, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, + 0x82, 0x09, 0x19, 0x30, 0x82, 0x09, 0x15, 0x02, + 0x01, 0x01, 0x31, 0x00, 0x30, 0x0b, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01, 0xa0, 0x82, 0x08, 0xfd, 0x30, 0x82, 0x03, + 0x70, 0x30, 0x82, 0x02, 0x58, 0xa0, 0x03, 0x02, + 0x01, 0x02, 0x02, 0x10, 0x2e, 0x33, 0x8b, 0x3d, + 0x69, 0x18, 0x4c, 0xf7, 0x78, 0x2e, 0x3b, 0x3b, + 0x43, 0xb4, 0x21, 0xb9, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x0b, 0x05, 0x00, 0x30, 0x6b, 0x31, 0x0b, 0x30, + 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, 0x61, + 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, 0x69, + 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, + 0x0f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, + 0x69, 0x64, 0x3a, 0x20, 0x37, 0x39, 0x31, 0x33, + 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x31, 0x30, 0x31, + 0x32, 0x37, 0x31, 0x35, 0x35, 0x35, 0x34, 0x37, + 0x5a, 0x17, 0x0d, 0x33, 0x31, 0x30, 0x31, 0x32, + 0x35, 0x31, 0x35, 0x35, 0x35, 0x34, 0x37, 0x5a, + 0x30, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x09, 0x37, 0x39, 0x31, + 0x33, 0x2d, 0x6c, 0x65, 0x61, 0x66, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x0c, 0x02, 0x57, 0x41, + 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x08, 0x4b, 0x69, 0x72, 0x6b, 0x6c, + 0x61, 0x6e, 0x64, 0x31, 0x0f, 0x30, 0x0d, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x06, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, + 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x57, + 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, 0x30, + 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, + 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, + 0xa8, 0x75, 0xd5, 0x3d, 0xd3, 0xf3, 0x59, 0xd1, + 0x63, 0x0f, 0x5d, 0x5f, 0x2c, 0xaf, 0x80, 0x4e, + 0x9a, 0xef, 0x9a, 0x8f, 0x88, 0x37, 0xe5, 0x56, + 0xf8, 0x66, 0xcb, 0xa6, 0x61, 0xab, 0xc1, 0xa9, + 0x04, 0xc2, 0x12, 0x9d, 0xa6, 0x0c, 0x2c, 0xcb, + 0x42, 0x09, 0xd0, 0x36, 0xf0, 0x85, 0x01, 0xdf, + 0xd5, 0xbd, 0xaf, 0x82, 0xbb, 0x25, 0xa1, 0x61, + 0x17, 0xfe, 0xa1, 0x65, 0x34, 0xda, 0x91, 0xee, + 0x91, 0x46, 0xd6, 0x63, 0x47, 0x6a, 0xa5, 0x32, + 0x62, 0xe2, 0x4c, 0x7c, 0xf7, 0x76, 0x59, 0xe1, + 0x2b, 0x47, 0x8d, 0x1c, 0xe6, 0xa0, 0xbd, 0xc3, + 0xc9, 0x36, 0x0e, 0x90, 0x75, 0xba, 0x1c, 0xbd, + 0xca, 0x85, 0x0a, 0x4e, 0xcc, 0xfe, 0x91, 0x3f, + 0x22, 0x42, 0x96, 0xae, 0xa0, 0x87, 0x82, 0x63, + 0x3b, 0x22, 0x54, 0xbc, 0x28, 0xa3, 0x45, 0x4b, + 0x34, 0x12, 0x4e, 0xeb, 0x04, 0x4d, 0x29, 0xb3, + 0x05, 0x62, 0x0d, 0x51, 0x16, 0x46, 0x98, 0x21, + 0xc8, 0x59, 0x96, 0x53, 0x43, 0x38, 0x95, 0x1a, + 0x42, 0x94, 0x8b, 0x49, 0x5d, 0x1b, 0x8a, 0xd5, + 0x82, 0x6a, 0x32, 0x6f, 0x0e, 0x5a, 0x85, 0x3b, + 0xd5, 0x42, 0xc0, 0x4c, 0x34, 0x43, 0x7c, 0x4f, + 0xef, 0xca, 0x02, 0x99, 0x38, 0xf9, 0xa5, 0xc0, + 0xd8, 0x1d, 0xe7, 0x9e, 0x8c, 0x4d, 0x9c, 0x40, + 0xcd, 0x4b, 0x5e, 0x44, 0x37, 0x8d, 0xc5, 0x96, + 0xd4, 0xf7, 0xb3, 0x37, 0x4c, 0x2e, 0x2d, 0x30, + 0xca, 0x97, 0x39, 0xed, 0xe8, 0x73, 0xc5, 0xe7, + 0xcb, 0x95, 0xf0, 0x84, 0x4a, 0x5a, 0x9e, 0x13, + 0x19, 0x5f, 0x98, 0xe5, 0xbe, 0x31, 0x5b, 0xff, + 0xed, 0x29, 0x26, 0xc4, 0x93, 0x54, 0x49, 0x84, + 0xd2, 0xeb, 0x21, 0x40, 0x19, 0x5f, 0xf7, 0x32, + 0x67, 0x93, 0xe0, 0xda, 0x77, 0xfc, 0xda, 0x5e, + 0xc4, 0x5b, 0x95, 0x2e, 0x46, 0xf3, 0xce, 0xfd, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x16, 0x30, + 0x14, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, 0x01, + 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, 0x04, + 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, + 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, + 0x00, 0x04, 0x9e, 0xbb, 0x41, 0x3e, 0x1b, 0x35, + 0xca, 0x24, 0xe3, 0xa7, 0x62, 0xf7, 0xbf, 0x54, + 0x88, 0x1d, 0xa3, 0x6c, 0x30, 0x1f, 0xb7, 0xe4, + 0x2b, 0x76, 0x54, 0x4f, 0xb1, 0x30, 0xba, 0x86, + 0x21, 0x12, 0xc3, 0xd9, 0x25, 0xfd, 0x94, 0xab, + 0x3c, 0x9d, 0x4d, 0xbc, 0x2b, 0xdc, 0x68, 0x01, + 0x8d, 0x59, 0x4f, 0x81, 0xe8, 0x87, 0xbe, 0x05, + 0x75, 0x3e, 0x24, 0xd9, 0xf1, 0x55, 0xe3, 0x56, + 0x75, 0xa4, 0x7f, 0xb4, 0x50, 0x41, 0x4b, 0x88, + 0x0e, 0x8f, 0x6e, 0x10, 0x13, 0x25, 0x24, 0xda, + 0x4c, 0x97, 0x0a, 0xdc, 0xbf, 0x2a, 0x1d, 0x4d, + 0x02, 0xb3, 0x4b, 0x6a, 0x96, 0xe6, 0x0e, 0xd1, + 0x61, 0x80, 0x78, 0xab, 0xf0, 0x7b, 0x8b, 0x1e, + 0x99, 0x48, 0x84, 0x31, 0xd2, 0xaf, 0x23, 0x32, + 0x01, 0x5e, 0x11, 0x55, 0x06, 0x6e, 0x0e, 0xed, + 0x69, 0x7b, 0xb8, 0x41, 0x63, 0x3b, 0x30, 0x05, + 0x1e, 0xcd, 0x3e, 0x49, 0xb8, 0x0c, 0x83, 0x50, + 0x26, 0x4e, 0xd8, 0x97, 0x9d, 0x89, 0x30, 0x15, + 0xb9, 0x20, 0x20, 0xba, 0x5d, 0x8b, 0xad, 0x3d, + 0x7f, 0x52, 0xcd, 0x1e, 0xc0, 0x0e, 0xe1, 0xdc, + 0x21, 0x9b, 0xb0, 0x89, 0xa0, 0x20, 0xc6, 0x8c, + 0x56, 0x39, 0xc3, 0x40, 0x30, 0x40, 0x52, 0x2f, + 0x3b, 0x87, 0x96, 0xe2, 0x4d, 0x80, 0x57, 0xb3, + 0xb3, 0xe0, 0xb7, 0x5c, 0x55, 0x6a, 0x0f, 0x44, + 0x91, 0xe8, 0x98, 0xb3, 0xb4, 0xd3, 0x07, 0x8e, + 0x85, 0x8e, 0xc0, 0xcb, 0x85, 0x92, 0x0e, 0xca, + 0x7c, 0x03, 0x23, 0xa0, 0x1f, 0x4e, 0x75, 0x01, + 0x95, 0x61, 0x2c, 0x21, 0x2f, 0x4f, 0x6d, 0x55, + 0xa3, 0xcc, 0x23, 0x62, 0x7f, 0xcb, 0x0a, 0x8a, + 0x8b, 0x82, 0xb5, 0x8c, 0x8a, 0xaa, 0x88, 0xb4, + 0x65, 0x82, 0x6d, 0x12, 0x4a, 0x06, 0xe7, 0xde, + 0xcd, 0x3c, 0xf9, 0x1c, 0x02, 0x9c, 0xf8, 0x21, + 0x20, 0x30, 0x82, 0x05, 0x85, 0x30, 0x82, 0x03, + 0x6d, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, + 0x03, 0xb1, 0xf7, 0x58, 0xdf, 0x1d, 0xe3, 0x25, + 0x00, 0x0b, 0x10, 0x3d, 0xd5, 0xe6, 0xe4, 0x64, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, + 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, + 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, + 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, + 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, + 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, + 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, + 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, + 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x30, + 0x1e, 0x17, 0x0d, 0x31, 0x37, 0x31, 0x31, 0x31, + 0x38, 0x30, 0x31, 0x31, 0x33, 0x33, 0x35, 0x5a, + 0x17, 0x0d, 0x32, 0x37, 0x31, 0x31, 0x31, 0x38, + 0x30, 0x31, 0x31, 0x33, 0x31, 0x33, 0x5a, 0x30, + 0x6b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x02, 0x57, 0x41, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, + 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, + 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, + 0x6e, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x0f, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x20, 0x69, 0x64, 0x3a, 0x20, + 0x37, 0x39, 0x31, 0x33, 0x30, 0x82, 0x01, 0x22, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, + 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, + 0x02, 0x82, 0x01, 0x01, 0x00, 0xae, 0xc8, 0x71, + 0xae, 0x08, 0x0c, 0x06, 0x06, 0x2d, 0x81, 0x7c, + 0xa9, 0x8b, 0xb3, 0xd6, 0x66, 0xe4, 0xf6, 0x08, + 0x5e, 0x5a, 0x75, 0xe8, 0x74, 0x61, 0x7a, 0x88, + 0xca, 0x85, 0x14, 0x0d, 0x58, 0xa4, 0x09, 0x19, + 0x6c, 0x60, 0xc9, 0xad, 0x91, 0x1c, 0xbf, 0x04, + 0xb3, 0x47, 0x10, 0x63, 0x7f, 0x02, 0x58, 0xc2, + 0x1e, 0xbd, 0xcc, 0x07, 0x77, 0xaa, 0x7e, 0x14, + 0xa8, 0xc2, 0x01, 0xcd, 0xe8, 0x46, 0x60, 0x53, + 0x6f, 0x2f, 0xda, 0x17, 0x2d, 0x4d, 0x9d, 0x0e, + 0x5d, 0xb5, 0x50, 0x95, 0xae, 0xab, 0x6e, 0x43, + 0xe3, 0xb0, 0x00, 0x12, 0xb4, 0x05, 0x82, 0x4a, + 0x2b, 0x14, 0x63, 0x0d, 0x1f, 0x06, 0x12, 0xaa, + 0xe1, 0x9d, 0xe7, 0xba, 0xda, 0xe3, 0xfc, 0x7c, + 0x6c, 0x73, 0xae, 0x56, 0xf8, 0xab, 0xf7, 0x51, + 0x93, 0x31, 0xef, 0x8f, 0xe4, 0xb6, 0x01, 0x2c, + 0xeb, 0x7b, 0xe4, 0xd8, 0xb3, 0xea, 0x70, 0x37, + 0x89, 0x05, 0xa9, 0x51, 0x57, 0x72, 0x98, 0x9e, + 0xa8, 0x46, 0xdb, 0xeb, 0x7a, 0x38, 0x2b, 0x2f, + 0xc0, 0x27, 0xb7, 0xc2, 0xe1, 0x9a, 0x17, 0xdf, + 0xf5, 0xd6, 0x9c, 0xd5, 0x8c, 0xb8, 0x66, 0x42, + 0xd5, 0x04, 0x1e, 0x7c, 0x36, 0x4c, 0x1e, 0x3e, + 0x45, 0x51, 0x4d, 0x41, 0x72, 0x22, 0x53, 0x3d, + 0xf4, 0x57, 0x7c, 0x6c, 0x33, 0x34, 0x24, 0x45, + 0xdf, 0x84, 0x87, 0x4a, 0xa6, 0xcb, 0x7c, 0x03, + 0xa3, 0xaa, 0x8e, 0x2d, 0x82, 0x01, 0x27, 0x87, + 0x74, 0x82, 0x1a, 0xbc, 0x0f, 0x76, 0x69, 0xab, + 0xe0, 0x4e, 0x70, 0xbe, 0x37, 0xfc, 0xc8, 0x2c, + 0x91, 0x17, 0x4f, 0xd5, 0x26, 0x3b, 0x7b, 0x90, + 0xb5, 0x2d, 0x64, 0xba, 0xf7, 0xd2, 0x8a, 0xb4, + 0x8f, 0x38, 0x9d, 0x8e, 0xba, 0xe7, 0x5c, 0x52, + 0xf1, 0x0a, 0xb8, 0xc0, 0x1b, 0xb6, 0xb1, 0x70, + 0x7e, 0x47, 0x59, 0x94, 0x59, 0x02, 0x03, 0x01, + 0x00, 0x01, 0xa3, 0x82, 0x01, 0x10, 0x30, 0x82, + 0x01, 0x0c, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, + 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, + 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, + 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, + 0x04, 0x04, 0x03, 0x02, 0x02, 0x04, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, + 0x14, 0x4b, 0xcb, 0xdf, 0xaa, 0x02, 0xde, 0x8d, + 0xc3, 0xe7, 0xe5, 0x85, 0xdb, 0x2e, 0x8a, 0xbe, + 0x75, 0x6b, 0x8a, 0x67, 0x58, 0x30, 0x81, 0xb2, + 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xaa, + 0x30, 0x81, 0xa7, 0x80, 0x14, 0x04, 0x94, 0x66, + 0xaa, 0xf9, 0x61, 0x89, 0xb6, 0xdb, 0xb5, 0xf7, + 0x13, 0x38, 0x3d, 0x62, 0x84, 0xb8, 0x18, 0x0a, + 0x8f, 0xa1, 0x81, 0x83, 0xa4, 0x81, 0x80, 0x30, + 0x7e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, + 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, + 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, + 0x74, 0x6f, 0x6e, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x07, 0x0c, 0x08, 0x4b, 0x69, + 0x72, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x0f, + 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, + 0x06, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x0c, 0x08, 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, + 0x6e, 0x65, 0x31, 0x23, 0x30, 0x21, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x1a, 0x77, 0x69, 0x64, + 0x65, 0x76, 0x69, 0x6e, 0x65, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x6f, 0x65, 0x6d, 0x2d, 0x72, 0x6f, + 0x6f, 0x74, 0x2d, 0x70, 0x72, 0x6f, 0x64, 0x82, + 0x09, 0x00, 0xdf, 0x86, 0x05, 0x31, 0x01, 0xbe, + 0x9a, 0x9a, 0x30, 0x12, 0x06, 0x0a, 0x2b, 0x06, + 0x01, 0x04, 0x01, 0xd6, 0x79, 0x04, 0x01, 0x01, + 0x04, 0x04, 0x02, 0x02, 0x1e, 0xe9, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x02, + 0x01, 0x00, 0x61, 0x3f, 0x2f, 0x43, 0xe4, 0xbe, + 0x66, 0x34, 0xef, 0x92, 0x06, 0xe9, 0x88, 0xba, + 0x6a, 0x1d, 0x4f, 0x54, 0x5a, 0x97, 0xb1, 0x75, + 0xd7, 0x93, 0xf8, 0x45, 0xc6, 0x83, 0x92, 0x36, + 0xfd, 0x55, 0xa9, 0x21, 0x0b, 0xdc, 0xf6, 0xae, + 0x11, 0xdc, 0x62, 0x21, 0x44, 0xbd, 0x04, 0x1d, + 0x58, 0x2c, 0x03, 0xf8, 0xe4, 0xe2, 0x1e, 0xba, + 0xe6, 0xdd, 0x19, 0xdd, 0x56, 0xfd, 0xce, 0x06, + 0x73, 0x5f, 0x94, 0x1e, 0xb6, 0x03, 0xdb, 0x3d, + 0x7b, 0xab, 0xab, 0x72, 0x64, 0x7b, 0xde, 0x7d, + 0x4d, 0xcf, 0x7e, 0xf0, 0x91, 0x29, 0xc1, 0x77, + 0x13, 0xc2, 0x6f, 0x80, 0xab, 0x7a, 0xa8, 0xce, + 0xb0, 0x1c, 0x2a, 0xc5, 0x9c, 0xfb, 0x0b, 0xe5, + 0x9f, 0x9c, 0x1b, 0xc9, 0x4b, 0x58, 0xdf, 0x96, + 0x18, 0xf7, 0x67, 0x67, 0x89, 0xa4, 0xe9, 0x14, + 0x48, 0xac, 0xfa, 0x9d, 0x86, 0x2a, 0xeb, 0x75, + 0x2c, 0x2b, 0xbf, 0x63, 0x7d, 0xc7, 0x4e, 0x7e, + 0xad, 0x39, 0x2d, 0xb4, 0x7c, 0x07, 0xa5, 0x5a, + 0xe8, 0x3a, 0xd4, 0xf5, 0x0c, 0x4f, 0xf3, 0xa2, + 0x9c, 0x3c, 0x32, 0xed, 0x9d, 0x4b, 0x49, 0x05, + 0xbc, 0x1f, 0xa0, 0x13, 0xe6, 0xdd, 0x82, 0x79, + 0x06, 0x31, 0x3b, 0xc6, 0x97, 0xec, 0x8d, 0xaa, + 0x4f, 0xef, 0x14, 0x3c, 0x21, 0xf6, 0x72, 0xb2, + 0x09, 0x42, 0xc7, 0x74, 0xfe, 0xef, 0x70, 0xbd, + 0xe9, 0x85, 0x41, 0x30, 0x0b, 0xb3, 0x6b, 0x59, + 0x0c, 0x0f, 0x11, 0x75, 0xd4, 0xbb, 0xb1, 0xdf, + 0xb1, 0xdf, 0xb3, 0xfa, 0xb3, 0x3a, 0x43, 0x17, + 0x7d, 0x8a, 0x82, 0xae, 0xa2, 0x07, 0xf8, 0x83, + 0x51, 0xfb, 0x16, 0xfb, 0x64, 0xb6, 0x46, 0xda, + 0xbe, 0x32, 0x2b, 0xc0, 0xee, 0x78, 0x2a, 0x84, + 0xa9, 0x54, 0x0a, 0xf9, 0x2d, 0x61, 0x65, 0xde, + 0xa5, 0x97, 0x66, 0x79, 0x02, 0xf8, 0x97, 0x17, + 0xe2, 0xd4, 0x9f, 0x9e, 0xac, 0xcc, 0xae, 0x99, + 0x9a, 0x03, 0x04, 0xbb, 0x45, 0xfe, 0xb2, 0xf5, + 0x80, 0xba, 0xbf, 0xdd, 0x24, 0xe5, 0xe6, 0x1e, + 0x5d, 0x36, 0xa5, 0x87, 0x0c, 0xdf, 0x60, 0x81, + 0x6f, 0xb7, 0x5f, 0xb9, 0x1f, 0xca, 0x75, 0x3c, + 0x1a, 0x63, 0xb0, 0xeb, 0xe6, 0x95, 0x86, 0x0d, + 0xae, 0xa6, 0xc9, 0x2a, 0x94, 0xf1, 0xd0, 0xbe, + 0x75, 0xc8, 0xf8, 0x07, 0xd7, 0x88, 0xff, 0xec, + 0xf9, 0xcd, 0x49, 0xc6, 0xfe, 0x4d, 0x7f, 0x44, + 0x1e, 0xd8, 0xaf, 0xa9, 0x72, 0x27, 0x98, 0xe2, + 0x5a, 0x08, 0xea, 0x55, 0xd3, 0xb3, 0xea, 0xdc, + 0x76, 0x69, 0x51, 0x10, 0x01, 0x46, 0x7d, 0x33, + 0x94, 0x9c, 0x94, 0xef, 0xfe, 0x76, 0x1c, 0xc6, + 0xd7, 0x15, 0x53, 0x3e, 0x8d, 0x3d, 0x29, 0x9a, + 0x58, 0x6a, 0xf1, 0x75, 0x9e, 0xea, 0x1b, 0x4c, + 0xf0, 0x47, 0x76, 0xac, 0xc6, 0xa2, 0x32, 0x44, + 0x40, 0xdf, 0xfe, 0xff, 0x9d, 0xf4, 0xe2, 0xc2, + 0xfa, 0xa1, 0x5f, 0x2e, 0x66, 0xe9, 0x97, 0xcb, + 0x27, 0x26, 0x6e, 0x53, 0xe4, 0xe8, 0x86, 0x2c, + 0xea, 0xd3, 0x69, 0x6c, 0x61, 0x4f, 0xfe, 0xc1, + 0xc9, 0x8b, 0x05, 0x92, 0x6f, 0x47, 0x96, 0xce, + 0xf0, 0x33, 0xfa, 0x7c, 0x78, 0x24, 0x9b, 0xd7, + 0x8d, 0x36, 0x56, 0x37, 0x86, 0xbc, 0x72, 0x5a, + 0xf9, 0xb9, 0xb0, 0x93, 0xf0, 0x81, 0x78, 0x10, + 0xf2, 0xb0, 0xc2, 0x79, 0x91, 0x5e, 0xcf, 0xbc, + 0x8c, 0xf2, 0x32, 0x0f, 0xf7, 0x2d, 0x30, 0xd8, + 0x13, 0x77, 0x4f, 0x78, 0x9e, 0x40, 0x8d, 0xe6, + 0x3a, 0x98, 0xb2, 0xaa, 0x13, 0x4d, 0x25, 0x49, + 0x34, 0x6c, 0x80, 0x9e, 0x19, 0x03, 0xdb, 0xcd, + 0xf5, 0xb1, 0x54, 0x74, 0x1b, 0x67, 0x3c, 0x46, + 0xac, 0x3e, 0x5d, 0xa2, 0xd9, 0x13, 0x83, 0x30, + 0xeb, 0x82, 0x3b, 0x06, 0xab, 0x3c, 0x39, 0x7d, + 0xd0, 0x68, 0x31, 0x00 +}; + +// clang-format on + +} // namespace + +const size_t kTestOemPublicCertSize = sizeof(kTestOemPublicCert); + +const uint32_t kOEMSystemId = kTestOemSystemId; + +const uint8_t* kOEMPrivateKey = kTestOemPrivateKey; +const uint8_t* kOEMPublicCert = kTestOemPublicCert; + +const size_t kOEMPrivateKeySize = kTestOemPrivateKeySize; +const size_t kOEMPublicCertSize = kTestOemPublicCertSize; + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/test/oemcrypto_ecc_key_unittest.cpp b/oemcrypto/ref/test/oemcrypto_ecc_key_unittest.cpp new file mode 100644 index 0000000..e5dd5c7 --- /dev/null +++ b/oemcrypto/ref/test/oemcrypto_ecc_key_unittest.cpp @@ -0,0 +1,232 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include + +#include "OEMCryptoCENCCommon.h" +#include "oemcrypto_ecc_key.h" +#include "oemcrypto_ref_test_utils.h" + +namespace wvoec_ref { +constexpr size_t kMessageSize = 4 * 1024; // 4 kB + +class OEMCryptoEccKeyTest : public ::testing::TestWithParam { + public: + void SetUp() override { key_ = EccPrivateKey::New(GetParam()); } + + void TearDown() override { key_.reset(); } + + protected: + std::unique_ptr key_; +}; + +// Basic verification of ECC private key generation. +TEST_P(OEMCryptoEccKeyTest, KeyProperties) { + ASSERT_TRUE(key_); + const EccCurve expected_curve = GetParam(); + + EXPECT_EQ(key_->curve(), expected_curve); + EXPECT_NE(nullptr, key_->GetEcKey()); +} + +// Checks that the private key serialization APIs are compatible +// and performing in a manner that is similar to other OEMCrypto methods +// that retrieve data. +TEST_P(OEMCryptoEccKeyTest, SerializePrivateKey) { + ASSERT_TRUE(key_); + + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t buffer_size = kInitialBufferSize; + std::vector buffer(buffer_size); + + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + key_->Serialize(buffer.data(), &buffer_size)); + EXPECT_GT(buffer_size, kInitialBufferSize); + + buffer.resize(buffer_size); + EXPECT_EQ(OEMCrypto_SUCCESS, key_->Serialize(buffer.data(), &buffer_size)); + buffer.resize(buffer_size); + + const std::vector direct_key_data = key_->Serialize(); + EXPECT_FALSE(direct_key_data.empty()); + ASSERT_EQ(buffer.size(), direct_key_data.size()); + for (size_t i = 0; i < buffer.size(); i++) { + ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << i; + } +} + +// Checks that a private key that is serialized can be deserialized and +// reload. Also checks that the serialization of a key produces the +// same data to ensure consistency. +TEST_P(OEMCryptoEccKeyTest, SerializeAndReloadPrivateKey) { + ASSERT_TRUE(key_); + + const std::vector key_data = key_->Serialize(); + std::unique_ptr loaded_key = EccPrivateKey::Load(key_data); + ASSERT_TRUE(loaded_key); + + EXPECT_EQ(key_->curve(), loaded_key->curve()); + + const std::vector loaded_key_data = loaded_key->Serialize(); + ASSERT_EQ(key_data.size(), loaded_key_data.size()); + for (size_t i = 0; i < key_data.size(); i++) { + ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << i; + } +} + +// Checks that a public key can be created from the private key. +TEST_P(OEMCryptoEccKeyTest, DerivePublicKey) { + ASSERT_TRUE(key_); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + EXPECT_TRUE(key_->IsMatchingPublicKey(*pub_key)); +} + +// Checks that a public key that is serialized can be deserialized and +// reload. Also checks that the serialization of a key produces the +// same data to ensure consistency. +TEST_P(OEMCryptoEccKeyTest, SerializePublicKey) { + ASSERT_TRUE(key_); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t buffer_size = kInitialBufferSize; + std::vector buffer(buffer_size); + + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + pub_key->Serialize(buffer.data(), &buffer_size)); + EXPECT_GT(buffer_size, kInitialBufferSize); + + buffer.resize(buffer_size); + EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->Serialize(buffer.data(), &buffer_size)); + buffer.resize(buffer_size); + + const std::vector direct_key_data = pub_key->Serialize(); + EXPECT_FALSE(direct_key_data.empty()); + ASSERT_EQ(buffer.size(), direct_key_data.size()); + for (size_t i = 0; i < buffer.size(); i++) { + ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << i; + } +} + +// Checks that a public key that is serialized can be deserialized and +// reload. Also checks that the serialization of a key produces the +// same data to ensure consistency. +// It is anticipated that OEMCrypto will need to parse the licensing +// server's ephemerial key when deriving the session key. +TEST_P(OEMCryptoEccKeyTest, SerializeAndReloadPublicKey) { + ASSERT_TRUE(key_); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + const std::vector key_data = pub_key->Serialize(); + + std::unique_ptr loaded_key = EccPublicKey::Load(key_data); + ASSERT_TRUE(loaded_key); + + EXPECT_EQ(pub_key->curve(), loaded_key->curve()); + + const std::vector loaded_key_data = loaded_key->Serialize(); + ASSERT_EQ(key_data.size(), loaded_key_data.size()); + for (size_t i = 0; i < key_data.size(); i++) { + ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << i; + } +} + +// Checks that the ECC signature generating API operates similar to +// existing signature generation functions. +TEST_P(OEMCryptoEccKeyTest, GenerateSignature) { + ASSERT_TRUE(key_); + + const std::vector message = RandomData(kMessageSize); + ASSERT_FALSE(message.empty()) << "CdmRandom failed"; + + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t signature_size = kInitialBufferSize; + std::vector signature(signature_size); + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + key_->GenerateSignature(message.data(), message.size(), + signature.data(), &signature_size)); + EXPECT_GT(signature_size, kInitialBufferSize); + + signature.resize(signature_size); + EXPECT_EQ(OEMCrypto_SUCCESS, + key_->GenerateSignature(message.data(), message.size(), + signature.data(), &signature_size)); + signature.resize(signature_size); + + EXPECT_LE(signature_size, key_->SignatureSize()); +} + +// Checks that ECC signatures can be verified by an ECC public key. +TEST_P(OEMCryptoEccKeyTest, VerifySignature) { + ASSERT_TRUE(key_); + const std::vector message = RandomData(kMessageSize); + ASSERT_FALSE(message.empty()) << "CdmRandom failed"; + + const std::vector signature = key_->GenerateSignature(message); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->VerifySignature(message, signature)); + + // Check with different message. + const std::vector message_two = RandomData(kMessageSize); + EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, + pub_key->VerifySignature(message_two, signature)); + + // Check with bad signature. + const std::vector bad_signature = RandomData(signature.size()); + EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, + pub_key->VerifySignature(message, bad_signature)); +} + +// Verifies the session key exchange protocol used by the licensing +// server. +TEST_P(OEMCryptoEccKeyTest, DeriveSessionKey) { + ASSERT_TRUE(key_); + // Set up Alice. + EccPrivateKey* alice_private_key = key_.get(); + std::unique_ptr alice_public_key = + alice_private_key->MakePublicKey(); + ASSERT_TRUE(alice_public_key); + // Set up Bob. + std::unique_ptr bob_private_key = + EccPrivateKey::New(alice_private_key->curve()); + ASSERT_TRUE(bob_private_key); + std::unique_ptr bob_public_key = + bob_private_key->MakePublicKey(); + ASSERT_TRUE(bob_public_key); + + const size_t session_key_length = alice_private_key->SessionKeyLength(); + EXPECT_EQ(session_key_length, bob_private_key->SessionKeyLength()); + // From Alice's perspective. + const std::vector alice_session_key = + alice_private_key->DeriveSessionKey(*bob_public_key); + + // From Bob's perspective. + const std::vector bob_session_key = + bob_private_key->DeriveSessionKey(*alice_public_key); + + // Both should have the same session key. + ASSERT_EQ(session_key_length, alice_session_key.size()); + ASSERT_EQ(session_key_length, bob_session_key.size()); + for (size_t i = 0; i < session_key_length; i++) { + ASSERT_EQ(alice_session_key[i], bob_session_key[i]) << "i = " << i; + } +} + +INSTANTIATE_TEST_SUITE_P(AllCurves, OEMCryptoEccKeyTest, + ::testing::Values(kEccSecp256r1, kEccSecp384r1, + kEccSecp521r1)); + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/test/oemcrypto_oem_cert_unittest.cpp b/oemcrypto/ref/test/oemcrypto_oem_cert_unittest.cpp new file mode 100644 index 0000000..6afa51d --- /dev/null +++ b/oemcrypto/ref/test/oemcrypto_oem_cert_unittest.cpp @@ -0,0 +1,115 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include + +#include "OEMCryptoCENCCommon.h" +#include "oem_cert.h" +#include "oemcrypto_oem_cert.h" +#include "oemcrypto_rsa_key.h" + +namespace wvoec_ref { +namespace { +const std::vector kOEMPrivateKeyVector(kOEMPrivateKey, + kOEMPrivateKey + + kOEMPrivateKeySize); + +const std::vector kOEMPublicCertVector(kOEMPublicCert, + kOEMPublicCert + + kOEMPublicCertSize); +} // namespace + +// Creates an OemCertificate wrapper around the built-in reference +// OEM cert. +// Creating the OemCertificate should succeed so long as the data +// is well-formed. +// Validating the OEM cert should succeed (assuming built-in cert+key +// are valid). +TEST(OEMCryptoOemCertTest, CreateFromArray) { + std::unique_ptr oem_cert = OemCertificate::Create( + kOEMPrivateKey, kOEMPrivateKeySize, kOEMPublicCert, kOEMPublicCertSize); + ASSERT_TRUE(oem_cert); + + EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type()); + + const std::vector private_key = oem_cert->GetPrivateKey(); + EXPECT_EQ(kOEMPrivateKeyVector, private_key); + + size_t public_cert_size = 10; + std::vector public_cert(public_cert_size, 0); + EXPECT_EQ( + OEMCrypto_ERROR_SHORT_BUFFER, + oem_cert->GetPublicCertificate(public_cert.data(), &public_cert_size)); + public_cert.resize(public_cert_size); + EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->GetPublicCertificate( + public_cert.data(), &public_cert_size)); + EXPECT_EQ(kOEMPublicCertSize, public_cert_size); + EXPECT_EQ(kOEMPublicCertVector, public_cert); + + EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->IsCertificateValid()); +} + +TEST(OEMCryptoOemCertTest, CreateFromVector) { + std::unique_ptr oem_cert = + OemCertificate::Create(kOEMPrivateKeyVector, kOEMPublicCertVector); + ASSERT_TRUE(oem_cert); + + EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type()); + + const std::vector private_key = oem_cert->GetPrivateKey(); + EXPECT_EQ(kOEMPrivateKeyVector, private_key); + + const std::vector public_cert = oem_cert->GetPublicCertificate(); + EXPECT_EQ(kOEMPublicCertVector, public_cert); + + EXPECT_EQ(OEMCrypto_SUCCESS, oem_cert->IsCertificateValid()); +} + +// Creation of OemCertificate wrapper should fail if the provided +// key is not well-formed. +TEST(OEMCryptoOemCertTest, CreateWithABadPrivateKey) { + static const uint8_t kBadPrivateKeyData[] = {'n', 'o', 't', ' ', 'a', ' ', + 'p', 'r', 'i', 'v', 'a', 't', + 'e', 'k', 'e', 'y'}; + std::unique_ptr oem_cert = + OemCertificate::Create(kBadPrivateKeyData, sizeof(kBadPrivateKeyData), + kOEMPublicCert, kOEMPublicCertSize); + EXPECT_FALSE(oem_cert); +} + +// Creation of OemCertificate wrapper should fail if the provided +// OEM Public Cert is not well-formed. +TEST(OEMCryptoOemCertTest, CreateWithABadPublicCert) { + static const uint8_t kBadPublicCert[] = {'n', 'o', 't', ' ', 'a', ' ', 'o', + 'e', 'm', ' ', 'p', 'u', 'b', 'l', + 'i', 'c', ' ', 'c', 'e', 'r', 't'}; + std::unique_ptr oem_cert = + OemCertificate::Create(kOEMPrivateKey, kOEMPrivateKeySize, kBadPublicCert, + sizeof(kBadPublicCert)); + EXPECT_FALSE(oem_cert); +} + +// It is possible to create an OEM Certificate using a non-matching +// public-private key pair so long as the key types are the same. +// However, OEM Cert validation should catch the problem. +TEST(OEMCryptoOemCertTest, CreateWithDifferentPrivateRsaKey) { + std::unique_ptr key = RsaPrivateKey::New(kRsa2048Bit); + ASSERT_TRUE(key); + const std::vector private_key = key->Serialize(); + ASSERT_FALSE(private_key.empty()); + + // Creating the OEM Certificate should succeed. + std::unique_ptr oem_cert = + OemCertificate::Create(private_key, kOEMPublicCertVector); + ASSERT_TRUE(oem_cert); + + EXPECT_EQ(OemCertificate::kRsa, oem_cert->key_type()); + + // Validating key should return an error. + EXPECT_EQ(OEMCrypto_ERROR_INVALID_RSA_KEY, oem_cert->IsCertificateValid()); +} + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/test/oemcrypto_ref_test_utils.cpp b/oemcrypto/ref/test/oemcrypto_ref_test_utils.cpp new file mode 100644 index 0000000..2741548 --- /dev/null +++ b/oemcrypto/ref/test/oemcrypto_ref_test_utils.cpp @@ -0,0 +1,20 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include "oemcrypto_ref_test_utils.h" + +#include + +#include "cdm_random.h" + +namespace wvoec_ref { + +std::vector RandomData(size_t length) { + const std::string data = wvcdm::CdmRandom::RandomData(length); + return std::vector(data.begin(), data.end()); +} + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/test/oemcrypto_ref_test_utils.h b/oemcrypto/ref/test/oemcrypto_ref_test_utils.h new file mode 100644 index 0000000..e229077 --- /dev/null +++ b/oemcrypto/ref/test/oemcrypto_ref_test_utils.h @@ -0,0 +1,21 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#ifndef OEMCRYPTO_REF_TEST_UTILS_H_ +#define OEMCRYPTO_REF_TEST_UTILS_H_ + +#include + +#include + +namespace wvoec_ref { + +// Returns a vector of random bytes. +std::vector RandomData(size_t length); + +} // namespace wvoec_ref + +#endif // OEMCRYPTO_REF_TEST_UTILS_H_ diff --git a/oemcrypto/ref/test/oemcrypto_rsa_key_unittest.cpp b/oemcrypto/ref/test/oemcrypto_rsa_key_unittest.cpp new file mode 100644 index 0000000..dcab21e --- /dev/null +++ b/oemcrypto/ref/test/oemcrypto_rsa_key_unittest.cpp @@ -0,0 +1,406 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include + +#include + +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oemcrypto_ref_test_utils.h" +#include "oemcrypto_rsa_key.h" + +namespace wvoec_ref { +constexpr size_t kMessageSize = 4 * 1024; // 4 kB +constexpr size_t kCastMessageSize = 83; // Special max size. + +class OEMCryptoRsaKeyTest : public ::testing::TestWithParam { + public: + void SetUp() override { + // RSA key generation is slow (~2 seconds) compared to the + // operations they perform (<50 ms). Each key type is generated + // once and globally stored in serialized form. + // Caching the instance may result in test failures for + // memory-leak detection. + const RsaFieldSize field_size = GetParam(); + std::lock_guard rsa_key_lock(rsa_key_mutex_); + // Use of a switch case is intentional to cause compiler warnings + // if a new field size is introduced without updating the test. + switch (field_size) { + case kRsa2048Bit: { + if (!rsa_2048_key_data_.empty()) { + key_ = RsaPrivateKey::Load(rsa_2048_key_data_); + } + if (!key_) { + key_ = RsaPrivateKey::New(kRsa2048Bit); + } + if (rsa_2048_key_data_.empty() && key_) { + rsa_2048_key_data_ = key_->Serialize(); + } + } break; + case kRsa3072Bit: { + if (!rsa_3072_key_data_.empty()) { + key_ = RsaPrivateKey::Load(rsa_3072_key_data_); + } + if (!key_) { + key_ = RsaPrivateKey::New(kRsa3072Bit); + } + if (rsa_3072_key_data_.empty() && key_) { + rsa_3072_key_data_ = key_->Serialize(); + } + } break; + case kRsaFieldUnknown: // Suppress compiler warnings + LOGE("RSA test was incorrectly instantiation"); + exit(EXIT_FAILURE); + break; + } + } + + void TearDown() override { key_.reset(); } + + protected: + std::unique_ptr key_; + static std::mutex rsa_key_mutex_; + static std::vector rsa_2048_key_data_; + static std::vector rsa_3072_key_data_; +}; + +std::mutex OEMCryptoRsaKeyTest::rsa_key_mutex_; +std::vector OEMCryptoRsaKeyTest::rsa_2048_key_data_; +std::vector OEMCryptoRsaKeyTest::rsa_3072_key_data_; + +// Basic verification of RSA private key generation. +TEST_P(OEMCryptoRsaKeyTest, KeyProperties) { + ASSERT_TRUE(key_); + const RsaFieldSize expected_field_size = GetParam(); + + EXPECT_EQ(key_->field_size(), expected_field_size); + EXPECT_NE(nullptr, key_->GetRsaKey()); +} + +// Checks that the private key serialization APIs are compatible +// and performing in a manner that is similar to other OEMCrypto methods +// that retrieve data. +TEST_P(OEMCryptoRsaKeyTest, SerializePrivateKey) { + ASSERT_TRUE(key_); + + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t buffer_size = kInitialBufferSize; + std::vector buffer(buffer_size); + + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + key_->Serialize(buffer.data(), &buffer_size)); + EXPECT_GT(buffer_size, kInitialBufferSize); + + buffer.resize(buffer_size); + EXPECT_EQ(OEMCrypto_SUCCESS, key_->Serialize(buffer.data(), &buffer_size)); + buffer.resize(buffer_size); + + const std::vector direct_key_data = key_->Serialize(); + EXPECT_FALSE(direct_key_data.empty()); + ASSERT_EQ(buffer.size(), direct_key_data.size()); + for (size_t i = 0; i < buffer.size(); i++) { + ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i); + } +} + +// Checks that a private key that is serialized can be deserialized and +// reload. Also checks that the serialization of a key produces the +// same data to ensure consistency. +TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKey) { + ASSERT_TRUE(key_); + + const std::vector key_data = key_->Serialize(); + std::unique_ptr loaded_key = RsaPrivateKey::Load(key_data); + ASSERT_TRUE(loaded_key); + + EXPECT_EQ(key_->field_size(), loaded_key->field_size()); + + const std::vector loaded_key_data = loaded_key->Serialize(); + ASSERT_EQ(key_data.size(), loaded_key_data.size()); + for (size_t i = 0; i < key_data.size(); i++) { + ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i); + } +} + +// Checks that a private key with explicitly indicated schemes include +// the scheme fields in the reserialized key. +TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPrivateKeyWithAllowedSchemes) { + ASSERT_TRUE(key_); + + const std::vector raw_key_data = key_->Serialize(); + std::vector key_data = {'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, 0x03}; + key_data.insert(key_data.end(), raw_key_data.begin(), raw_key_data.end()); + + std::unique_ptr explicit_key = RsaPrivateKey::Load(key_data); + ASSERT_TRUE(explicit_key); + EXPECT_EQ(key_->field_size(), explicit_key->field_size()); + EXPECT_EQ(explicit_key->allowed_schemes(), 0x03); + + const std::vector explicit_key_data = explicit_key->Serialize(); + ASSERT_EQ(key_data.size(), explicit_key_data.size()); + ASSERT_EQ(key_data, explicit_key_data); +} + +// Checks that a public key can be created from the private key. +TEST_P(OEMCryptoRsaKeyTest, DerivePublicKey) { + ASSERT_TRUE(key_); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + EXPECT_TRUE(key_->IsMatchingPublicKey(*pub_key)); +} + +// Checks that the public key serialization APIs are compatible +// and performing in a manner that is similar to other OEMCrypto methods +// that retrieve data. +TEST_P(OEMCryptoRsaKeyTest, SerializePublicKey) { + ASSERT_TRUE(key_); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t buffer_size = kInitialBufferSize; + std::vector buffer(buffer_size); + + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + pub_key->Serialize(buffer.data(), &buffer_size)); + EXPECT_GT(buffer_size, kInitialBufferSize); + + buffer.resize(buffer_size); + EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->Serialize(buffer.data(), &buffer_size)); + buffer.resize(buffer_size); + + const std::vector direct_key_data = pub_key->Serialize(); + EXPECT_FALSE(direct_key_data.empty()); + ASSERT_EQ(buffer.size(), direct_key_data.size()); + for (size_t i = 0; i < buffer.size(); i++) { + ASSERT_EQ(buffer[i], direct_key_data[i]) << "i = " << std::to_string(i); + } +} + +// Checks that a public key that is serialized can be deserialized and +// reload. Also checks that the serialization of a key produces the +// same data to ensure consistency. +TEST_P(OEMCryptoRsaKeyTest, SerializeAndReloadPublicKey) { + ASSERT_TRUE(key_); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + const std::vector key_data = pub_key->Serialize(); + + std::unique_ptr loaded_key = RsaPublicKey::Load(key_data); + ASSERT_TRUE(loaded_key); + + EXPECT_EQ(pub_key->field_size(), loaded_key->field_size()); + EXPECT_EQ(pub_key->allowed_schemes(), loaded_key->allowed_schemes()); + + const std::vector loaded_key_data = loaded_key->Serialize(); + ASSERT_EQ(key_data.size(), loaded_key_data.size()); + for (size_t i = 0; i < key_data.size(); i++) { + ASSERT_EQ(key_data[i], loaded_key_data[i]) << "i = " << std::to_string(i); + } +} + +// Checks that the RSA signature generating API operates similar to +// existing signature generation functions. +TEST_P(OEMCryptoRsaKeyTest, GenerateSignature) { + ASSERT_TRUE(key_); + + const std::vector message = RandomData(kMessageSize); + ASSERT_FALSE(message.empty()) << "CdmRandom failed"; + + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t signature_size = kInitialBufferSize; + std::vector signature(signature_size); + EXPECT_EQ( + OEMCrypto_ERROR_SHORT_BUFFER, + key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault, + signature.data(), &signature_size)); + EXPECT_GT(signature_size, kInitialBufferSize); + + signature.resize(signature_size); + EXPECT_EQ( + OEMCrypto_SUCCESS, + key_->GenerateSignature(message.data(), message.size(), kRsaPssDefault, + signature.data(), &signature_size)); + signature.resize(signature_size); + + EXPECT_LE(signature_size, key_->SignatureSize()); +} + +// Checks that RSA signatures can be verified by an RSA public key. +TEST_P(OEMCryptoRsaKeyTest, VerifySignature) { + ASSERT_TRUE(key_); + const std::vector message = RandomData(kMessageSize); + ASSERT_FALSE(message.empty()) << "CdmRandom failed"; + + const std::vector signature = key_->GenerateSignature(message); + + std::unique_ptr pub_key = key_->MakePublicKey(); + ASSERT_TRUE(pub_key); + + EXPECT_EQ(OEMCrypto_SUCCESS, pub_key->VerifySignature(message, signature)); + + // Check with different message. + const std::vector message_two = RandomData(kMessageSize); + EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, + pub_key->VerifySignature(message_two, signature)); + + // Check with bad signature. + const std::vector bad_signature = RandomData(signature.size()); + EXPECT_EQ(OEMCrypto_ERROR_SIGNATURE_FAILURE, + pub_key->VerifySignature(message, bad_signature)); +} + +// Checks that the special CAST receiver signature scheme works +// to the degree that it is possible to test. +TEST_P(OEMCryptoRsaKeyTest, GenerateAndVerifyRsaSignature) { + ASSERT_TRUE(key_); + // Key must be enabled for PKCS1 Block 1 padding scheme. + // To do so, the key is serialized and the padding scheme is + // added to the key data. + const std::vector key_data = key_->Serialize(); + ASSERT_FALSE(key_data.empty()); + std::vector pkcs_enabled_key_data = { + 'S', 'I', 'G', 'N', 0x00, 0x00, 0x00, kSign_PKCS1_Block1}; + pkcs_enabled_key_data.insert(pkcs_enabled_key_data.end(), key_data.begin(), + key_data.end()); + std::unique_ptr pkcs_enabled_key = + RsaPrivateKey::Load(pkcs_enabled_key_data); + ASSERT_TRUE(pkcs_enabled_key); + + // The actual cast message is a domain specific hash of the message, + // however, random data works for testing purposes. + const std::vector message = RandomData(kCastMessageSize); + + // Generate signature. + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t signature_size = kInitialBufferSize; + std::vector signature(signature_size); + EXPECT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + pkcs_enabled_key->GenerateSignature(message.data(), message.size(), + kRsaPkcs1Cast, signature.data(), + &signature_size)); + EXPECT_GT(signature_size, kInitialBufferSize); + signature.resize(signature_size); + EXPECT_EQ(OEMCrypto_SUCCESS, + pkcs_enabled_key->GenerateSignature(message.data(), message.size(), + kRsaPkcs1Cast, signature.data(), + &signature_size)); + signature.resize(signature_size); + + EXPECT_LE(signature_size, pkcs_enabled_key->SignatureSize()); + + // Verify signature. + std::unique_ptr pub_key = pkcs_enabled_key->MakePublicKey(); + ASSERT_TRUE(pub_key); + + EXPECT_EQ(OEMCrypto_SUCCESS, + pub_key->VerifySignature(message, signature, kRsaPkcs1Cast)); +} + +// Verifies the session key exchange protocol used by the licensing +// server. +TEST_P(OEMCryptoRsaKeyTest, ShareSessionKey) { + constexpr size_t kSessionKeySize = 16; + ASSERT_TRUE(key_); + std::unique_ptr public_key = key_->MakePublicKey(); + ASSERT_TRUE(public_key); + + // Generate session key. + const std::vector session_key = RandomData(kSessionKeySize); + ASSERT_FALSE(session_key.empty()); + + // Server's perspective. + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t enc_session_key_size = kInitialBufferSize; + std::vector enc_session_key(enc_session_key_size); + OEMCryptoResult result = public_key->EncryptSessionKey( + session_key.data(), session_key.size(), enc_session_key.data(), + &enc_session_key_size); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result); + enc_session_key.resize(enc_session_key_size); + result = public_key->EncryptSessionKey(session_key.data(), session_key.size(), + enc_session_key.data(), + &enc_session_key_size); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + enc_session_key.resize(enc_session_key_size); + + // Client's perspective. + size_t received_session_key_size = kInitialBufferSize; + std::vector received_session_key(received_session_key_size); + result = key_->DecryptSessionKey( + enc_session_key.data(), enc_session_key.size(), + received_session_key.data(), &received_session_key_size); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result); + received_session_key.resize(received_session_key_size); + result = key_->DecryptSessionKey( + enc_session_key.data(), enc_session_key.size(), + received_session_key.data(), &received_session_key_size); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + received_session_key.resize(received_session_key_size); + + // Compare keys. + ASSERT_EQ(session_key.size(), received_session_key.size()); + ASSERT_EQ(session_key, received_session_key); +} + +// Verifies the encryption key exchange protocol used by the licensing +// server. +TEST_P(OEMCryptoRsaKeyTest, ShareEncryptionKey) { + constexpr size_t kEncryptionKeySize = 16; + ASSERT_TRUE(key_); + std::unique_ptr public_key = key_->MakePublicKey(); + ASSERT_TRUE(public_key); + + // Generate session key. + const std::vector encryption_key = RandomData(kEncryptionKeySize); + ASSERT_FALSE(encryption_key.empty()); + + // Server's perspective. + constexpr size_t kInitialBufferSize = 10; // Definitely too small. + size_t enc_encryption_key_size = kInitialBufferSize; + std::vector enc_encryption_key(enc_encryption_key_size); + OEMCryptoResult result = public_key->EncryptEncryptionKey( + encryption_key.data(), encryption_key.size(), enc_encryption_key.data(), + &enc_encryption_key_size); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result); + enc_encryption_key.resize(enc_encryption_key_size); + result = public_key->EncryptEncryptionKey( + encryption_key.data(), encryption_key.size(), enc_encryption_key.data(), + &enc_encryption_key_size); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + enc_encryption_key.resize(enc_encryption_key_size); + + // Client's perspective. + size_t received_encryption_key_size = kInitialBufferSize; + std::vector received_encryption_key(received_encryption_key_size); + result = key_->DecryptEncryptionKey( + enc_encryption_key.data(), enc_encryption_key.size(), + received_encryption_key.data(), &received_encryption_key_size); + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, result); + received_encryption_key.resize(received_encryption_key_size); + result = key_->DecryptEncryptionKey( + enc_encryption_key.data(), enc_encryption_key.size(), + received_encryption_key.data(), &received_encryption_key_size); + ASSERT_EQ(OEMCrypto_SUCCESS, result); + received_encryption_key.resize(received_encryption_key_size); + + // Compare keys. + ASSERT_EQ(encryption_key.size(), received_encryption_key.size()); + ASSERT_EQ(encryption_key, received_encryption_key); +} + +INSTANTIATE_TEST_SUITE_P(AllFieldSizes, OEMCryptoRsaKeyTest, + ::testing::Values(kRsa2048Bit, kRsa3072Bit)); + +} // namespace wvoec_ref diff --git a/oemcrypto/ref/test/oemcrypto_wvcrc32_unittest.cpp b/oemcrypto/ref/test/oemcrypto_wvcrc32_unittest.cpp new file mode 100644 index 0000000..baabaa1 --- /dev/null +++ b/oemcrypto/ref/test/oemcrypto_wvcrc32_unittest.cpp @@ -0,0 +1,74 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Reference implementation of OEMCrypto APIs +// +#include + +#include "wvcrc32.h" + +namespace wvoec_ref { + +uint32_t ComputeCrc32(const std::string& s) { + return wvcrc32(reinterpret_cast(s.data()), s.size()); +} + +uint32_t ComputeCrc32Cont(const std::string& s, uint32_t prev_crc) { + return wvcrc32Cont(reinterpret_cast(s.data()), s.size(), + prev_crc); +} + +TEST(OEMCryptoWvCrc32Test, BasicTest) { + EXPECT_EQ(0xF88AC628, ComputeCrc32("abcdefg")); + EXPECT_EQ(0xDF520F72, ComputeCrc32("Widevine")); + EXPECT_EQ(0x0376E6E7, ComputeCrc32("123456789")); + EXPECT_EQ(0xBA62119E, + ComputeCrc32("The quick brown fox jumps over the lazy dog")); +} + +TEST(OEMCryptoWvCrc32Test, StreamTest) { + const std::vector parts = {"The ", "quick", " brown ", + "fox", " jumps ", "over", + " the ", "lazy", " dog"}; + uint32_t crc = wvcrc32Init(); + for (const auto& part : parts) { + crc = ComputeCrc32Cont(part, crc); + } + EXPECT_EQ(0xBA62119E, crc); +} + +TEST(OEMCryptoWvCrc32Test, Keybox) { + // clang-format off + const uint8_t kKeyboxData[128] = { + // deviceID = WidevineCRCTestKeyBox + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, + 0x43, 0x52, 0x43, 0x54, 0x65, 0x73, 0x74, 0x4b, + 0x65, 0x79, 0x62, 0x6f, 0x78, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + // key = random + 0x8a, 0x7c, 0xda, 0x3e, 0x09, 0xd9, 0x8e, 0xd5, + 0x47, 0x47, 0x00, 0x84, 0x5a, 0x1f, 0x52, 0xd4, + // data = random + 0x98, 0xa5, 0x00, 0x19, 0x8b, 0xfe, 0x54, 0xfd, + 0xca, 0x4d, 0x26, 0xa3, 0xfa, 0xaa, 0x3b, 0x6c, + 0x35, 0xfe, 0x03, 0x7c, 0xbf, 0x35, 0xba, 0xce, + 0x31, 0xb5, 0x1e, 0x3c, 0x49, 0xd6, 0x3f, 0x9c, + 0x3a, 0xde, 0x9b, 0x58, 0xcc, 0x54, 0x8d, 0xc0, + 0x4b, 0x04, 0xcc, 0xee, 0xae, 0x4d, 0x9f, 0x90, + 0xd3, 0xf3, 0xfe, 0x23, 0x26, 0x13, 0x56, 0x80, + 0xe4, 0x3b, 0x79, 0x22, 0x69, 0x5d, 0xd6, 0xb7, + 0xa0, 0x0e, 0x7e, 0x07, 0xcd, 0x1a, 0x15, 0xca, + // magic + 'k', 'b', 'o', 'x', + // crc + 0x09, 0x7b, 0x7e, 0xcc + }; + // clang-format on + const uint32_t crc_computed = wvcrc32n(kKeyboxData, 124); + uint32_t crc_current; + memcpy(&crc_current, &kKeyboxData[124], 4); + EXPECT_EQ(crc_computed, crc_current); +} + +} // namespace wvoec_ref diff --git a/oemcrypto/renewal/Makefile b/oemcrypto/renewal/Makefile new file mode 100644 index 0000000..f2bdd38 --- /dev/null +++ b/oemcrypto/renewal/Makefile @@ -0,0 +1,3 @@ +derive_key: derive_key.cpp + g++ -g -o derive_key derive_key.cpp -lssl -lcrypto + diff --git a/oemcrypto/test/Android.mk b/oemcrypto/test/Android.mk new file mode 100644 index 0000000..5d86cda --- /dev/null +++ b/oemcrypto/test/Android.mk @@ -0,0 +1,25 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_C_INCLUDES := \ + vendor/widevine/libwvdrmengine/cdm/util/include \ + +LOCAL_MODULE:=oemcrypto_test +LOCAL_LICENSE_KINDS:=legacy_by_exception_only +LOCAL_LICENSE_CONDITIONS:=by_exception_only +LOCAL_MODULE_TAGS := tests + +LOCAL_MODULE_OWNER := widevine +LOCAL_PROPRIETARY_MODULE := true + +# When built, explicitly put it in the DATA/nativetest directory. +LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest + +ifneq ($(TARGET_ENABLE_MEDIADRM_64), true) +LOCAL_MODULE_TARGET_ARCH := arm x86 mips +endif + +include $(LOCAL_PATH)/common.mk + +include $(BUILD_EXECUTABLE) diff --git a/oemcrypto/test/common.mk b/oemcrypto/test/common.mk new file mode 100644 index 0000000..698a7d7 --- /dev/null +++ b/oemcrypto/test/common.mk @@ -0,0 +1,56 @@ +LOCAL_PATH:= $(call my-dir) + +ifeq ($(filter mips mips64, $(TARGET_ARCH)),) +# Tests need to be compatible with devices that do not support gnu hash-style +LOCAL_LDFLAGS+=-Wl,--hash-style=both +endif + +# The unit tests can access v15 functions through the dynamic adapter: +LOCAL_CFLAGS += -DTEST_OEMCRYPTO_V15 + +LOCAL_SRC_FILES:= \ + oec_device_features.cpp \ + oec_decrypt_fallback_chain.cpp \ + oec_key_deriver.cpp \ + oec_session_util.cpp \ + oemcrypto_corpus_generator_helper.cpp \ + oemcrypto_session_tests_helper.cpp \ + oemcrypto_test.cpp \ + oemcrypto_test_android.cpp \ + oemcrypto_test_main.cpp \ + ota_keybox_test.cpp \ + wvcrc.cpp \ + ../../cdm/util/test/test_sleep.cpp \ + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/fuzz_tests \ + $(LOCAL_PATH)/../include \ + $(LOCAL_PATH)/../odk/include \ + $(LOCAL_PATH)/../odk/kdo/include \ + $(LOCAL_PATH)/../ref/src \ + vendor/widevine/libwvdrmengine/cdm/core/include \ + vendor/widevine/libwvdrmengine/cdm/util/include \ + vendor/widevine/libwvdrmengine/cdm/util/test \ + +LOCAL_STATIC_LIBRARIES := \ + libcdm \ + libcdm_utils \ + libgtest \ + libgtest_main \ + libwvlevel3 \ + libcdm_protos \ + libcdm_utils \ + libwv_kdo \ + libwv_odk \ + +LOCAL_SHARED_LIBRARIES := \ + libbase \ + libcrypto \ + libdl \ + libhidlbase \ + liblog \ + libmedia_omx \ + libprotobuf-cpp-lite \ + libstagefright_foundation \ + libutils \ + libz \ diff --git a/oemcrypto/test/fuzz_tests/README.md b/oemcrypto/test/fuzz_tests/README.md index 3550994..3f66444 100644 --- a/oemcrypto/test/fuzz_tests/README.md +++ b/oemcrypto/test/fuzz_tests/README.md @@ -85,12 +85,12 @@ OEMCrypto implementations on linux. $ ./out/Default/oemcrypto_unittests --generate_corpus \ --gtest_filter=-"*Huge*" ``` - + * There can be lot of duplicate corpus files that are generated from unit tests. We can minimize the corpus files to only a subset of files that cover unique paths within the API when run using fuzzer. Run following command to minimize corpus. - + ```shell $ cd /path/to/cdm/repo # build fuzzer binaries @@ -128,7 +128,7 @@ OEMCrypto implementations on linux. * Build and test fuzz scripts locally using following commands. The build script builds fuzz binaries for both oemcrypto reference implementation - as well as odkitee implementation. + as well as opk implementation. ```shell $ cd PATH_TO_CDM_DIR diff --git a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests index a32f5a3..41c9b62 100755 --- a/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests +++ b/oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests @@ -9,4 +9,11 @@ export PYTHONPATH="$PYTHONPATH:$PATH_TO_CDM_DIR/third_party" python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ --depth=$(pwd) oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp +ninja -C out/Default +# oemcrypto_opk_fuzztests.gypi has flags to instrument all the gyp targets +# with fuzzer flags. +python3 $PATH_TO_CDM_DIR/third_party/gyp/__init__.py --format=ninja \ + --depth=$(pwd) \ + --include=oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi \ + oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp ninja -C out/Default \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/build_partner_oemcrypto_fuzztests b/oemcrypto/test/fuzz_tests/build_partner_oemcrypto_fuzztests old mode 100644 new mode 100755 diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc new file mode 100644 index 0000000..46e3e19 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_copy_buffer_fuzz.cc @@ -0,0 +1,94 @@ +// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine Master +// License Agreement. + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oemcrypto_fuzz_helper.h" +#include "oemcrypto_fuzz_structs.h" + +namespace wvoec { +// Free dynamic memory allocated by fuzzer script. +void FreeOutputBuffers(OEMCrypto_SESSION session_id, + OEMCrypto_DestBufferDesc& output_descriptor, + int* secure_fd) { + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: { + delete[] output_descriptor.buffer.clear.address; + break; + } + case OEMCrypto_BufferType_Secure: { + OEMCrypto_FreeSecureBuffer(session_id, &output_descriptor, *secure_fd); + break; + } + case OEMCrypto_BufferType_Direct: { + break; + } + } +} + +bool InitializeOutputBuffers(OEMCrypto_SESSION session_id, + OEMCrypto_DestBufferDesc& output_descriptor, + int* secure_fd, size_t input_buffer_size) { + switch (output_descriptor.type) { + case OEMCrypto_BufferType_Clear: { + output_descriptor.buffer.clear.address = + new OEMCrypto_SharedMemory[input_buffer_size]; + return true; + } + case OEMCrypto_BufferType_Secure: { + OEMCryptoResult sts = OEMCrypto_AllocateSecureBuffer( + session_id, input_buffer_size, &output_descriptor, secure_fd); + return sts == OEMCrypto_SUCCESS; + } + case OEMCrypto_BufferType_Direct: { + return true; + } + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // Redirect printf and log statements from oemcrypto functions to a file to + // reduce noise + RedirectStdoutToFile(); + uint8_t subsample_flags; + + // OEMCrypto_DestBufferDesc and a buffer from which data needs to be copied + // are expected as inputs to copy buffer API. + // Input fuzzed data is interpreted as + // (OEMCrypto_DestBufferDesc | subsample_flags | input_buffer) + if (size <= sizeof(OEMCrypto_Copy_Buffer_Fuzz)) { + return 0; + } + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + // Fuzz dest_buffer_desc. + memcpy(&fuzzed_structure, data, sizeof(fuzzed_structure)); + ConvertDataToValidEnum(OEMCrypto_BufferType_MaxValue, + &fuzzed_structure.dest_buffer_desc.type); + + OEMCryptoLicenseAPIFuzz license_api_fuzz; + Session* session = license_api_fuzz.session(); + // Fuzz input buffer to be copied. + size_t input_buffer_size = size - sizeof(fuzzed_structure); + int secure_fd = 0; + // Create output buffer pointers. If secure buffer is not supported, we + // explicitly convert to clear buffer and fuzz. + if (!InitializeOutputBuffers(session->session_id(), + fuzzed_structure.dest_buffer_desc, &secure_fd, + input_buffer_size)) { + LOGI( + "[OEMCrypto decrypt CENC fuzz] Secure buffers are not supported. Use " + "clear buffer instead."); + fuzzed_structure.dest_buffer_desc.type = OEMCrypto_BufferType_Clear; + InitializeOutputBuffers(session->session_id(), + fuzzed_structure.dest_buffer_desc, &secure_fd, + input_buffer_size); + } + OEMCrypto_CopyBuffer(session->session_id(), data + sizeof(fuzzed_structure), + input_buffer_size, &fuzzed_structure.dest_buffer_desc, + subsample_flags); + FreeOutputBuffers(session->session_id(), fuzzed_structure.dest_buffer_desc, + &secure_fd); + return 0; +} +} // namespace wvoec \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc index b3d0582..560a172 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_deactivate_usage_entry_fuzz.cc @@ -1,5 +1,5 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine +// source code may only be used and distributed under the Widevine Master // License Agreement. #include "oemcrypto_fuzz_helper.h" diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc index 6ff69a9..9a16086 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_decrypt_cenc_fuzz.cc @@ -5,9 +5,9 @@ #include "FuzzedDataProvider.h" #include "OEMCryptoCENC.h" #include "log.h" -#include "odk_overflow.h" #include "oemcrypto_fuzz_helper.h" #include "oemcrypto_fuzz_structs.h" +#include "oemcrypto_overflow.h" namespace wvoec { const size_t MAX_FUZZ_SAMPLE_SIZE = 5 * MB; @@ -138,9 +138,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { // Copy sub sample data. sample_descriptions[i].subsamples = &subsamples[input_subsample_index]; - if (odk_add_overflow_ux(input_subsample_index, - sample_descriptions[i].subsamples_length, - &input_subsample_index)) { + if (OPK_AddOverflowUX(input_subsample_index, + sample_descriptions[i].subsamples_length, + &input_subsample_index)) { return 0; } if (input_subsample_index > subsamples.size()) return 0; diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h index 5a5febb..37b3daf 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzz_structs.h @@ -68,6 +68,14 @@ struct OEMCrypto_Generate_RSA_Signature_Fuzz { // input buffer data is of variable length and not included in // this structure. }; + +struct OEMCrypto_Copy_Buffer_Fuzz { + // Corpus format is as below. + // dest_buffer_desc + subsample_flags + input buffer + OEMCrypto_DestBufferDesc dest_buffer_desc; + uint8_t subsample_flags; + // Input buffer of variable length is not included in this structure. +}; } // namespace wvoec #endif // OEMCRYPTO_FUZZ_STRUCTS_H_ \ No newline at end of file diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp index 6192f29..458e3b8 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gyp @@ -119,5 +119,11 @@ 'oemcrypto_report_usage_fuzz.cc', ], }, + { + 'target_name': 'oemcrypto_copy_buffer_fuzz', + 'sources': [ + 'oemcrypto_copy_buffer_fuzz.cc', + ], + }, ], } diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi index 6d43e37..9193012 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_fuzztests.gypi @@ -40,14 +40,14 @@ '<(oemcrypto_dir)/test/fuzz_tests', '<(oemcrypto_dir)/odk/include', '<(oemcrypto_dir)/odk/src', - '<(oemcrypto_dir)/odkitee/oemcrypto_ta', + '<(oemcrypto_dir)/opk/oemcrypto_ta', ], 'includes': [ '../../../util/libssl_dependency.gypi', ], 'dependencies': [ - '../../../third_party/gmock.gyp:gtest', - '../../../third_party/gmock.gyp:gmock', + '../../../third_party/googletest.gyp:gtest', + '../../../third_party/googletest.gyp:gmock', ], 'defines': [ 'OEMCRYPTO_FUZZ_TESTS', @@ -95,6 +95,7 @@ '-fcoverage-mapping', ], 'ldflags': [ + '-fsanitize=fuzzer', '-fprofile-instr-generate', '-fcoverage-mapping', ], @@ -106,11 +107,11 @@ '../../ref/oec_ref.gypi', ], }], - ['oemcrypto_implementation_version=="odkitee"', { - # Include oemcrypto odkitee implementation code for building odkitee + ['oemcrypto_implementation_version=="opk"', { + # Include oemcrypto opk implementation code for building opk # implementation fuzz binaries. 'dependencies': [ - '../../odkitee/oemcrypto_ta/oemcrypto_ta.gyp:oemcrypto_ta', + '<(oemcrypto_dir)/opk/ports/linux/wtpi_test_impl/wtpi_test_impl.gyp:oemcrypto_ta_test_impl_no_ipc', ], }], ], # conditions diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc index da6ed6a..ed47b0b 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_load_usage_entry_fuzz.cc @@ -1,5 +1,5 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine +// source code may only be used and distributed under the Widevine Master // License Agreement. #include "OEMCryptoCENC.h" diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp deleted file mode 100644 index e5eb71a..0000000 --- a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gyp +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -# source code may only be used and distributed under the Widevine -# License Agreement. -{ - 'target_defaults': { - 'type': 'executable', - 'includes': [ - 'oemcrypto_fuzztests.gypi', - ], - }, - 'variables': { - # Flag to select appropriate underlying oemcrypto implementation when - # buiding fuzz binaries. - 'oemcrypto_implementation_version%': 'odkitee', - 'oemcrypto_dir': '../..', - }, - 'targets': [ - { - 'target_name': 'oemcrypto_odkitee_load_license_fuzz', - 'sources': [ - 'oemcrypto_load_license_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_load_provisioning_fuzz', - 'sources': [ - 'oemcrypto_load_provisioning_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_load_renewal_fuzz', - 'sources': [ - 'oemcrypto_load_renewal_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_license_request_fuzz', - 'sources': [ - 'oemcrypto_license_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_provisioning_request_fuzz', - 'sources': [ - 'oemcrypto_provisioning_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_renewal_request_fuzz', - 'sources': [ - 'oemcrypto_renewal_request_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_decrypt_cenc_fuzz', - 'sources': [ - 'oemcrypto_decrypt_cenc_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_load_entitled_content_keys_fuzz', - 'sources': [ - 'oemcrypto_load_entitled_content_keys_fuzz.cc', - ], - }, - { - 'target_name': 'oemcrypto_odkitee_dispatcher_fuzz', - 'include_dirs': [ - '<(oemcrypto_dir)/odkitee/serialization/common', - '<(oemcrypto_dir)/odkitee/serialization/os_interfaces', - '<(oemcrypto_dir)/odkitee/serialization/tee', - '<(oemcrypto_dir)/odkitee/serialization/tee/include', - '<(oemcrypto_dir)/odkitee/serialization/ports/trusty/include/', - ], - 'dependencies': [ - '<(oemcrypto_dir)/odkitee/serialization/tee/tee.gyp:odkitee_tee', - ], - 'sources': [ - 'oemcrypto_odkitee_dispatcher_fuzz.cc', - '<(oemcrypto_dir)/odkitee/serialization/test/transport_interface.c', - '<(oemcrypto_dir)/odkitee/serialization/ports/trusty/serialization_adapter/shared_memory.c', - ], - }, - ], -} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc similarity index 50% rename from oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc rename to oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc index 1a3c770..3fae8e6 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_dispatcher_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_dispatcher_fuzz.cc @@ -1,23 +1,15 @@ #include +#include -#include "dispatcher.h" -#include "marshaller_base.h" -#include "transport_interface.h" +#include "opk_dispatcher.h" +#include "opk_init.h" +#include "tos_transport_interface.h" namespace wvoec { -void InitializeODKMessage(ODK_Message* message, uint8_t* data, size_t size) { - ODK_Message_Impl* impl = (ODK_Message_Impl*)message; - impl->base = data; - impl->size = size; - impl->capacity = size; - impl->read_offset = 0; - impl->status = MESSAGE_STATUS_OK; -} - void OpenOEMCryptoTASession() { ODK_Message request; - ODK_Message* response = NULL; + ODK_Message response; uint8_t response_buffer[0x1000]; uint8_t request_body[] = { 0x06, // TAG_UINT32 @@ -26,16 +18,13 @@ void OpenOEMCryptoTASession() { 0x00, // value (false) 0x0a // TAG_EOM }; - - InitializeODKMessage(&request, request_body, sizeof(request_body)); - - ODK_DispatchMessage(&request, &response); - if (response != NULL) ODK_Transport_DeallocateMessage(response); + request = ODK_Message_Create(request_body, sizeof(request_body)); + OPK_DispatchMessage(&request, &response); } void InitializeOEMCryptoTA() { ODK_Message init_request; - ODK_Message* init_response = NULL; + ODK_Message init_response; uint8_t response_buffer[0x1000]; uint8_t init_request_body[] = { 0x06, // TAG_UINT32 @@ -43,15 +32,13 @@ void InitializeOEMCryptoTA() { 0x0a // TAG_EOM }; - InitializeODKMessage(&init_request, init_request_body, - sizeof(init_request_body)); - - ODK_DispatchMessage(&init_request, &init_response); - if (init_response != NULL) ODK_Transport_DeallocateMessage(init_response); + init_request = + ODK_Message_Create(init_request_body, sizeof(init_request_body)); + OPK_DispatchMessage(&init_request, &init_response); } extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { - ODK_InitializeDispatcher(); + OPK_Initialize(); InitializeOEMCryptoTA(); OpenOEMCryptoTASession(); return 0; @@ -59,16 +46,14 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { ODK_Message request; - ODK_Message* response = NULL; + ODK_Message response; unsigned char response_buffer[0x1000]; uint8_t* input = new uint8_t[size]; memcpy(input, data, size); - InitializeODKMessage(&request, input, size); - - ODK_DispatchMessage(&request, &response); - if (response != NULL) ODK_Transport_DeallocateMessage(response); + request = ODK_Message_Create(input, size); + OPK_DispatchMessage(&request, &response); delete[] input; return 0; diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp new file mode 100644 index 0000000..b5a73a1 --- /dev/null +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gyp @@ -0,0 +1,148 @@ +# Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +# source code may only be used and distributed under the Widevine +# License Agreement. +{ + 'target_defaults': { + 'type': 'executable', + 'includes': [ + 'oemcrypto_fuzztests.gypi', + ], + }, + 'variables': { + # Flag to select appropriate underlying oemcrypto implementation when + # buiding fuzz binaries. + 'oemcrypto_implementation_version%': 'opk', + 'oemcrypto_dir': '../..', + }, + 'targets': [ + { + 'target_name': 'oemcrypto_opk_load_license_fuzz', + 'sources': [ + 'oemcrypto_load_license_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_provisioning_fuzz', + 'sources': [ + 'oemcrypto_load_provisioning_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_renewal_fuzz', + 'sources': [ + 'oemcrypto_load_renewal_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_license_request_fuzz', + 'sources': [ + 'oemcrypto_license_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_provisioning_request_fuzz', + 'sources': [ + 'oemcrypto_provisioning_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_renewal_request_fuzz', + 'sources': [ + 'oemcrypto_renewal_request_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_decrypt_cenc_fuzz', + 'sources': [ + 'oemcrypto_decrypt_cenc_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_entitled_content_keys_fuzz', + 'sources': [ + 'oemcrypto_load_entitled_content_keys_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_encrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_encrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_decrypt_fuzz', + 'sources': [ + 'oemcrypto_generic_decrypt_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_sign_fuzz', + 'sources': [ + 'oemcrypto_generic_sign_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generic_verify_fuzz', + 'sources': [ + 'oemcrypto_generic_verify_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_generate_rsa_signature_fuzz', + 'sources': [ + 'oemcrypto_generate_rsa_signature_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_usage_table_header_fuzz', + 'sources': [ + 'oemcrypto_load_usage_table_header_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_load_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_load_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_deactivate_usage_entry_fuzz', + 'sources': [ + 'oemcrypto_deactivate_usage_entry_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_report_usage_fuzz', + 'sources': [ + 'oemcrypto_report_usage_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_copy_buffer_fuzz', + 'sources': [ + 'oemcrypto_copy_buffer_fuzz.cc', + ], + }, + { + 'target_name': 'oemcrypto_opk_dispatcher_fuzz', + 'include_dirs': [ + '<(oemcrypto_dir)/opk/serialization/common', + '<(oemcrypto_dir)/opk/serialization/common/include', + '<(oemcrypto_dir)/opk/serialization/os_interfaces', + '<(oemcrypto_dir)/opk/serialization/tee', + '<(oemcrypto_dir)/opk/serialization/tee/include', + '<(oemcrypto_dir)/opk/ports/trusty/include/', + ], + 'dependencies': [ + '<(oemcrypto_dir)/opk/serialization/tee/tee.gyp:opk_tee', + ], + 'sources': [ + 'oemcrypto_opk_dispatcher_fuzz.cc', + '<(oemcrypto_dir)/opk/serialization/test/tos_secure_buffers.c', + '<(oemcrypto_dir)/opk/serialization/test/tos_transport_interface.c', + '<(oemcrypto_dir)/opk/serialization/test/tos_logging.c', + '<(oemcrypto_dir)/opk/ports/trusty/serialization_adapter/shared_memory.c', + ], + }, + ], +} diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi similarity index 94% rename from oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi rename to oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi index 574c8b0..0a655fc 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_odkitee_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/oemcrypto_opk_fuzztests.gypi @@ -3,7 +3,7 @@ # License Agreement. # gypi file to be included using --includes option while building oemcrypto -# odkitee fuzz binaries. Odkitee classes needs to be instrumented with fuzzer +# opk fuzz binaries. OPK classes needs to be instrumented with fuzzer # but only when being built for fuzzing. Instead of directly updating # oemcrypto_ta.gyp target, we use gypi in build_oemcrypto_fuzztests script. { @@ -45,6 +45,9 @@ 'libraries': [ '-lpthread', ], + 'defines': [ + 'OPK_LOG_LEVEL=LOG_NONE', + ], 'conditions': [ ['generate_code_coverage_report=="true"', { # Include flags to build fuzzer binaries to generate source based code coverage reports. diff --git a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc index 65c1a9f..3b3813a 100644 --- a/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc +++ b/oemcrypto/test/fuzz_tests/oemcrypto_report_usage_fuzz.cc @@ -1,5 +1,5 @@ // Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine +// source code may only be used and distributed under the Widevine Master // License Agreement. #include "oemcrypto_fuzz_helper.h" diff --git a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi index 16af1a8..581727d 100644 --- a/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi +++ b/oemcrypto/test/fuzz_tests/partner_oemcrypto_fuzztests.gypi @@ -45,8 +45,8 @@ '../../../util/libssl_dependency.gypi', ], 'dependencies': [ - '../../../third_party/gmock.gyp:gtest', - '../../../third_party/gmock.gyp:gmock', + '../../../third_party/googletest.gyp:gtest', + '../../../third_party/googletest.gyp:gmock', ], 'defines': [ 'OEMCRYPTO_FUZZ_TESTS', diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.cpp b/oemcrypto/test/oec_decrypt_fallback_chain.cpp index b3d36dc..9d59bd8 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.cpp +++ b/oemcrypto/test/oec_decrypt_fallback_chain.cpp @@ -205,13 +205,13 @@ void WriteDecryptCencCorpus( const OEMCrypto_CENCEncryptPatternDesc* pattern, size_t samples_length) { const std::string file_name = GetFileName("oemcrypto_decrypt_cenc_fuzz_seed_corpus"); - // Cipher mode. - AppendToFile(file_name, reinterpret_cast(&cipher_mode), - sizeof(OEMCryptoCipherMode)); - - // Pattern. - AppendToFile(file_name, reinterpret_cast(pattern), - sizeof(OEMCrypto_CENCEncryptPatternDesc)); + OEMCrypto_Decrypt_Cenc_Fuzz decrypt_cenc_fuzz_struct; + decrypt_cenc_fuzz_struct.cipher_mode = cipher_mode; + decrypt_cenc_fuzz_struct.pattern = *pattern; + // Cipher mode and Pattern. + AppendToFile(file_name, + reinterpret_cast(&decrypt_cenc_fuzz_struct), + sizeof(OEMCrypto_Decrypt_Cenc_Fuzz)); // Sample data for all samples. for (size_t i = 0; i < samples_length; i++) { diff --git a/oemcrypto/test/oec_decrypt_fallback_chain.h b/oemcrypto/test/oec_decrypt_fallback_chain.h index 06ca62f..aafbb07 100644 --- a/oemcrypto/test/oec_decrypt_fallback_chain.h +++ b/oemcrypto/test/oec_decrypt_fallback_chain.h @@ -7,6 +7,7 @@ #include "OEMCryptoCENC.h" #include "disallow_copy_and_assign.h" +#include "oemcrypto_fuzz_structs.h" namespace wvoec { diff --git a/oemcrypto/test/oec_key_deriver.cpp b/oemcrypto/test/oec_key_deriver.cpp index f6abdb6..dc1d237 100644 --- a/oemcrypto/test/oec_key_deriver.cpp +++ b/oemcrypto/test/oec_key_deriver.cpp @@ -5,7 +5,7 @@ // OEMCrypto unit tests // -#include "oec_session_util.h" +#include "oec_key_deriver.h" #include #include @@ -58,7 +58,7 @@ void Encryptor::CBCEncrypt(const uint8_t* data, uint8_t* encrypted_data, void Encryptor::PadAndEncryptProvisioningMessage( RSAPrivateKeyMessage* data, RSAPrivateKeyMessage* encrypted) const { - EXPECT_EQ(1, GetRandBytes(data->rsa_key_iv, KEY_IV_SIZE)); + EXPECT_EQ(1, RAND_bytes(data->rsa_key_iv, KEY_IV_SIZE)); ASSERT_EQ(enc_key_.size(), KEY_SIZE); *encrypted = *data; if (data->rsa_key_length > sizeof(data->rsa_key)) { @@ -95,7 +95,7 @@ void KeyDeriver::DeriveKey(const uint8_t* key, const vector& context, CMAC_CTX* cmac_ctx = CMAC_CTX_new(); ASSERT_NE(nullptr, cmac_ctx); - ASSERT_TRUE(CMAC_Init(cmac_ctx, key, KEY_SIZE, cipher, 0)); + ASSERT_TRUE(CMAC_Init(cmac_ctx, key, KEY_SIZE, cipher, nullptr)); std::vector message; message.push_back(static_cast(counter)); @@ -147,8 +147,9 @@ void KeyDeriver::ServerSignBuffer(const uint8_t* data, size_t data_length, ASSERT_EQ(mac_key_server_.size(), MAC_KEY_SIZE); signature->assign(SHA256_DIGEST_LENGTH, 0); unsigned int sig_len = SHA256_DIGEST_LENGTH; - ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_server_.data(), mac_key_server_.size(), - data, data_length, signature->data(), &sig_len)); + ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_server_.data(), + static_cast(mac_key_server_.size()), data, data_length, + signature->data(), &sig_len)); } void KeyDeriver::ClientSignBuffer(const vector& buffer, @@ -156,8 +157,9 @@ void KeyDeriver::ClientSignBuffer(const vector& buffer, ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE); signature->assign(SHA256_DIGEST_LENGTH, 0); unsigned int sig_len = SHA256_DIGEST_LENGTH; - ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_client_.data(), mac_key_client_.size(), - buffer.data(), buffer.size(), signature->data(), &sig_len)); + ASSERT_TRUE(HMAC(EVP_sha256(), mac_key_client_.data(), + static_cast(mac_key_client_.size()), buffer.data(), + buffer.size(), signature->data(), &sig_len)); } void KeyDeriver::ClientSignPstReport(const vector& pst_report_buffer, @@ -165,7 +167,8 @@ void KeyDeriver::ClientSignPstReport(const vector& pst_report_buffer, ASSERT_EQ(mac_key_client_.size(), MAC_KEY_SIZE); signature->assign(SHA_DIGEST_LENGTH, 0); unsigned int sig_len = SHA_DIGEST_LENGTH; - ASSERT_TRUE(HMAC(EVP_sha1(), mac_key_client_.data(), mac_key_client_.size(), + ASSERT_TRUE(HMAC(EVP_sha1(), mac_key_client_.data(), + static_cast(mac_key_client_.size()), &pst_report_buffer[SHA_DIGEST_LENGTH], pst_report_buffer.size() - SHA_DIGEST_LENGTH, signature->data(), &sig_len)); diff --git a/oemcrypto/test/oec_session_util.cpp b/oemcrypto/test/oec_session_util.cpp index 76fea1d..de06754 100644 --- a/oemcrypto/test/oec_session_util.cpp +++ b/oemcrypto/test/oec_session_util.cpp @@ -112,9 +112,9 @@ OEMCryptoResult DecryptCTR(OEMCrypto_SESSION session_id, const uint8_t* key, } // namespace -int GetRandBytes(unsigned char* buf, int num) { +int GetRandBytes(unsigned char* buf, size_t num) { // returns 1 on success, -1 if not supported, or 0 if other failure. - return RAND_bytes(buf, num); + return RAND_bytes(buf, static_cast(num)); } // Does the boilerplate to fill out sample and subsample descriptions for @@ -162,10 +162,12 @@ void ctr128_inc64(int64_t increaseBy, uint8_t* iv) { uint32_t htonl_fnc(uint32_t x) { return htonl(x); } void dump_boringssl_error() { - while (unsigned long err = ERR_get_error()) { + // BoringSSL and OpenSSL disagree about what the type of an error code is, so + // we must use "auto" here. + while (auto err = ERR_get_error()) { char buffer[120]; ERR_error_string_n(err, buffer, sizeof(buffer)); - cout << "BoringSSL Error -- " << buffer << "\n"; + cerr << "BoringSSL Error -- " << buffer << "\n"; } } @@ -557,9 +559,9 @@ void LicenseRoundTrip::FillAndVerifyCoreRequest( core_message_string, &core_request_)); EXPECT_EQ(global_features.api_version, core_request_.api_major_version); if (global_features.api_version == 16) { - // We support either 16.3 or 16.4 for OEMCrypto 16. + // We support 16.3, 16.4, or 16.5 for OEMCrypto 16. EXPECT_LE(3, core_request_.api_minor_version); - EXPECT_GE(4, core_request_.api_minor_version); + EXPECT_GE(5, core_request_.api_minor_version); } else if (global_features.api_version == ODK_MAJOR_VERSION) { // If we are testing the latest OEMCrypto version, make sure it is built // with the latest ODK version, too: @@ -1045,10 +1047,10 @@ void EntitledMessage::EncryptContentKey() { // Corpus for load entitled keys fuzzer should be in the format: // message buffer to be verified | entitled content key object array. AppendToFile(file_name, reinterpret_cast(entitled_key_data_), - sizeof(entitled_key_data_)); + num_keys_ * sizeof(EntitledContentKeyData)); AppendSeparator(file_name); AppendToFile(file_name, reinterpret_cast(entitled_key_array_), - num_keys_); + num_keys_ * sizeof(OEMCrypto_EntitledContentKeyObject)); } } @@ -1273,7 +1275,7 @@ Session::Session() forced_session_id_(false), session_id_(0), nonce_(0), - public_rsa_(0) {} + public_rsa_(nullptr) {} Session::~Session() { if (!forced_session_id_ && open_) close(); @@ -1375,7 +1377,8 @@ void Session::GenerateDerivedKeysFromSessionKey() { } void Session::TestDecryptCTR(bool select_key_first, - OEMCryptoResult expected_result, int key_index) { + OEMCryptoResult expected_result, + size_t key_index) { OEMCryptoResult select_result = OEMCrypto_SUCCESS; if (select_key_first) { // Select the key (from FillSimpleMessage) @@ -1435,7 +1438,7 @@ void Session::TestDecryptResult(OEMCryptoResult expected_result, } } -void Session::TestSelectExpired(unsigned int key_index) { +void Session::TestSelectExpired(size_t key_index) { if (global_features.api_version >= 13) { OEMCryptoResult status = OEMCrypto_SelectKey( session_id(), license().keys[key_index].key_id, @@ -1469,7 +1472,7 @@ void Session::LoadOEMCert(bool verify_cert) { reinterpret_cast(public_cert.data()); long cert_size = static_cast(public_cert.size()); boringssl_ptr pkcs7( - d2i_PKCS7(NULL, &cert_data, cert_size)); + d2i_PKCS7(nullptr, &cert_data, cert_size)); ASSERT_TRUE(pkcs7.NotNull()) << "Error parsing PKCS7 message"; ASSERT_TRUE(PKCS7_type_is_signed(pkcs7.get())) << "Unexpected PKCS7 message type"; @@ -1479,13 +1482,13 @@ void Session::LoadOEMCert(bool verify_cert) { // Load the public cert's key into public_rsa_ and verify, if requested for (size_t i = 0; certs && i < static_cast(sk_X509_num(certs)); ++i) { - X509* x509_cert = sk_X509_value(certs, i); + X509* x509_cert = sk_X509_value(certs, static_cast(i)); boringssl_ptr pubkey(X509_get_pubkey(x509_cert)); ASSERT_TRUE(pubkey.NotNull()); if (i == 0) { public_rsa_ = EVP_PKEY_get1_RSA(pubkey.get()); if (!public_rsa_) { - cout << "d2i_RSAPrivateKey failed.\n"; + cerr << "d2i_RSAPrivateKey failed.\n"; dump_boringssl_error(); ASSERT_TRUE(nullptr != public_rsa_); } @@ -1495,7 +1498,8 @@ void Session::LoadOEMCert(bool verify_cert) { X509_NAME* name = X509_get_subject_name(x509_cert); printf(" OEM Certificate Name: %s\n", - X509_NAME_oneline(name, buffer.data(), buffer.size())); + X509_NAME_oneline(name, buffer.data(), + static_cast(buffer.size()))); boringssl_ptr store(X509_STORE_new()); ASSERT_TRUE(store.NotNull()); boringssl_ptr store_ctx( @@ -1525,7 +1529,8 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) { rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048); } uint8_t* p = const_cast(rsa_key); - boringssl_ptr bio(BIO_new_mem_buf(p, rsa_key_length)); + boringssl_ptr bio( + BIO_new_mem_buf(p, static_cast(rsa_key_length))); ASSERT_TRUE(bio.NotNull()); boringssl_ptr pkcs8_pki( d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), nullptr)); @@ -1535,7 +1540,7 @@ void Session::PreparePublicKey(const uint8_t* rsa_key, size_t rsa_key_length) { if (public_rsa_) RSA_free(public_rsa_); public_rsa_ = EVP_PKEY_get1_RSA(evp.get()); if (!public_rsa_) { - cout << "d2i_RSAPrivateKey failed. "; + cerr << "d2i_RSAPrivateKey failed. "; dump_boringssl_error(); FAIL() << "Could not parse public RSA key."; } @@ -1623,8 +1628,9 @@ void Session::VerifyRSASignature(const vector& message, int size; // RSA_public_decrypt decrypts the signature, and then verifies that // it was padded with RSA PKCS1 padding. - size = RSA_public_decrypt(signature_length, signature, padded_digest.data(), - public_rsa_, RSA_PKCS1_PADDING); + size = RSA_public_decrypt(static_cast(signature_length), signature, + padded_digest.data(), public_rsa_, + RSA_PKCS1_PADDING); EXPECT_GT(size, 0); padded_digest.resize(size); EXPECT_EQ(message, padded_digest); @@ -1636,17 +1642,17 @@ void Session::VerifyRSASignature(const vector& message, bool Session::GenerateRSASessionKey(vector* session_key, vector* enc_session_key) { if (!public_rsa_) { - cout << "No public RSA key loaded in test code.\n"; + cerr << "No public RSA key loaded in test code.\n"; return false; } *session_key = wvcdm::a2b_hex("6fa479c731d2770b6a61a5d1420bb9d1"); enc_session_key->assign(RSA_size(public_rsa_), 0); - int status = RSA_public_encrypt(session_key->size(), &(session_key->front()), - &(enc_session_key->front()), public_rsa_, - RSA_PKCS1_OAEP_PADDING); + int status = RSA_public_encrypt( + static_cast(session_key->size()), &(session_key->front()), + &(enc_session_key->front()), public_rsa_, RSA_PKCS1_OAEP_PADDING); int size = static_cast(RSA_size(public_rsa_)); if (status != size) { - cout << "GenerateRSASessionKey error encrypting session key.\n"; + cerr << "GenerateRSASessionKey error encrypting session key.\n"; dump_boringssl_error(); return false; } @@ -1688,8 +1694,6 @@ void Session::UpdateUsageEntry(std::vector* header_buffer) { } void Session::LoadUsageEntry(uint32_t index, const vector& buffer) { - usage_entry_number_ = index; - encrypted_usage_entry_ = buffer; ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageEntry(session_id(), index, buffer.data(), buffer.size())); @@ -1816,10 +1820,11 @@ void WriteRequestApiCorpus(size_t signature_length, size_t core_message_length, } // Corpus for request APIs should be signature_length + core_message_length + // data pointer. - AppendToFile(file_name, reinterpret_cast(&signature_length), - sizeof(signature_length)); - AppendToFile(file_name, reinterpret_cast(&core_message_length), - sizeof(core_message_length)); + OEMCrypto_Request_Fuzz request_fuzz_struct; + request_fuzz_struct.core_message_length = core_message_length; + request_fuzz_struct.signature_length = signature_length; + AppendToFile(file_name, reinterpret_cast(&request_fuzz_struct), + sizeof(OEMCrypto_Request_Fuzz)); AppendToFile(file_name, reinterpret_cast(data.data()), data.size()); } diff --git a/oemcrypto/test/oec_session_util.h b/oemcrypto/test/oec_session_util.h index 38766cf..d8c8c9d 100644 --- a/oemcrypto/test/oec_session_util.h +++ b/oemcrypto/test/oec_session_util.h @@ -54,13 +54,6 @@ constexpr int32_t kTimeTolerance = 3 * kSpeedMultiplier; constexpr int64_t kUsageTableTimeTolerance = 10 * kSpeedMultiplier; } // namespace -typedef struct { - uint8_t verification[4]; - uint32_t duration; - uint32_t nonce; - uint32_t control_bits; -} KeyControlBlock; - // Note: The API does not specify a maximum key id length. We specify a // maximum just for these tests, so that we have a fixed message size. constexpr size_t kTestKeyIdMaxLength = 16; @@ -117,7 +110,7 @@ struct EntitledContentKeyData { }; // returns 1 on success, -1 if not supported, or 0 if other failure. -int GetRandBytes(unsigned char* buf, int num); +int GetRandBytes(unsigned char* buf, size_t num); void GenerateSimpleSampleDescription(const std::vector& in, std::vector& out, @@ -218,7 +211,7 @@ class RoundTrip { } protected: - // Returns true if the a nonce should be generated before signing the request. + // Returns true if a nonce should be generated before signing the request. virtual bool RequestHasNonce() = 0; // ---------------------------------------------------------------------- @@ -542,10 +535,10 @@ class Session { // Encrypt some data and pass to OEMCrypto_DecryptCENC to verify decryption. void TestDecryptCTR(bool select_key_first = true, OEMCryptoResult expected_result = OEMCrypto_SUCCESS, - int key_index = 0); + size_t key_index = 0); // Verify that an attempt to select an expired key either succeeds, or gives // an actionable error code. - void TestSelectExpired(unsigned int key_index); + void TestSelectExpired(size_t key_index); // Calls OEMCrypto_GetOEMPublicCertificate and OEMCrypto_LoadOEMPrivateKey and // loads the OEM cert's public rsa key into public_rsa_. void LoadOEMCert(bool verify_cert = false); @@ -610,7 +603,7 @@ class Session { // order to verify signatures. void GenerateReport(const std::string& pst, OEMCryptoResult expected_result = OEMCrypto_SUCCESS, - Session* other = 0); + Session* other = nullptr); // Move this usage entry to a new index. void MoveUsageEntry(uint32_t new_index, std::vector* header_buffer, OEMCryptoResult expect_result = OEMCrypto_SUCCESS); diff --git a/oemcrypto/test/oec_test_data.h b/oemcrypto/test/oec_test_data.h index fbd202d..453847b 100644 --- a/oemcrypto/test/oec_test_data.h +++ b/oemcrypto/test/oec_test_data.h @@ -18,6 +18,7 @@ namespace wvoec { // This is a test keybox. It will not be accepted by production systems. By // using a known keybox for these tests, the results for a given set of inputs // to a test are predictable and can be compared to the actual results. +// clang-format off static const WidevineKeybox kTestKeybox = { // Sample keybox used for test vectors { @@ -49,6 +50,43 @@ static const WidevineKeybox kTestKeybox = { 0x39, 0xf2, 0x94, 0xa7, } }; +// clang-format on + +// This test keybox is only accepted by the QA provisioning server. +// It is not valid with the production provisioning server. +// clang-format off +static const WidevineKeybox kQATestKeybox = { + // Sample keybox used for test vectors + { + // deviceID = WidevineQATestOnlyKeybox000 + 0x57, 0x69, 0x64, 0x65, 0x76, 0x69, 0x6e, 0x65, + 0x51, 0x41, 0x54, 0x65, 0x73, 0x74, 0x4f, 0x6e, + 0x6c, 0x79, 0x4b, 0x65, 0x79, 0x62, 0x6f, 0x78, + 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + }, { + // key + 0x03, 0x77, 0x0f, 0x4e, 0x29, 0x77, 0x4b, 0x43, + 0x9e, 0xd2, 0x8a, 0x94, 0x73, 0xb3, 0x26, 0x65, + }, { + // data (system ID 2000000 = 0x1E8480). + 0x00, 0x00, 0x00, 0x02, 0x00, 0x1e, 0x84, 0x80, + 0x90, 0x46, 0x8a, 0x1d, 0x27, 0x52, 0xca, 0xdb, + 0x5b, 0xf4, 0x67, 0xcb, 0xd3, 0x5e, 0x9e, 0xe9, + 0xb1, 0xcf, 0x89, 0x74, 0x08, 0x26, 0x96, 0x5b, + 0x43, 0x02, 0x7c, 0xb6, 0x4a, 0x9d, 0xf6, 0x7e, + 0x24, 0x82, 0x1d, 0xe2, 0x89, 0x52, 0x8e, 0xac, + 0xf2, 0x98, 0xac, 0x92, 0xa9, 0x40, 0x11, 0x9f, + 0x9f, 0xf8, 0x55, 0x84, 0x42, 0x04, 0x34, 0xbc, + 0x53, 0x14, 0x3d, 0x44, 0x97, 0x5c, 0xd9, 0xb4, + }, { + // magic + 0x6b, 0x62, 0x6f, 0x78, + }, { + // Crc + 0x43, 0xa2, 0x67, 0x63, + } +}; +// clang-format on // A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format // Used to verify the functions that manipulate RSA keys. diff --git a/oemcrypto/test/oemcrypto_serialization_version_test.cpp b/oemcrypto/test/oemcrypto_serialization_version_test.cpp new file mode 100644 index 0000000..31bfacb --- /dev/null +++ b/oemcrypto/test/oemcrypto_serialization_version_test.cpp @@ -0,0 +1,107 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. +// + +#include + +#include + +#include "OEMCryptoCENC.h" +#include "log.h" +#include "oec_test_data.h" + +using namespace std; + +namespace wvoec { + +class OEMCryptoTest : public ::testing::Test { + protected: + OEMCryptoTest() {} + + void SetUp() override { + ::testing::Test::SetUp(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } + + void TearDown() override { + OEMCrypto_Terminate(); + ::testing::Test::TearDown(); + } +}; + +TEST_F(OEMCryptoTest, OPK_SerializationVersion) { + uint32_t ree_major = 0; + uint32_t ree_minor = 0; + uint32_t tee_major = 0; + uint32_t tee_minor = 0; + OEMCryptoResult sts = OEMCrypto_OPK_SerializationVersion( + &ree_major, &ree_minor, &tee_major, &tee_minor); + if (sts != OEMCrypto_ERROR_NOT_IMPLEMENTED) { + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + cout << "OPK REE serialization version is " << ree_major << "." << ree_minor + << "\n"; + cout << "OPK TEE serialization version is " << tee_major << "." << tee_minor + << "\n"; + EXPECT_NE(ree_major, 0u); + EXPECT_NE(tee_major, 0u); + + const uint32_t orig_ree_major = ree_major; + const uint32_t orig_ree_minor = ree_minor; + const uint32_t orig_tee_major = tee_major; + const uint32_t orig_tee_minor = tee_minor; + + /* test requiring a specific version, should create incompatibility */ + ree_major = 100; + ree_minor = 1; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OPK_ERROR_INCOMPATIBLE_VERSION, sts); + EXPECT_EQ(ree_major, 100u); + EXPECT_EQ(ree_minor, 1u); + + /* now OEMCrypto_Initialize should fail with incompatible version */ + OEMCrypto_Terminate(); + EXPECT_EQ(OPK_ERROR_INCOMPATIBLE_VERSION, OEMCrypto_Initialize()); + + /* restore the default versions */ + ree_major = 0; + ree_minor = 0; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(ree_major, orig_ree_major); + EXPECT_EQ(ree_minor, orig_ree_minor); + EXPECT_EQ(tee_major, orig_tee_major); + EXPECT_EQ(tee_minor, orig_tee_minor); + + /* OEMCrypto_Initialize should work now */ + OEMCrypto_Terminate(); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + + /* changing minor version shouldn't create incompatibility */ + ree_minor++; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(ree_minor, orig_ree_minor + 1); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + + /* OEMCrypto_Initialize should still work */ + OEMCrypto_Terminate(); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + + /* remove the REE version override so subsequent tests work */ + ree_major = 0; + ree_minor = 0; + sts = OEMCrypto_OPK_SerializationVersion(&ree_major, &ree_minor, &tee_major, + &tee_minor); + EXPECT_EQ(OEMCrypto_SUCCESS, sts); + EXPECT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } +} + +} // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_test.cpp b/oemcrypto/test/oemcrypto_test.cpp index 10d4fa0..1e82258 100644 --- a/oemcrypto/test/oemcrypto_test.cpp +++ b/oemcrypto/test/oemcrypto_test.cpp @@ -53,6 +53,8 @@ #include "oec_extra_test_keys.h" #include "oec_session_util.h" #include "oec_test_data.h" +#include "oemcrypto_corpus_generator_helper.h" +#include "oemcrypto_fuzz_structs.h" #include "oemcrypto_session_tests_helper.h" #include "oemcrypto_types.h" #include "platform.h" @@ -217,6 +219,29 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { } return &(*pos); } + + OEMCryptoResult CopyBuffer( + OEMCrypto_SESSION session, OEMCrypto_SharedMemory* input_buffer, + size_t input_buffer_size, + const OEMCrypto_DestBufferDesc* dest_buffer_descriptor, + uint8_t subsample_flags) { + if (ShouldGenerateCorpus() && input_buffer != nullptr && + dest_buffer_descriptor != nullptr) { + OEMCrypto_Copy_Buffer_Fuzz fuzzed_structure; + fuzzed_structure.dest_buffer_desc = *dest_buffer_descriptor; + fuzzed_structure.subsample_flags = subsample_flags; + const std::string file_name = + GetFileName("oemcrypto_copy_buffer_fuzz_seed_corpus"); + // Corpus for copy buffer fuzzer should be in the format: + // (dest_buffer_descriptor | subsample_flags | input_buffer). + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(&input_buffer), + input_buffer_size); + } + return OEMCrypto_CopyBuffer(session, input_buffer, input_buffer_size, + dest_buffer_descriptor, subsample_flags); + } }; TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { @@ -240,7 +265,7 @@ TEST_F(OEMCryptoClientTest, FreeUnallocatedSecureBufferNoFailure) { */ TEST_F(OEMCryptoClientTest, VersionNumber) { const std::string log_message = - "OEMCrypto unit tests for API 16.3 or 4. Tests last updated 2021-12-01"; + "OEMCrypto unit tests for API 16.3 or 4. Tests last updated 2022-02-18"; cout << " " << log_message << "\n"; cout << " " << "These tests are part of Android S." @@ -441,7 +466,7 @@ TEST_F(OEMCryptoClientTest, CheckSRMCapabilityV13) { OEMCrypto_LoadSRM(bad_srm.data(), bad_srm.size())); } -TEST_F(OEMCryptoClientTest, OEMCryptoMemoryLoadSrmForLargeSrm) { +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryLoadSrmHugeLargeSrm) { auto oemcrypto_function = [](size_t buffer_length) { vector srm_buffer(buffer_length); return OEMCrypto_LoadSRM(srm_buffer.data(), srm_buffer.size()); @@ -482,7 +507,7 @@ TEST_F(OEMCryptoClientTest, NormalInitTermination) { } // Test that set sandbox doesn't crash for a large sandbox id leangth. -TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForLargeSandboxIdLength) { +TEST_F(OEMCryptoClientTest, OEMCryptoMemorySetSandboxForHugeSandboxIdLength) { auto oemcrypto_function = [](size_t buffer_length) { vector buffer(buffer_length); return OEMCrypto_SetSandbox(buffer.data(), buffer.size()); @@ -581,7 +606,7 @@ TEST_F(OEMCryptoClientTest, GetRandomLargeBuffer) { } // Verify that GetRandom doesn't crash for large input lengths. -TEST_F(OEMCryptoClientTest, OEMCryptoMemoryGetRandomForLargeBuffer) { +TEST_F(OEMCryptoClientTest, OEMCryptoMemoryGetRandomForHugeBuffer) { auto oemcrypto_function = [](size_t buffer_length) { vector buffer(buffer_length); // TODO(ellurubharath, fredgc): Need to re-evaluate this on a real device @@ -610,6 +635,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood2API16) { ASSERT_NO_FATAL_FAILURE(s.open()); s.GenerateNonce(&error_counter); } + wvcdm::TestSleep::SyncFakeClock(); const int64_t test_end = wvcdm::Clock().GetCurrentTime(); int valid_counter = loop_count - error_counter; // Either oemcrypto should enforce a delay, or it should return an error from @@ -647,6 +673,7 @@ TEST_F(OEMCryptoClientTest, PreventNonceFlood3API16) { s[j].GenerateNonce(&error_counter); } } + wvcdm::TestSleep::SyncFakeClock(); const int64_t test_end = wvcdm::Clock().GetCurrentTime(); int valid_counter = request_counter - error_counter; // Either oemcrypto should enforce a delay, or it should return an error from @@ -675,34 +702,30 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestAPI10) { dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size(); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_EQ(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(input_buffer, output_buffer); - ASSERT_EQ( - OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer(s.session_id(), nullptr, input_buffer.size(), - &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer( - s.session_id(), input_buffer.data(), input_buffer.size(), - nullptr, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); - dest_buffer_descriptor.buffer.clear.address = nullptr; + CopyBuffer(s.session_id(), nullptr, input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ( OEMCrypto_ERROR_INVALID_CONTEXT, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + nullptr, OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + dest_buffer_descriptor.buffer.clear.address = nullptr; + ASSERT_EQ(OEMCrypto_ERROR_INVALID_CONTEXT, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size() - 1; - ASSERT_NE( - OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_NE(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); } // This verifies that CopyBuffer works on the maximum required buffer size. @@ -717,11 +740,10 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestLargeSubsample) { dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size(); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_CopyBuffer(s.session_id(), input_buffer.data(), - input_buffer.size(), &dest_buffer_descriptor, - OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); + ASSERT_EQ(OEMCrypto_SUCCESS, + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, + OEMCrypto_FirstSubsample | OEMCrypto_LastSubsample)); ASSERT_EQ(input_buffer, output_buffer); } @@ -846,9 +868,9 @@ TEST_F(OEMCryptoClientTest, ClearCopyTestInvalidSubsampleFlag) { dest_buffer_descriptor.type = OEMCrypto_BufferType_Clear; dest_buffer_descriptor.buffer.clear.address = output_buffer.data(); dest_buffer_descriptor.buffer.clear.address_length = output_buffer.size(); - ASSERT_NO_FATAL_FAILURE(OEMCrypto_CopyBuffer( - s.session_id(), input_buffer.data(), input_buffer.size(), - &dest_buffer_descriptor, oemcrypto_invalid_subsample_flag)); + ASSERT_NO_FATAL_FAILURE( + CopyBuffer(s.session_id(), input_buffer.data(), input_buffer.size(), + &dest_buffer_descriptor, oemcrypto_invalid_subsample_flag)); } TEST_F(OEMCryptoClientTest, CanLoadTestKeys) { @@ -979,7 +1001,7 @@ TEST_F(OEMCryptoKeyboxTest, NormalGetKeyData) { ASSERT_EQ(OEMCrypto_SUCCESS, sts); } -TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForLargeIdLength) { +TEST_F(OEMCryptoKeyboxTest, OEMCryptoMemoryGetKeyIdForHugeIdLength) { auto oemcrypto_function = [](size_t input_length) { size_t key_data_length = input_length; vector key_data(key_data_length); @@ -1020,7 +1042,7 @@ TEST_F(OEMCryptoKeyboxTest, GenerateDerivedKeysFromKeyboxLargeBuffer) { } TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryGenerateDerivedKeysForLargeMacContextLength) { + OEMCryptoMemoryGenerateDerivedKeysForHugeMacContextLength) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); vector mac_context; @@ -1038,7 +1060,7 @@ TEST_F(OEMCryptoKeyboxTest, } TEST_F(OEMCryptoKeyboxTest, - OEMCryptoMemoryGenerateDerivedKeysForLargeEncContextLength) { + OEMCryptoMemoryGenerateDerivedKeysForHugeEncContextLength) { Session s; ASSERT_NO_FATAL_FAILURE(s.open()); vector mac_context; @@ -1165,7 +1187,7 @@ TEST_F(OEMCryptoProv30Test, GetCertOnlyAPI16) { ASSERT_EQ(OEMCrypto_SUCCESS, license_messages.LoadResponse()); } -TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForLargeCertLength) { +TEST_F(OEMCryptoProv30Test, OEMCryptoMemoryGetOEMPublicCertForHugeCertLength) { if (wrapped_rsa_key_.size() == 0) { // If we don't have a wrapped key yet, create one. // This wrapped key will be shared by all sessions in the test. @@ -1250,59 +1272,6 @@ class OEMCryptoSessionTests : public OEMCryptoClientTest { license_messages.EncryptAndSignResponse(); return license_messages.LoadResponse(); } - - void TestLoadLicenseForHugeBufferLengths( - const std::function f, bool check_status, - bool update_core_message_substring_values) { - auto oemcrypto_function = [&](size_t message_length) { - Session s; - LicenseRoundTrip license_messages(&s); - s.open(); - InstallTestRSAKey(&s); - bool verify_keys_loaded = true; - license_messages.SignAndVerifyRequest(); - license_messages.CreateDefaultResponse(); - if (update_core_message_substring_values) { - // Make the license message big enough so that updated core message - // substring offset and length values from tests are still able to read - // data from license_message buffer rather than reading some garbage - // data. - license_messages.set_message_size( - sizeof(license_messages.response_data()) + message_length); - } - f(message_length, &license_messages); - if (update_core_message_substring_values) { - // We will be updating offset for these tests, which will cause verify - // keys to fail with an assertion. Hence skipping verification. - verify_keys_loaded = false; - } - license_messages.EncryptAndSignResponse(); - OEMCryptoResult result = - license_messages.LoadResponse(&s, verify_keys_loaded); - s.close(); - return result; - }; - TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); - } - - void TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( - const std::function f) { - Session s; - LicenseRoundTrip license_messages(&s); - s.open(); - InstallTestRSAKey(&s); - license_messages.SignAndVerifyRequest(); - license_messages.CreateDefaultResponse(); - size_t message_length = sizeof(license_messages.response_data()); - f(message_length, &license_messages); - license_messages.EncryptAndSignResponse(); - OEMCryptoResult result = license_messages.LoadResponse(); - s.close(); - // Verifying error is not due to signature failure which can be caused due - // to test code. - ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); - ASSERT_NE(OEMCrypto_SUCCESS, result); - } }; TEST_F(OEMCryptoSessionTests, @@ -1376,6 +1345,77 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus); } +class OEMCryptoLicenseOverflowTest : public OEMCryptoSessionTests, + public WithParamInterface { + public: + OEMCryptoLicenseOverflowTest() : license_api_version_(kCurrentAPI) {} + + void SetUp() override { + OEMCryptoSessionTests::SetUp(); + license_api_version_ = GetParam(); + } + + void TearDown() override { OEMCryptoSessionTests::TearDown(); } + + void TestLoadLicenseForHugeBufferLengths( + const std::function f, bool check_status, + bool update_core_message_substring_values) { + auto oemcrypto_function = [&](size_t message_length) { + Session s; + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + s.open(); + InstallTestRSAKey(&s); + bool verify_keys_loaded = true; + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + if (update_core_message_substring_values) { + // Make the license message big enough so that updated core message + // substring offset and length values from tests are still able to read + // data from license_message buffer rather than reading some garbage + // data. + license_messages.set_message_size( + sizeof(license_messages.response_data()) + message_length); + } + f(message_length, &license_messages); + if (update_core_message_substring_values) { + // We will be updating offset for these tests, which will cause verify + // keys to fail with an assertion. Hence skipping verification. + verify_keys_loaded = false; + } + license_messages.EncryptAndSignResponse(); + OEMCryptoResult result = + license_messages.LoadResponse(&s, verify_keys_loaded); + s.close(); + return result; + }; + TestHugeLengthDoesNotCrashAPI(oemcrypto_function, check_status); + } + + void TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( + const std::function f) { + Session s; + LicenseRoundTrip license_messages(&s); + license_messages.set_api_version(license_api_version_); + s.open(); + InstallTestRSAKey(&s); + license_messages.SignAndVerifyRequest(); + license_messages.CreateDefaultResponse(); + size_t message_length = sizeof(license_messages.response_data()); + OEMCryptoResult result = license_messages.LoadResponse(); + f(message_length, &license_messages); + license_messages.EncryptAndSignResponse(); + s.close(); + // Verifying error is not due to signature failure which can be caused due + // to test code. + ASSERT_NE(OEMCrypto_ERROR_SIGNATURE_FAILURE, result); + ASSERT_NE(OEMCrypto_SUCCESS, result); + } + + protected: + uint32_t license_api_version_; +}; + // This class is for testing a single license with the default API version // of 16. Used for buffer overflow tests. class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { @@ -1408,7 +1448,7 @@ class OEMCryptoMemoryLicenseTest : public OEMCryptoLicenseTestAPI16 { EntitledMessage entitled_message_; size_t entitlement_response_length_; - void TestLoadEntitlementKeysForHugeBufferLengths( + void TestLoadEntitledKeysForHugeBufferLengths( const std::function f, bool check_status) { size_t entitled_key_data_size = entitled_message_.entitled_key_data_size(); @@ -1667,7 +1707,7 @@ TEST_P(OEMCryptoLicenseTest, LoadKeyWithNonceTwiceAPI16) { } // This verifies that entitlement keys and entitled content keys can be loaded. -TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysAPI14) { +TEST_P(OEMCryptoLicenseTest, LoadEntitledKeysAPI14) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); @@ -1683,7 +1723,7 @@ TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysAPI14) { // This verifies that entitled content keys cannot be loaded if we have not yet // loaded the entitlement keys. -TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysNoEntitlementKeysAPI14) { +TEST_P(OEMCryptoLicenseTest, LoadEntitledKeysNoEntitlementKeysAPI14) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); @@ -1696,7 +1736,7 @@ TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysNoEntitlementKeysAPI14) { // This verifies that entitled content keys cannot be loaded if we have loaded // the wrong entitlement keys. -TEST_P(OEMCryptoLicenseTest, LoadEntitlementKeysWrongEntitlementKeysAPI14) { +TEST_P(OEMCryptoLicenseTest, LoadEntitledKeysWrongEntitlementKeysAPI14) { license_messages_.set_license_type(OEMCrypto_EntitlementLicense); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); @@ -1742,8 +1782,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_id.length = key_id_length; @@ -1752,8 +1792,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyIdOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_id.offset = key_id_offset; @@ -1763,7 +1803,7 @@ TEST_F(OEMCryptoMemoryLicenseTest, TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdLength) { auto& content_key_id = entitled_message_.entitled_key_array()[0].content_key_id; content_key_id.length = @@ -1773,7 +1813,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyIdOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyIdOffset) { auto& content_key_id = entitled_message_.entitled_key_array()[0].content_key_id; content_key_id.offset = @@ -1781,10 +1821,9 @@ TEST_F( ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].entitlement_key_id.length = key_id_length; @@ -1792,10 +1831,9 @@ TEST_F( !kCheckStatus); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringEntitlementKeyIdOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringEntitlementKeyIdOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].entitlement_key_id.offset = key_id_offset; @@ -1805,7 +1843,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdLength) { auto& entitlement_key_id = entitled_message_.entitled_key_array()[0].entitlement_key_id; entitlement_key_id.length = @@ -1815,7 +1853,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringEntitlementKeyIdOffset) { auto& entitlement_key_id = entitled_message_.entitled_key_array()[0].entitlement_key_id; entitlement_key_id.offset = @@ -1823,10 +1861,9 @@ TEST_F( ASSERT_NE(OEMCrypto_SUCCESS, entitled_message_.LoadKeys()); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvLength) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_iv_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data_iv.length = content_key_data_iv_length; @@ -1834,10 +1871,9 @@ TEST_F( !kCheckStatus); } -TEST_F( - OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataIvOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( +TEST_F(OEMCryptoMemoryLicenseTest, + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataIvOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_iv_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data_iv.offset = content_key_data_iv_offset; @@ -1847,7 +1883,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvLength) { auto& content_key_data_iv = entitled_message_.entitled_key_array()[0].content_key_data_iv; content_key_data_iv.length = @@ -1857,7 +1893,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataIvOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataIvOffset) { auto& content_key_data_iv = entitled_message_.entitled_key_array()[0].content_key_data_iv; content_key_data_iv.offset = @@ -1866,8 +1902,8 @@ TEST_F( } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data.length = content_key_data_length; @@ -1876,8 +1912,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeSubstringContentKeyDataOffset) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeSubstringContentKeyDataOffset) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t content_key_data_offset, EntitledMessage* entitled_message) { entitled_message->entitled_key_array()[0].content_key_data.offset = content_key_data_offset; @@ -1887,7 +1923,7 @@ TEST_F(OEMCryptoMemoryLicenseTest, TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataLength) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataLength) { auto& content_key_data = entitled_message_.entitled_key_array()[0].content_key_data; content_key_data.length = @@ -1897,7 +1933,7 @@ TEST_F( TEST_F( OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForOutOfRangeSubstringContentKeyDataOffset) { + OEMCryptoMemoryLoadEntitledKeysForOutOfRangeSubstringContentKeyDataOffset) { auto& content_key_data = entitled_message_.entitled_key_array()[0].content_key_data; content_key_data.offset = @@ -1906,8 +1942,8 @@ TEST_F( } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeEntitlementKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeEntitlementKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_data()->entitlement_key_id_length = key_id_length; @@ -1916,8 +1952,8 @@ TEST_F(OEMCryptoMemoryLicenseTest, } TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeContentKeyIdLength) { - TestLoadEntitlementKeysForHugeBufferLengths( + OEMCryptoMemoryLoadEntitledKeysForHugeContentKeyIdLength) { + TestLoadEntitledKeysForHugeBufferLengths( [](size_t key_id_length, EntitledMessage* entitled_message) { entitled_message->entitled_key_data()->content_key_id_length = key_id_length; @@ -1928,7 +1964,7 @@ TEST_F(OEMCryptoMemoryLicenseTest, // This verifies that entitled content keys API does not crash for unreasonable // input message buffer lengths. TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryLoadEntitlementKeysForHugeBufferLength) { + OEMCryptoMemoryLoadEntitledKeysForHugeBufferLength) { auto oemcrypto_function = [&](size_t buffer_length) { size_t entitled_key_data_length = entitled_message_.entitled_key_data_size(); @@ -2295,8 +2331,8 @@ TEST_P(OEMCryptoLicenseTestRangeAPI, LoadKeys) { // Range of API versions to test. This should start several versions old, and // go to the current API + 2. We use +2 because we want to test at least 1 // future API, and the ::testing::Range is not inclusive. -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoLicenseTestRangeAPI, - Range(10, kCurrentAPI + 2)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTestRangeAPI, + Range(10, kCurrentAPI + 2)); TEST_P(OEMCryptoLicenseTest, LoadKeysBadSignatureAPI16) { ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); @@ -2376,7 +2412,7 @@ TEST_P(OEMCryptoLicenseTest, // addition operation. This will result in 1 which will match with input data // length, which causes validation to pass. sub_samples[0].num_bytes_clear = 2; - sub_samples[0].num_bytes_encrypted = 0xFFFFFFFFFFFFFFFF; + sub_samples[0].num_bytes_encrypted = ~0; // Create the pattern description (always 0,0 for CTR) OEMCrypto_CENCEncryptPatternDesc pattern = {0, 0}; @@ -2671,7 +2707,7 @@ TEST_F(OEMCryptoSessionTests, TestHugeLengthDoesNotCrashAPI(oemcrypto_function, !kCheckStatus); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2681,7 +2717,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyIdOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2690,7 +2726,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2699,7 +2735,7 @@ TEST_F(OEMCryptoSessionTests, }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyIdOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2708,7 +2744,7 @@ TEST_F(OEMCryptoSessionTests, }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2718,7 +2754,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataIvOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2728,8 +2764,8 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2739,8 +2775,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataIvOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2750,7 +2786,7 @@ TEST_F( }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2760,7 +2796,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyDataOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2769,8 +2805,8 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2780,8 +2816,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyDataOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2791,8 +2827,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2802,8 +2838,8 @@ TEST_F( !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlIvOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2813,8 +2849,8 @@ TEST_F( !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2825,8 +2861,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlIvOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2837,7 +2873,7 @@ TEST_F( }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2847,7 +2883,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringKeyControlOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2857,8 +2893,8 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2868,8 +2904,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringKeyControlOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2879,7 +2915,7 @@ TEST_F( }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2888,7 +2924,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyIvOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2897,8 +2933,8 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2909,8 +2945,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyIvOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2921,7 +2957,7 @@ TEST_F( }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2930,7 +2966,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringEncMacKeyOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2939,8 +2975,8 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2949,8 +2985,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringEncMacKeyOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2959,7 +2995,7 @@ TEST_F( }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -2968,7 +3004,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringPstOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -2977,7 +3013,7 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2986,7 +3022,7 @@ TEST_F(OEMCryptoSessionTests, }); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringPstOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -2995,8 +3031,8 @@ TEST_F(OEMCryptoSessionTests, }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataLength) { TestLoadLicenseForHugeBufferLengths( [](size_t length, LicenseRoundTrip* license_messages) { @@ -3005,8 +3041,8 @@ TEST_F( !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageSubstringSrmRestrictionDataOffset) { TestLoadLicenseForHugeBufferLengths( [](size_t offset, LicenseRoundTrip* license_messages) { @@ -3015,8 +3051,8 @@ TEST_F( !kCheckStatus, kUpdateCoreMessageSubstringValues); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataLength) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -3027,8 +3063,8 @@ TEST_F( }); } -TEST_F( - OEMCryptoSessionTests, +TEST_P( + OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForOutOfRangeCoreMessageSubstringSrmRestrictionDataOffset) { TestLoadLicenseForOutOfRangeSubStringOffSetAndLengths( [](size_t response_message_length, LicenseRoundTrip* license_messages) { @@ -3039,7 +3075,8 @@ TEST_F( }); } -TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadLicenseForHugeResponseLength) { +TEST_P(OEMCryptoLicenseOverflowTest, + OEMCryptoMemoryLoadLicenseForHugeResponseLength) { TestLoadLicenseForHugeBufferLengths( [](size_t message_size, LicenseRoundTrip* license_messages) { license_messages->set_message_size(message_size); @@ -3047,7 +3084,7 @@ TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadLicenseForHugeResponseLength) { !kCheckStatus, !kUpdateCoreMessageSubstringValues); } -TEST_F(OEMCryptoSessionTests, +TEST_P(OEMCryptoLicenseOverflowTest, OEMCryptoMemoryLoadLicenseForHugeCoreMessageLength) { TestLoadLicenseForHugeBufferLengths( [](size_t message_size, LicenseRoundTrip* license_messages) { @@ -3056,6 +3093,9 @@ TEST_F(OEMCryptoSessionTests, !kCheckStatus, !kUpdateCoreMessageSubstringValues); } +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseOverflowTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); + TEST_F(OEMCryptoSessionTests, OEMCryptoMemoryLoadRenewalForHugeResponseLength) { auto oemcrypto_function = [&](size_t message_size) { Session s; @@ -3187,7 +3227,7 @@ TEST_P(OEMCryptoLicenseTest, AntiRollbackHardwareRequired) { TEST_P(OEMCryptoLicenseTest, MinimumKeys) { const size_t num_keys = GetResourceValue(kMaxKeysPerSession); ASSERT_LE(num_keys, kMaxNumKeys) << "Test constants need updating."; - license_messages_.set_num_keys(num_keys); + license_messages_.set_num_keys(static_cast(num_keys)); ASSERT_NO_FATAL_FAILURE(license_messages_.SignAndVerifyRequest()); ASSERT_NO_FATAL_FAILURE(license_messages_.CreateDefaultResponse()); ASSERT_NO_FATAL_FAILURE(license_messages_.EncryptAndSignResponse()); @@ -3214,7 +3254,7 @@ void TestMaxKeys(SessionUtil* util, size_t num_keys_per_session) { new LicenseRoundTrip(sessions[i].get()))); const size_t num_keys = std::min(max_total_keys - total_keys, num_keys_per_session); - licenses[i]->set_num_keys(num_keys); + licenses[i]->set_num_keys(static_cast(num_keys)); total_keys += num_keys; ASSERT_NO_FATAL_FAILURE(sessions[i]->open()); ASSERT_NO_FATAL_FAILURE(util->InstallTestRSAKey(sessions[i].get())); @@ -3358,8 +3398,8 @@ TEST_P(OEMCryptoSessionTestDecryptWithHDCP, DecryptAPI09) { // Test parameterized by HDCP version. DecryptWithHDCP(static_cast(GetParam())); } -INSTANTIATE_TEST_CASE_P(TestHDCP, OEMCryptoSessionTestDecryptWithHDCP, - Range(1, 6)); +INSTANTIATE_TEST_SUITE_P(TestHDCP, OEMCryptoSessionTestDecryptWithHDCP, + Range(1, 6)); /// @} @@ -3512,12 +3552,12 @@ TEST_P(OEMCryptoRefreshTest, RefreshWithNoSelectKey) { ASSERT_NO_FATAL_FAILURE(session_.TestDecryptCTR(false)); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoRefreshTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoRefreshTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); // These tests only work when the license has a core message. -INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoRefreshTestAPI16, - Range(kCoreMessagesAPI, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoRefreshTestAPI16, + Range(kCoreMessagesAPI, kCurrentAPI + 1)); // If the license does not allow a hash, then we should not compute one. TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { @@ -3547,7 +3587,7 @@ TEST_P(OEMCryptoLicenseTest, HashForbiddenAPI15) { // This test verifies that OEMCrypto_SetDecryptHash doesn't crash for a very // large hash buffer. TEST_F(OEMCryptoMemoryLicenseTest, - OEMCryptoMemoryDecryptHashForLargeHashBuffer) { + OEMCryptoMemoryDecryptHashForHugeHashBuffer) { uint32_t session_id = session_.session_id(); auto f = [session_id](size_t hash_length) { uint32_t frame_number = 1; @@ -4309,13 +4349,13 @@ constexpr OEMCrypto_CENCEncryptPatternDesc MakePattern(size_t encrypt, return {encrypt, skip}; } -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CTRTests, OEMCryptoSessionTestsDecryptTests, Combine(Values(MakePattern(0, 0)), Values(OEMCrypto_CipherMode_CTR), ::testing::ValuesIn(global_features.GetOutputTypes()))); // Decrypt in place for CBC tests was only required in v13. -INSTANTIATE_TEST_CASE_P( +INSTANTIATE_TEST_SUITE_P( CBCTestsAPI14, OEMCryptoSessionTestsDecryptTests, Combine( Values(MakePattern(3, 7), MakePattern(9, 1), @@ -4357,8 +4397,8 @@ TEST_P(OEMCryptoLicenseTest, KeyDuration) { ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(0)); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoLicenseTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoLicenseTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); // // Certificate Root of Trust Tests @@ -5126,6 +5166,21 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) { &signature_length, kSign_RSASSA_PSS); ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, sts); ASSERT_NE(static_cast(0), signature_length); + + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generate_rsa_signature_fuzz_seed_corpus"); + OEMCrypto_Generate_RSA_Signature_Fuzz fuzzed_structure; + fuzzed_structure.padding_scheme = kSign_RSASSA_PSS; + fuzzed_structure.signature_length = signature_length; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, + reinterpret_cast(licenseRequest.data()), + licenseRequest.size()); + } + uint8_t* signature = new uint8_t[signature_length]; sts = OEMCrypto_GenerateRSASignature(s.session_id(), licenseRequest.data(), licenseRequest.size(), signature, @@ -5398,7 +5453,7 @@ class OEMCryptoLoadsCertificateAlternates : public OEMCryptoLoadsCertificate { }; TEST_F(OEMCryptoLoadsCertificateAlternates, - OEMCryptoMemoryGenerateRSASignatureForLargeBuffer) { + OEMCryptoMemoryGenerateRSASignatureForHugeBuffer) { OEMCryptoResult sts; LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); // If the device is a cast receiver, then this scheme is required. @@ -5434,7 +5489,7 @@ TEST_F(OEMCryptoLoadsCertificateAlternates, } TEST_F(OEMCryptoLoadsCertificateAlternates, - OEMCryptoMemoryGenerateRSASignatureForLargeSignatureLength) { + OEMCryptoMemoryGenerateRSASignatureForHugeSignatureLength) { OEMCryptoResult sts; LoadWithAllowedSchemes(kSign_PKCS1_Block1, false); // If the device is a cast receiver, then this scheme is required. @@ -6482,6 +6537,100 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { in_buffer.size(), signature->data(), &md_len); } + OEMCryptoResult GenericEncrypt(OEMCrypto_SESSION session, + const uint8_t* clear_buffer, + size_t clear_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_encrypt_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CTR; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(iv), + wvoec::KEY_IV_SIZE); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Encrypt(session, clear_buffer, clear_buffer_length, + iv, algorithm, out_buffer); + } + + OEMCryptoResult GenericDecrypt(OEMCrypto_SESSION session, + const uint8_t* encrypted_buffer, + size_t encrypted_buffer_length, + const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + uint8_t* out_buffer) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_decrypt_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CTR; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(iv), + wvoec::KEY_IV_SIZE); + AppendSeparator(file_name); + AppendToFile(file_name, reinterpret_cast(encrypted_buffer), + encrypted_buffer_length); + } + return OEMCrypto_Generic_Decrypt(session, encrypted_buffer, + encrypted_buffer_length, iv, algorithm, + out_buffer); + } + + OEMCryptoResult GenericVerify(OEMCrypto_SESSION session, + const uint8_t* clear_buffer, + size_t clear_buffer_length, + OEMCrypto_Algorithm algorithm, + const uint8_t* signature, + size_t signature_length) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_verify_fuzz_seed_corpus"); + OEMCrypto_Generic_Verify_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CTR; + fuzzed_structure.algorithm = algorithm; + fuzzed_structure.signature_length = signature_length; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Verify(session, clear_buffer, clear_buffer_length, + algorithm, signature, signature_length); + } + + OEMCryptoResult GenericSign(OEMCrypto_SESSION session, + const uint8_t* clear_buffer, + size_t clear_buffer_length, + OEMCrypto_Algorithm algorithm, uint8_t* signature, + size_t* signature_length) { + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_generic_sign_fuzz_seed_corpus"); + OEMCrypto_Generic_Api_Fuzz fuzzed_structure; + fuzzed_structure.cipher_mode = OEMCrypto_CipherMode_CTR; + fuzzed_structure.algorithm = algorithm; + // Cipher mode and algorithm. + AppendToFile(file_name, reinterpret_cast(&fuzzed_structure), + sizeof(fuzzed_structure)); + AppendToFile(file_name, reinterpret_cast(clear_buffer), + clear_buffer_length); + } + return OEMCrypto_Generic_Sign(session, clear_buffer, clear_buffer_length, + algorithm, signature, signature_length); + } + // This asks OEMCrypto to encrypt with the specified key, and expects a // failure. void BadEncrypt(unsigned int key_index, OEMCrypto_Algorithm algorithm, @@ -6495,9 +6644,8 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector encrypted(buffer_length); - sts = OEMCrypto_Generic_Encrypt(session_.session_id(), clear_buffer_.data(), - buffer_length, iv_, algorithm, - encrypted.data()); + sts = GenericEncrypt(session_.session_id(), clear_buffer_.data(), + buffer_length, iv_, algorithm, encrypted.data()); EXPECT_NE(OEMCrypto_SUCCESS, sts); expected_encrypted.resize(buffer_length); EXPECT_NE(encrypted, expected_encrypted); @@ -6516,9 +6664,8 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); vector resultant(encrypted.size()); - sts = OEMCrypto_Generic_Decrypt(session_.session_id(), encrypted.data(), - buffer_length, iv_, algorithm, - resultant.data()); + sts = GenericDecrypt(session_.session_id(), encrypted.data(), buffer_length, + iv_, algorithm, resultant.data()); EXPECT_NE(OEMCrypto_SUCCESS, sts); EXPECT_NE(clear_buffer_, resultant); } @@ -6537,9 +6684,9 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { ASSERT_EQ(OEMCrypto_SUCCESS, sts); size_t signature_length = (size_t)SHA256_DIGEST_LENGTH; vector signature(SHA256_DIGEST_LENGTH); - sts = OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), algorithm, - signature.data(), &signature_length); + sts = GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), algorithm, signature.data(), + &signature_length); EXPECT_NE(OEMCrypto_SUCCESS, sts); EXPECT_NE(signature, expected_signature); } @@ -6563,9 +6710,9 @@ class OEMCryptoGenericCryptoTest : public OEMCryptoRefreshTest { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR); ASSERT_EQ(OEMCrypto_SUCCESS, sts); - sts = OEMCrypto_Generic_Verify(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), algorithm, - signature.data(), signature_size); + sts = GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), algorithm, signature.data(), + signature_size); EXPECT_NE(OEMCrypto_SUCCESS, sts); } @@ -6591,11 +6738,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncrypt) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); vector encrypted(clear_buffer_.size()); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); } @@ -6625,10 +6771,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptSameBufferAPI12) { OEMCrypto_CipherMode_CTR)); // Input and output are same buffer: vector buffer = clear_buffer_; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), buffer.data(), buffer.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), buffer.data(), buffer.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); ASSERT_EQ(expected_encrypted, buffer); } @@ -6698,10 +6844,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecrypt) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); } @@ -6742,10 +6888,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptSameBufferAPI12) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); vector buffer = encrypted; - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), buffer.data(), buffer.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), buffer.data(), buffer.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, buffer.data())); ASSERT_EQ(clear_buffer_, buffer); } @@ -6766,10 +6912,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericSecureToClear) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); - ASSERT_NE(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_NE( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_NE(clear_buffer_, resultant); } @@ -6798,15 +6944,15 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySign) { OEMCrypto_CipherMode_CTR)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - nullptr, &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, nullptr, + &gen_signature_length)); ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); vector signature(SHA256_DIGEST_LENGTH); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &gen_signature_length)); ASSERT_EQ(expected_signature, signature); } @@ -6876,10 +7022,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerify) { session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( - session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); } TEST_P(OEMCryptoGenericCryptoTest, @@ -6896,9 +7042,9 @@ TEST_P(OEMCryptoGenericCryptoTest, vector buffer(buffer_length); vector signature; SignBuffer(key_index, buffer, &signature); - return OEMCrypto_Generic_Verify(session_.session_id(), buffer.data(), - buffer.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size()); + return GenericVerify(session_.session_id(), buffer.data(), buffer.size(), + OEMCrypto_HMAC_SHA256, signature.data(), + signature.size()); }; TestHugeLengthDoesNotCrashAPI(oemcrypto_function, kCheckStatus); } @@ -6953,11 +7099,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyEncryptLargeBuffer) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); vector encrypted(clear_buffer_.size()); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); } @@ -6976,10 +7121,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyDecryptLargeBuffer) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); } @@ -6999,15 +7144,15 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeySignLargeBuffer) { OEMCrypto_CipherMode_CTR)); size_t gen_signature_length = 0; ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - nullptr, &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, nullptr, + &gen_signature_length)); ASSERT_EQ(static_cast(SHA256_DIGEST_LENGTH), gen_signature_length); vector signature(SHA256_DIGEST_LENGTH); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &gen_signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &gen_signature_length)); ASSERT_EQ(expected_signature, signature); } @@ -7025,10 +7170,10 @@ TEST_P(OEMCryptoGenericCryptoTest, GenericKeyVerifyLargeBuffer) { session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( - session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); } // Test Generic_Encrypt when the key duration has expired. @@ -7049,11 +7194,10 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationEncrypt) { session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); - ASSERT_EQ( - OEMCrypto_SUCCESS, - OEMCrypto_Generic_Encrypt( - session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), - iv_, OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericEncrypt(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), iv_, + OEMCrypto_AES_CBC_128_NO_PADDING, encrypted.data())); ASSERT_EQ(expected_encrypted, encrypted); wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. @@ -7084,17 +7228,17 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationDecrypt) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); vector resultant(encrypted.size()); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); + ASSERT_EQ( + OEMCrypto_SUCCESS, + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data())); ASSERT_EQ(clear_buffer_, resultant); wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. resultant.assign(encrypted.size(), 0); - OEMCryptoResult status = OEMCrypto_Generic_Decrypt( - session_.session_id(), encrypted.data(), encrypted.size(), iv_, - OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); + OEMCryptoResult status = + GenericDecrypt(session_.session_id(), encrypted.data(), encrypted.size(), + iv_, OEMCrypto_AES_CBC_128_NO_PADDING, resultant.data()); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); ASSERT_NE(clear_buffer_, resultant); ASSERT_NO_FATAL_FAILURE(session_.TestSelectExpired(key_index)); @@ -7121,14 +7265,14 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationSign) { session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_Generic_Sign(session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), &signature_length)); + GenericSign(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), &signature_length)); ASSERT_EQ(expected_signature, signature); wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. signature.assign(SHA256_DIGEST_LENGTH, 0); - OEMCryptoResult status = OEMCrypto_Generic_Sign( + OEMCryptoResult status = GenericSign( session_.session_id(), clear_buffer_.data(), clear_buffer_.size(), OEMCrypto_HMAC_SHA256, signature.data(), &signature_length); ASSERT_EQ(OEMCrypto_ERROR_KEY_EXPIRED, status); @@ -7154,10 +7298,10 @@ TEST_P(OEMCryptoGenericCryptoTest, KeyDurationVerify) { session_.license().keys[key_index].key_id, session_.license().keys[key_index].key_id_length, OEMCrypto_CipherMode_CTR)); - ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Generic_Verify( - session_.session_id(), clear_buffer_.data(), - clear_buffer_.size(), OEMCrypto_HMAC_SHA256, - signature.data(), signature.size())); + ASSERT_EQ(OEMCrypto_SUCCESS, + GenericVerify(session_.session_id(), clear_buffer_.data(), + clear_buffer_.size(), OEMCrypto_HMAC_SHA256, + signature.data(), signature.size())); wvcdm::TestSleep::Sleep(kLongSleep + kShortSleep); // Should be expired key. OEMCryptoResult status = OEMCrypto_Generic_Verify( @@ -7256,11 +7400,11 @@ TEST_P(OEMCryptoGenericCryptoKeyIdLengthTest, UniformLongKeyId) { TestWithKey(2); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoGenericCryptoKeyIdLengthTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); /// @} @@ -7340,6 +7484,11 @@ class LicenseWithUsageEntry { void DeactivateUsageEntry() { active_ = false; + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_deactivate_usage_entry_fuzz_seed_corpus"); + AppendToFile(file_name, pst().c_str(), pst().length()); + } ASSERT_EQ( OEMCrypto_SUCCESS, OEMCrypto_DeactivateUsageEntry( @@ -7414,6 +7563,12 @@ class OEMCryptoUsageTableTest : public OEMCryptoGenericCryptoTest { } while (elapsed_time < total_seconds); cout << endl; } + + OEMCryptoResult LoadUsageTableHeader( + const vector& encrypted_usage_header) { + return OEMCrypto_LoadUsageTableHeader(encrypted_usage_header.data(), + encrypted_usage_header.size()); + } }; TEST_P(OEMCryptoUsageTableTest, @@ -7580,6 +7735,13 @@ TEST_P(OEMCryptoUsageTableTest, OEMCryptoMemoryReportUsageForHugeReportBuffer) { OEMCrypto_ReportUsage(s.session_id(), reinterpret_cast(entry.pst().c_str()), entry.pst().length(), nullptr, &length); + if (ShouldGenerateCorpus()) { + const std::string file_name = + GetFileName("oemcrypto_report_usage_fuzz_seed_corpus"); + AppendToFile(file_name, reinterpret_cast(&length), + sizeof(length)); + AppendToFile(file_name, entry.pst().c_str(), entry.pst().length()); + } vector pst_report_buffer(buffer_length); return OEMCrypto_ReportUsage( s.session_id(), reinterpret_cast(entry.pst().c_str()), @@ -8085,9 +8247,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadOfflineLicenseWithTerminate) { Session& s = entry.session(); ShutDown(); // This calls OEMCrypto_Terminate. Restart(); // This calls OEMCrypto_Initialize. - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(), - encrypted_usage_header_.size())); + ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); ASSERT_NO_FATAL_FAILURE(entry.OpenAndReload(this)); ASSERT_NO_FATAL_FAILURE(s.UpdateUsageEntry(&encrypted_usage_header_)); @@ -8383,9 +8543,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, MoveUsageEntries) { ASSERT_NO_FATAL_FAILURE(ShrinkHeader(3)); ShutDown(); Restart(); - ASSERT_EQ(OEMCrypto_SUCCESS, - OEMCrypto_LoadUsageTableHeader(encrypted_usage_header_.data(), - encrypted_usage_header_.size())); + ASSERT_EQ(OEMCrypto_SUCCESS, LoadUsageTableHeader(encrypted_usage_header_)); wvcdm::TestSleep::SyncFakeClock(); ASSERT_NO_FATAL_FAILURE(ReloadLicense(&entries[0])); // Now has index 1. @@ -8569,7 +8727,7 @@ TEST_P(OEMCryptoUsageTableDefragTest, ManyUsageEntries) { // Shrink the table a little. constexpr size_t small_number = 5; size_t smaller_size = successful_count - small_number; - ASSERT_NO_FATAL_FAILURE(ShrinkHeader(smaller_size)); + ASSERT_NO_FATAL_FAILURE(ShrinkHeader(static_cast(smaller_size))); // Throw out the last license if it was in the part of the table that was // shrunk. if (entries.back()->session().usage_entry_number() >= smaller_size) { @@ -8631,8 +8789,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { // Modified header generates error. vector bad_header = encrypted_usage_header_; bad_header[3] ^= 42; - ASSERT_NE(OEMCrypto_SUCCESS, OEMCrypto_LoadUsageTableHeader( - bad_header.data(), bad_header.size())); + ASSERT_NE(OEMCrypto_SUCCESS, LoadUsageTableHeader(bad_header)); ASSERT_NO_FATAL_FAILURE(s.open()); // Cannot load an entry if header didn't load. ASSERT_EQ(OEMCrypto_ERROR_UNKNOWN_FAILURE, @@ -8643,8 +8800,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { // Old by 2 generation numbers is error. ASSERT_EQ(OEMCrypto_ERROR_GENERATION_SKEW, - OEMCrypto_LoadUsageTableHeader(old_usage_header_2_.data(), - old_usage_header_2_.size())); + LoadUsageTableHeader(old_usage_header_2_)); ASSERT_NO_FATAL_FAILURE(s.open()); // Cannot load an entry if header didn't load. ASSERT_NE(OEMCrypto_SUCCESS, @@ -8655,8 +8811,7 @@ TEST_P(OEMCryptoUsageTableTest, ReloadUsageTableWithSkew) { // Old by 1 generation numbers is just warning. ASSERT_EQ(OEMCrypto_WARNING_GENERATION_SKEW, - OEMCrypto_LoadUsageTableHeader(old_usage_header_1_.data(), - old_usage_header_1_.size())); + LoadUsageTableHeader(old_usage_header_1_)); // Everything else should still work. The old entry goes with the old header. ASSERT_NO_FATAL_FAILURE(s.open()); ASSERT_EQ(OEMCrypto_SUCCESS, @@ -9000,16 +9155,16 @@ TEST_P(OEMCryptoUsageTableTest, PSTLargeBuffer) { ASSERT_NO_FATAL_FAILURE(s.close()); } -INSTANTIATE_TEST_CASE_P(TestAll, OEMCryptoUsageTableTest, - Range(kCurrentAPI - 1, kCurrentAPI + 1)); +INSTANTIATE_TEST_SUITE_P(TestAll, OEMCryptoUsageTableTest, + Range(kCurrentAPI - 1, kCurrentAPI + 1)); // These tests only work when the license has a core message. -INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoUsageTableDefragTest, - Values(kCurrentAPI)); +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableDefragTest, + Values(kCurrentAPI)); // These tests only work when the license has a core message. -INSTANTIATE_TEST_CASE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, - Values(kCurrentAPI)); +INSTANTIATE_TEST_SUITE_P(TestAPI16, OEMCryptoUsageTableTestWallClock, + Values(kCurrentAPI)); /// @} } // namespace wvoec diff --git a/oemcrypto/test/oemcrypto_unittests.gypi b/oemcrypto/test/oemcrypto_unittests.gypi index 9051a11..ec9de14 100644 --- a/oemcrypto/test/oemcrypto_unittests.gypi +++ b/oemcrypto/test/oemcrypto_unittests.gypi @@ -1,10 +1,14 @@ # Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -#source code may only be used and distributed under the Widevine License -#Agreement. +# source code may only be used and distributed under the Widevine License +# Agreement. # # Include this in any custom unit test targets. # Does not include the test runner main. { + 'variables': { + 'test_opk_serialization_version%' : 'false', + 'static_libcpp%' : 'false', + }, 'sources': [ 'oec_device_features.cpp', 'oec_decrypt_fallback_chain.cpp', @@ -15,6 +19,18 @@ 'oemcrypto_test.cpp', 'wvcrc.cpp', ], + 'conditions': [ + ['test_opk_serialization_version=="true"', { + 'sources+' : [ + 'oemcrypto_serialization_version_test.cpp', + ], + }], + ['static_libcpp=="true"', { + 'ldflags+':[ + '-static-libstdc++', + ], + }], + ], 'include_dirs': [ '<(util_dir)/include', '<(util_dir)/test', @@ -27,6 +43,13 @@ 'defines': [ 'OEMCRYPTO_TESTS', ], + 'conditions': [ + ['support_ota_keybox_functions=="true"', { + 'sources': [ + '<(oemcrypto_dir)/test/ota_keybox_test.cpp', + ], + }], + ], 'dependencies': [ '<(oemcrypto_dir)/odk/src/odk.gyp:odk', ], diff --git a/oemcrypto/test/ota_keybox_test.cpp b/oemcrypto/test/ota_keybox_test.cpp new file mode 100644 index 0000000..1ead628 --- /dev/null +++ b/oemcrypto/test/ota_keybox_test.cpp @@ -0,0 +1,300 @@ +// Copyright 2021 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// + +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "arraysize.h" +#include "log.h" +#include "oec_key_deriver.h" +#include "oec_session_util.h" +#include "oec_test_data.h" +#include "oemcrypto_session_tests_helper.h" +#include "oemcrypto_types.h" +#include "platform.h" +#include "string_conversions.h" + +using namespace std; + +namespace wvoec { +namespace { +const std::string kOption2Label = "WV_KB_REPROV_V02"; +constexpr size_t kLabelLength = 16u; +constexpr size_t kDeviceIdLength = 32u; +constexpr size_t kMinimumRequestLength = + kLabelLength // Start with a label. + + kDeviceIdLength // Fixed length device id. + + sizeof(uint32_t) // cert length. + // variable cert length. + + HMAC_SHA256_SIGNATURE_SIZE; // signature. +static const uint8_t TestKeyPKCS8[] = { + 0x30, 0x82, 0x04, 0xbf, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x04, 0xa9, 0x30, 0x82, 0x04, 0xa5, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, + 0x01, 0x00, 0xa6, 0x33, 0x7f, 0x22, 0x05, 0xae, 0xcf, 0xae, 0x29, 0x67, + 0xa9, 0x3a, 0xe7, 0x08, 0xbf, 0x61, 0x92, 0x62, 0x4a, 0xd4, 0x82, 0x37, + 0x4d, 0x08, 0xa1, 0x77, 0x9f, 0x31, 0xa8, 0x92, 0xc5, 0x8b, 0x85, 0x84, + 0x12, 0x66, 0x52, 0xe6, 0x4b, 0x4c, 0xde, 0xdd, 0x43, 0x85, 0x53, 0xd1, + 0x0c, 0x79, 0x2c, 0xcf, 0x38, 0x4b, 0x72, 0x50, 0xf4, 0x34, 0x15, 0x0b, + 0xbe, 0x06, 0xf7, 0x60, 0x66, 0xda, 0xea, 0x40, 0x25, 0x38, 0x3e, 0xeb, + 0x6e, 0x13, 0x1b, 0xd0, 0x04, 0xd9, 0x4a, 0xa0, 0x7c, 0x7a, 0xb8, 0x64, + 0xde, 0xdb, 0x55, 0x93, 0xed, 0xb9, 0x93, 0x89, 0x83, 0x61, 0x2f, 0x23, + 0x15, 0x91, 0x28, 0xd2, 0x7a, 0x02, 0x69, 0x12, 0x70, 0x19, 0xea, 0xfc, + 0x31, 0xd5, 0xdd, 0x85, 0xeb, 0x81, 0x2f, 0xae, 0xb3, 0x48, 0x94, 0xbe, + 0x57, 0x3b, 0xac, 0x0a, 0x4f, 0x9e, 0x24, 0x2e, 0xae, 0x4e, 0x13, 0x53, + 0x34, 0xe1, 0xcd, 0x66, 0xcc, 0xa6, 0x3a, 0x89, 0x8c, 0x43, 0xef, 0x65, + 0xe7, 0x40, 0xc5, 0x09, 0xb8, 0x36, 0xd6, 0xcd, 0x41, 0xdf, 0x29, 0xbb, + 0x23, 0xa2, 0x54, 0xa5, 0x9f, 0x37, 0x6c, 0xbd, 0x8d, 0xd6, 0x8c, 0x33, + 0xa5, 0xd8, 0x4a, 0xc9, 0x08, 0x35, 0x41, 0xfb, 0xb0, 0x8f, 0x74, 0xdc, + 0xbd, 0x35, 0x01, 0x65, 0xe1, 0x06, 0x6d, 0x41, 0xf4, 0x81, 0x4a, 0xfc, + 0xc3, 0xb3, 0x1c, 0xb7, 0x18, 0xdc, 0x29, 0x4e, 0xea, 0x1b, 0x98, 0xd5, + 0x7d, 0x51, 0x60, 0xcd, 0xfd, 0xdb, 0x74, 0x39, 0x43, 0xa7, 0xc7, 0x0d, + 0xe8, 0x8c, 0xd9, 0xc7, 0xb9, 0xdc, 0x42, 0x08, 0x34, 0x43, 0x2f, 0xf2, + 0x5b, 0xb6, 0x3e, 0x6a, 0x37, 0xb9, 0x08, 0x6a, 0xdf, 0x43, 0x32, 0x0e, + 0x38, 0xd3, 0x3a, 0xeb, 0x13, 0x74, 0xd2, 0x02, 0x36, 0xed, 0xa0, 0x7c, + 0xc8, 0x55, 0xc5, 0xbf, 0x58, 0xbd, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, + 0x82, 0x01, 0x01, 0x00, 0x85, 0x0f, 0x93, 0x88, 0x34, 0x8e, 0x89, 0x3d, + 0x01, 0x6f, 0x39, 0xa0, 0xab, 0xd9, 0x68, 0x07, 0x80, 0xff, 0xea, 0xb3, + 0x0a, 0x71, 0xa5, 0xdd, 0xf4, 0x0f, 0xe6, 0x47, 0x06, 0x94, 0x43, 0x4d, + 0xf9, 0x9e, 0x0c, 0x71, 0x19, 0x8b, 0xc0, 0xdb, 0x91, 0x4e, 0x0a, 0x41, + 0xd3, 0x21, 0xf9, 0xdf, 0x85, 0xcd, 0x7d, 0x5f, 0x81, 0xed, 0x68, 0x25, + 0xce, 0x77, 0xb1, 0x32, 0xb8, 0x98, 0xd8, 0xa0, 0x09, 0x8d, 0x43, 0x7f, + 0x2d, 0x78, 0xa5, 0x8e, 0xec, 0xe4, 0x75, 0x0d, 0x56, 0x5e, 0xf8, 0x69, + 0xf3, 0xf8, 0xe6, 0x27, 0x29, 0xf3, 0x9e, 0x0e, 0xc6, 0x1d, 0x01, 0x2f, + 0x2c, 0x62, 0xe5, 0x60, 0x6b, 0x13, 0x5f, 0x95, 0x50, 0x73, 0xef, 0x86, + 0x00, 0x88, 0xda, 0x89, 0x43, 0xaa, 0x75, 0x2a, 0xdf, 0x76, 0xf9, 0x98, + 0x71, 0x65, 0x96, 0x47, 0x72, 0xec, 0x6a, 0x63, 0xcc, 0xca, 0x06, 0xc7, + 0xb6, 0x58, 0x8d, 0x3e, 0x8a, 0x87, 0x4f, 0x5a, 0x5c, 0x1d, 0x82, 0x40, + 0x61, 0x13, 0xed, 0x6d, 0x21, 0x88, 0x1d, 0xb7, 0x70, 0xda, 0xc9, 0x9d, + 0xb2, 0x29, 0x44, 0x0a, 0xf2, 0xdb, 0xaa, 0x1e, 0xdb, 0x0a, 0x92, 0xf8, + 0x42, 0x1d, 0xe6, 0x75, 0x6a, 0xce, 0x2f, 0xd2, 0xea, 0x9d, 0x71, 0x98, + 0x27, 0x0d, 0xf2, 0xc9, 0x60, 0x85, 0x31, 0x88, 0x1c, 0x91, 0x55, 0xe3, + 0xf8, 0x7e, 0xe6, 0xcf, 0x7b, 0x66, 0x27, 0x45, 0x1e, 0xaa, 0x0a, 0x5a, + 0xfe, 0x07, 0x0a, 0x3a, 0xfd, 0x04, 0xdc, 0xae, 0x5a, 0xf3, 0xc5, 0x3d, + 0x18, 0x36, 0x49, 0x97, 0x5c, 0x42, 0xef, 0x9e, 0x4a, 0xcd, 0xa7, 0x23, + 0xca, 0x17, 0xc4, 0x09, 0x55, 0x15, 0xd4, 0x23, 0x7c, 0x19, 0xb2, 0x24, + 0x87, 0x8f, 0x75, 0x70, 0xca, 0xb4, 0x98, 0x33, 0x8a, 0xf2, 0xdd, 0x15, + 0x8d, 0x27, 0x76, 0xe4, 0xbb, 0xbb, 0x23, 0x2d, 0x02, 0x81, 0x81, 0x00, + 0xdc, 0x3b, 0x21, 0x8d, 0xf2, 0x17, 0xff, 0xc1, 0xc6, 0xfb, 0xe2, 0xdb, + 0x29, 0xed, 0x9e, 0xfd, 0xb6, 0xd5, 0xe7, 0x23, 0x29, 0x86, 0xdc, 0x65, + 0xfc, 0x8b, 0x86, 0x39, 0x52, 0x1e, 0xa4, 0x30, 0x72, 0x14, 0x12, 0x24, + 0x72, 0xb4, 0x97, 0x77, 0x61, 0x7c, 0x34, 0x5a, 0x0a, 0x1d, 0x12, 0xfe, + 0xc7, 0x1f, 0x06, 0x79, 0x8c, 0xf5, 0x41, 0xdd, 0x79, 0x8f, 0xeb, 0x17, + 0xf3, 0x32, 0x32, 0x13, 0x37, 0xee, 0x73, 0xeb, 0x82, 0xfa, 0x7b, 0x55, + 0x16, 0xb0, 0x3e, 0x2f, 0x6f, 0xb6, 0xa6, 0x38, 0x99, 0xaf, 0xde, 0xfd, + 0x3a, 0x48, 0xa2, 0x95, 0x70, 0x14, 0x06, 0xf9, 0x10, 0x0f, 0x48, 0x72, + 0x0d, 0x48, 0x69, 0xfc, 0x81, 0xf1, 0x07, 0x5c, 0x99, 0x44, 0xe9, 0x02, + 0xd5, 0x61, 0x36, 0x31, 0x64, 0x02, 0x5a, 0x1d, 0x3e, 0xae, 0xde, 0x08, + 0xd2, 0xde, 0x42, 0xac, 0xf1, 0xe1, 0x38, 0x9f, 0x02, 0x81, 0x81, 0x00, + 0xc1, 0x31, 0xe3, 0x45, 0xec, 0x53, 0xa5, 0x56, 0xe0, 0xc1, 0xe3, 0xf2, + 0xeb, 0xb0, 0xe5, 0x84, 0xdd, 0x56, 0x59, 0x7c, 0xf4, 0x65, 0x66, 0x8c, + 0x9c, 0x66, 0x55, 0x2a, 0x2c, 0x3c, 0x46, 0xf7, 0xac, 0x36, 0xd8, 0x2f, + 0x27, 0x97, 0x57, 0x64, 0x6e, 0xc7, 0x5f, 0x43, 0xf9, 0x82, 0x27, 0xf3, + 0xc4, 0xfa, 0xc6, 0xb1, 0xea, 0x2d, 0xcc, 0x36, 0x3a, 0x37, 0x22, 0xb6, + 0x7e, 0x6a, 0x25, 0xab, 0x1a, 0xd2, 0x3e, 0x38, 0x38, 0x9d, 0x04, 0xc0, + 0xc7, 0x4a, 0xa2, 0x38, 0xb4, 0xcf, 0x9c, 0x97, 0x4c, 0x03, 0x76, 0x37, + 0x86, 0x09, 0x1e, 0x25, 0x2b, 0x67, 0x8e, 0x7b, 0xce, 0x3d, 0x50, 0xf6, + 0x7a, 0x8b, 0x00, 0x23, 0x48, 0xda, 0x6e, 0xbe, 0x4c, 0x23, 0xdb, 0x9c, + 0x4f, 0x3f, 0xa9, 0x18, 0x59, 0xf6, 0xc4, 0x33, 0xc5, 0xaa, 0x75, 0x40, + 0xf7, 0xba, 0xfc, 0x83, 0x40, 0x36, 0x85, 0x23, 0x02, 0x81, 0x80, 0x68, + 0xd9, 0xf6, 0x35, 0xc0, 0x87, 0x50, 0x8b, 0x0f, 0x93, 0xa9, 0x04, 0x33, + 0x48, 0x20, 0xa4, 0x26, 0xc2, 0x5c, 0x53, 0x4f, 0x58, 0x17, 0xe2, 0xae, + 0x84, 0x37, 0x19, 0x5f, 0x51, 0x9b, 0x56, 0x3d, 0x59, 0xf4, 0xf1, 0x49, + 0x73, 0x55, 0x91, 0xce, 0xe5, 0xf5, 0x7e, 0xd0, 0xc5, 0xda, 0xdf, 0x56, + 0x2a, 0x1d, 0x49, 0x0d, 0xa5, 0x4f, 0x00, 0x84, 0xf9, 0xd2, 0x32, 0x0a, + 0xe5, 0x61, 0x15, 0xe9, 0x51, 0x2b, 0xfb, 0x7a, 0xd6, 0x8a, 0x95, 0x8e, + 0x41, 0xc6, 0xb9, 0x8a, 0xf4, 0x68, 0xdb, 0x15, 0xc0, 0xb7, 0xe7, 0xd4, + 0x31, 0xf4, 0xc6, 0x35, 0x20, 0x33, 0xd9, 0xac, 0x9d, 0xba, 0x1e, 0x22, + 0xd8, 0xd1, 0x2d, 0x19, 0x28, 0x8a, 0x1a, 0xba, 0x16, 0x26, 0xe1, 0xe4, + 0x79, 0x6d, 0xf5, 0xc1, 0xe9, 0xa4, 0xc1, 0xbb, 0xb0, 0x41, 0xa1, 0xed, + 0xd3, 0x47, 0xe7, 0x53, 0x19, 0xa9, 0x7d, 0x02, 0x81, 0x81, 0x00, 0xb4, + 0xd6, 0x5e, 0xb7, 0xd7, 0xe3, 0xe0, 0x13, 0x37, 0x65, 0x26, 0x5a, 0xff, + 0x75, 0x61, 0x12, 0x02, 0x20, 0xce, 0xb9, 0x21, 0x07, 0x3d, 0x7b, 0x86, + 0xf6, 0x5e, 0xe7, 0x8f, 0xea, 0x88, 0x3f, 0x53, 0x4b, 0x2f, 0x06, 0xcc, + 0x97, 0x64, 0x2d, 0x55, 0x68, 0x77, 0xea, 0xe7, 0xc5, 0x86, 0x62, 0x2e, + 0xd2, 0xd2, 0x64, 0x3d, 0x20, 0xcb, 0x53, 0x43, 0x20, 0xd2, 0xf4, 0x61, + 0xd6, 0x38, 0x16, 0x36, 0x8f, 0xef, 0xbf, 0xae, 0x76, 0x83, 0xb9, 0x73, + 0x92, 0x8f, 0xd0, 0x66, 0xa7, 0x23, 0x1b, 0x98, 0x02, 0x71, 0x88, 0xbd, + 0x85, 0x11, 0x5b, 0x97, 0x8a, 0x62, 0x9b, 0xce, 0xcc, 0x24, 0x59, 0xe3, + 0x10, 0xf3, 0x7b, 0x13, 0xb9, 0xab, 0x09, 0xa3, 0xb9, 0xb8, 0xda, 0x52, + 0x6f, 0xf3, 0x77, 0x20, 0xd6, 0xd4, 0x86, 0xe5, 0x92, 0x8e, 0x18, 0xd7, + 0x0a, 0x87, 0x4c, 0xd0, 0x31, 0x78, 0x63, 0x02, 0x81, 0x81, 0x00, 0xc2, + 0x8c, 0xea, 0xa2, 0x9b, 0xfa, 0x42, 0x98, 0x70, 0x5a, 0xf9, 0x73, 0x78, + 0xee, 0xd6, 0x2b, 0x3e, 0x5b, 0xf4, 0x2f, 0x84, 0x60, 0x71, 0x9b, 0xce, + 0xf4, 0x9b, 0x88, 0x25, 0x0a, 0x29, 0x41, 0x4b, 0x4d, 0x36, 0xcf, 0xd9, + 0x86, 0xac, 0x75, 0xa2, 0xed, 0x56, 0x5b, 0x6e, 0x87, 0x1e, 0x32, 0x04, + 0x13, 0xaf, 0xa5, 0x1e, 0xf5, 0x0f, 0x9d, 0x93, 0x4a, 0x29, 0x90, 0x23, + 0x0e, 0xf9, 0x8e, 0xfd, 0x2d, 0xfe, 0x2b, 0x79, 0xa6, 0x03, 0x6c, 0xcd, + 0x01, 0xee, 0xba, 0x69, 0xb3, 0xb9, 0xd4, 0xc8, 0x99, 0x0f, 0x72, 0xba, + 0x59, 0x22, 0xdc, 0x2d, 0xc3, 0x97, 0x8c, 0xa7, 0xb3, 0xbf, 0x60, 0xe1, + 0x61, 0xe5, 0xd4, 0x51, 0x6f, 0x36, 0x9c, 0x9a, 0xb8, 0x1b, 0x52, 0xec, + 0x13, 0xf3, 0xa7, 0xdb, 0xdb, 0x5d, 0x89, 0x2d, 0xd7, 0x02, 0x96, 0xaf, + 0xeb, 0x72, 0x8d, 0xd5, 0x56, 0x3b, 0x3a}; + +// TODO(fredgc): duplicate code. Move to common util package. +// Return a printable string from data. If all the characters are printable, +// then just use the string. Otherwise, convert to hex. +std::string MaybeHex(const uint8_t* data, size_t length) { + for (size_t i = 0; i < length; i++) { + if (!isprint(data[i])) return "0x" + wvcdm::HexEncode(data, length); + } + return std::string(reinterpret_cast(data), length); +} +std::string MaybeHex(const std::vector& data) { + return MaybeHex(data.data(), data.size()); +} + +std::vector GetModelKey(const std::vector& device_id) { + std::vector keymint_key( + TestKeyPKCS8, TestKeyPKCS8 + wvcdm::ArraySize(TestKeyPKCS8)); + keymint_key.insert(keymint_key.end(), device_id.begin(), device_id.end()); + std::vector key(SHA256_DIGEST_LENGTH); + SHA256(keymint_key.data(), keymint_key.size(), key.data()); + key.resize(wvoec::KEY_SIZE); // Truncate to standard AES 128 key. + return key; +} + +} // namespace + +class OTAKeyboxProvisioningTest : public ::testing::Test, public SessionUtil { + protected: + void SetUp() override { + ::testing::Test::SetUp(); + const ::testing::TestInfo* const test_info = + ::testing::UnitTest::GetInstance()->current_test_info(); + LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } + + void TearDown() override { + OEMCrypto_Terminate(); + ::testing::Test::TearDown(); + } +}; + +TEST_F(OTAKeyboxProvisioningTest, BasicTest) { + OEMCryptoResult result = OEMCrypto_IsKeyboxValid(); + if (result == OEMCrypto_SUCCESS) { + cout << " " + << "Keybox valid after initialization. Skipping rest of test." << endl; + return; + } + if (result != OEMCrypto_ERROR_NEEDS_KEYBOX_PROVISIONING) { + cout << " " + << "OTA Keybox functions not supported. Skipping rest of test." + << endl; + return; + } + cout << " " + << "OTA Keybox functions supported. Device needs provisioning." << endl; + // TODO(fredgc): Make sure that partners can use a test cert when use_test_key + // is true. + constexpr uint32_t use_test_key = 1; + size_t request_length = 0; + std::vector request; + + OEMCrypto_SESSION session_id; + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_OpenSession(&session_id)); + + ASSERT_EQ(OEMCrypto_ERROR_SHORT_BUFFER, + OEMCrypto_GenerateOTARequest(session_id, nullptr, &request_length, + use_test_key)); + ASSERT_NE(request_length, 0u); + request.resize(request_length); + ASSERT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_GenerateOTARequest(session_id, request.data(), + &request_length, use_test_key)); + ASSERT_GT(request_length, kMinimumRequestLength); + request.resize(request_length); + // First 16 bytes should match the label for Option 1 or 2. + // TODO(fredgc): Write tests for Option 1 -- only Option 2 is tested now. + EXPECT_EQ(kOption2Label.length(), kLabelLength); + const uint8_t* label_ptr = request.data(); + EXPECT_EQ(kOption2Label, std::string(label_ptr, label_ptr + kLabelLength)); + // Next 32 bytes are the device id. + const uint8_t* device_id_ptr = label_ptr + kLabelLength; + const std::vector device_id(device_id_ptr, + device_id_ptr + kDeviceIdLength); + LOGD("Device id is %s", MaybeHex(device_id).c_str()); + // Next 4 bytes say that this is a cert. + uint32_t cert_length; + const uint8_t* cert_length_ptr = device_id_ptr + kDeviceIdLength; + memcpy(&cert_length, cert_length_ptr, sizeof(uint32_t)); + cert_length = ntohl(cert_length); + LOGD("Cert Length is 0x%x = %u", cert_length, cert_length); + ASSERT_EQ(request_length, kMinimumRequestLength + cert_length); + const uint8_t* cert_ptr = cert_length_ptr + sizeof(uint32_t); + const std::vector cert(cert_ptr, cert_ptr + cert_length); + LOGD("x509 attestation cert = %s", MaybeHex(cert).c_str()); + const uint8_t* signature_ptr = cert_ptr + cert_length; + const std::vector signature( + signature_ptr, signature_ptr + HMAC_SHA256_SIGNATURE_SIZE); + +#if 0 + // This unit test only works with the test model key. + const std::vector model_key = + wvcdm::a2b_hex("0102030405060708090a0b0c0d0e0f10"); +#else + // This unit test only works with the test cert's private key. + const std::vector model_key = GetModelKey(device_id); +#endif + // The server should derive the same set of keys as the client. + const std::string mac_label = "WV_SIGN"; + std::vector mac_context(mac_label.begin(), mac_label.end()); + mac_context.push_back(0); + std::copy(cert.begin(), cert.end(), std::back_inserter(mac_context)); + std::copy(device_id.begin(), device_id.end(), + std::back_inserter(mac_context)); + uint32_t bit_size = MAC_KEY_SIZE * 8 * 2; + std::string bit_size_string = wvcdm::EncodeUint32(bit_size); + std::copy(bit_size_string.begin(), bit_size_string.end(), + std::back_inserter(mac_context)); + std::string enc_label = "WV_ENCRYPT"; + std::vector enc_context(enc_label.begin(), enc_label.end()); + enc_context.push_back(0); + std::copy(cert.begin(), cert.end(), std::back_inserter(enc_context)); + std::copy(device_id.begin(), device_id.end(), + std::back_inserter(enc_context)); + bit_size = KEY_SIZE * 8; + bit_size_string = wvcdm::EncodeUint32(bit_size); + std::copy(bit_size_string.begin(), bit_size_string.end(), + std::back_inserter(enc_context)); + KeyDeriver keys; + keys.DeriveKeys(model_key.data(), mac_context, enc_context); + const std::vector message( + request.data(), + request.data() + request.size() - HMAC_SHA256_SIGNATURE_SIZE); + // Once the keys have been derived, the server should verify the signature. + std::vector computed_signature; + keys.ClientSignBuffer(message, &computed_signature); + ASSERT_EQ(signature, computed_signature); + + // The server should randomly pick an iv. + uint8_t iv[wvoec::KEY_IV_SIZE]; + EXPECT_EQ(GetRandBytes(iv, KEY_IV_SIZE), 1); + // Encrypt the keybox. + std::vector encrypted_keybox(sizeof(WidevineKeybox)); + keys.CBCEncrypt(reinterpret_cast(&kTestKeybox), + encrypted_keybox.data(), sizeof(WidevineKeybox), iv); + std::vector response(iv, iv + wvoec::KEY_IV_SIZE); + std::copy(encrypted_keybox.begin(), encrypted_keybox.end(), + std::back_inserter(response)); + std::vector response_signature; + // Sign the iv + encrypted keybox. + keys.ServerSignBuffer(response.data(), response.size(), &response_signature); + std::copy(response_signature.begin(), response_signature.end(), + std::back_inserter(response)); + // Finally, send the response back to the device. + EXPECT_EQ(OEMCrypto_SUCCESS, + OEMCrypto_ProcessOTAKeybox(session_id, response.data(), + response.size(), use_test_key)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_CloseSession(session_id)); + // After installation, the keybox should be valid. + EXPECT_EQ(OEMCrypto_IsKeyboxValid(), OEMCrypto_SUCCESS); +} +} // namespace wvoec diff --git a/oemcrypto/test/test_rsa_key.der b/oemcrypto/test/test_rsa_key.der new file mode 100644 index 0000000..b6752ee Binary files /dev/null and b/oemcrypto/test/test_rsa_key.der differ diff --git a/util/include/file_store.h b/util/include/file_store.h index 94dded6..a2310e9 100644 --- a/util/include/file_store.h +++ b/util/include/file_store.h @@ -18,6 +18,13 @@ namespace wvcdm { +static const std::string kAtscCertificateFileName = "atsccert.bin"; +static const std::string kCertificateFileName = "cert1.bin"; +static const std::string kCertificateFileNameExt = ".bin"; +static const std::string kCertificateFileNamePrefix = "cert1_"; +static const std::string kLegacyCertificateFileName = "cert.bin"; +static const std::string kLegacyCertificateFileNamePrefix = "cert"; + // File class. The implementation is platform dependent. class CORE_UTIL_EXPORT File { public: diff --git a/util/include/log.h b/util/include/log.h index 5d945e4..c877c28 100644 --- a/util/include/log.h +++ b/util/include/log.h @@ -7,6 +7,11 @@ #ifndef WVCDM_UTIL_LOG_H_ #define WVCDM_UTIL_LOG_H_ +#include +#include +#include +#include +#include #include "util_common.h" namespace wvcdm { @@ -27,15 +32,53 @@ typedef enum { extern LogPriority g_cutoff; +struct LogMessage { + uint32_t uid_; + int64_t time_ms_; + LogPriority priority_; + std::string message_; +}; + +class LogBuffer { + public: + static const int MAX_CAPACITY = 100; + void addLog(const LogMessage& log); + std::vector getLogs(); + + private: + std::deque buffer_; + std::mutex mutex_; +}; + +extern LogBuffer g_logbuf; + +static const uint32_t UNKNOWN_UID = std::numeric_limits::max(); + +#ifdef __ANDROID__ +void SetLoggingUid(const uint32_t); +void ClearLoggingUid(); +uint32_t GetLoggingUid(); +uint32_t GetIpcCallingUid(); +#else +static inline void SetLoggingUid(const uint32_t) {} +static inline void ClearLoggingUid() {} +static inline uint32_t GetLoggingUid() { return UNKNOWN_UID; } +static inline uint32_t GetIpcCallingUid() { return UNKNOWN_UID; } +#endif + +struct LoggingUidSetter { + LoggingUidSetter() {} + LoggingUidSetter(uint32_t uid) { SetLoggingUid(uid); } + virtual ~LoggingUidSetter() { ClearLoggingUid(); } +}; + // Enable/disable verbose logging (LOGV). // This function is supplied for cases where the system layer does not // initialize logging. This is also needed to initialize logging in // unit tests. CORE_UTIL_EXPORT void InitLogging(); -// Only enable format specifier warnings on LP64 systems. There is -// no easy portable method to handle format specifiers for int64_t. -#if (defined(__GNUC__) || defined(__clang__)) && defined(__LP64__) +#ifdef __GNUC__ [[gnu::format(printf, 5, 6)]] CORE_UTIL_EXPORT void Log(const char* file, const char* function, int line, diff --git a/util/include/string_conversions.h b/util/include/string_conversions.h index feff9dc..939fecd 100644 --- a/util/include/string_conversions.h +++ b/util/include/string_conversions.h @@ -1,7 +1,6 @@ // Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. - #ifndef WVCDM_UTIL_STRING_CONVERSIONS_H_ #define WVCDM_UTIL_STRING_CONVERSIONS_H_ @@ -15,29 +14,54 @@ namespace wvcdm { +// ASCII hex to Binary conversion. CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& b); CORE_UTIL_EXPORT std::vector a2b_hex(const std::string& label, const std::string& b); CORE_UTIL_EXPORT std::string a2bs_hex(const std::string& b); + +// Binary to ASCII hex conversion. The default versions limit output to 2k to +// protect us from log spam. The unlimited version has no length limit. CORE_UTIL_EXPORT std::string b2a_hex(const std::vector& b); +CORE_UTIL_EXPORT std::string unlimited_b2a_hex(const std::vector& b); CORE_UTIL_EXPORT std::string b2a_hex(const std::string& b); +CORE_UTIL_EXPORT std::string unlimited_b2a_hex(const std::string& b); +CORE_UTIL_EXPORT std::string HexEncode(const uint8_t* bytes, size_t size); +CORE_UTIL_EXPORT std::string UnlimitedHexEncode(const uint8_t* bytes, + size_t size); + +// Base64 encoding/decoding. +// Converts binary data into the ASCII Base64 character set and vice +// versa using the encoding rules defined in RFC4648 section 4. CORE_UTIL_EXPORT std::string Base64Encode( const std::vector& bin_input); +CORE_UTIL_EXPORT std::string Base64Encode(const std::string& bin_input); CORE_UTIL_EXPORT std::vector Base64Decode( const std::string& bin_input); + +// URL-Safe Base64 encoding/decoding. +// Converts binary data into the URL/Filename safe ASCII Base64 +// character set and vice versa using the encoding rules defined in +// RFC4648 section 5. CORE_UTIL_EXPORT std::string Base64SafeEncode( const std::vector& bin_input); -CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( - const std::vector& bin_input); +CORE_UTIL_EXPORT std::string Base64SafeEncode(const std::string& bin_input); CORE_UTIL_EXPORT std::vector Base64SafeDecode( const std::string& bin_input); -CORE_UTIL_EXPORT std::string HexEncode(const uint8_t* bytes, unsigned size); -CORE_UTIL_EXPORT std::string IntToString(int value); +// URL-Safe Base64 encoding without padding. +// Similar to Base64SafeEncode(), without any padding character '=' +// at the end. +CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( + const std::vector& bin_input); +CORE_UTIL_EXPORT std::string Base64SafeEncodeNoPad( + const std::string& bin_input); + +// Host to Network/Network to Host conversion. CORE_UTIL_EXPORT int64_t htonll64(int64_t x); CORE_UTIL_EXPORT inline int64_t ntohll64(int64_t x) { return htonll64(x); } -CORE_UTIL_EXPORT std::string BytesToString(const uint8_t* bytes, unsigned size); -// Encode unsigned integer into a big endian formatted string -CORE_UTIL_EXPORT std::string EncodeUint32(unsigned int u); + +// Encode unsigned integer into a big endian formatted string. +CORE_UTIL_EXPORT std::string EncodeUint32(uint32_t u); } // namespace wvcdm diff --git a/util/include/util_common.h b/util/include/util_common.h index 4477ca1..7b28c48 100644 --- a/util/include/util_common.h +++ b/util/include/util_common.h @@ -5,18 +5,53 @@ #ifndef WVCDM_UTIL_UTIL_COMMON_H_ #define WVCDM_UTIL_UTIL_COMMON_H_ +// This section deals with defines that are platform-specific. + #ifdef _WIN32 + # ifdef CORE_UTIL_IMPLEMENTATION # define CORE_UTIL_EXPORT __declspec(dllexport) # else # define CORE_UTIL_EXPORT __declspec(dllimport) # endif + +# define CORE_UTIL_IGNORE_DEPRECATED +# define CORE_UTIL_RESTORE_WARNINGS + #else + # ifdef CORE_UTIL_IMPLEMENTATION # define CORE_UTIL_EXPORT __attribute__((visibility("default"))) # else # define CORE_UTIL_EXPORT # endif + +# ifdef __GNUC__ +# define CORE_UTIL_IGNORE_DEPRECATED \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define CORE_UTIL_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") +# else +# define CORE_UTIL_IGNORE_DEPRECATED +# define CORE_UTIL_RESTORE_WARNINGS +# endif + +#endif + +// This section deals with attribute-detection and is platform-agnostic. + +#if !defined(__has_cpp_attribute) +# define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(fallthrough) +# define CORE_UTIL_FALLTHROUGH [[fallthrough]] +#elif __has_cpp_attribute(clang::fallthrough) +# define CORE_UTIL_FALLTHROUGH [[clang::fallthrough]] +#elif __has_cpp_attribute(gnu::fallthrough) +# define CORE_UTIL_FALLTHROUGH [[gnu::fallthrough]] +#else +# define CORE_UTIL_FALLTHROUGH #endif #endif // WVCDM_UTIL_UTIL_COMMON_H_ diff --git a/util/include/wv_attributes.h b/util/include/wv_attributes.h new file mode 100644 index 0000000..c817f1c --- /dev/null +++ b/util/include/wv_attributes.h @@ -0,0 +1,16 @@ +// Copyright 2021 Google LLC. All rights reserved. This file and proprietary +// source code may only be used and distributed under the Widevine +// License Agreement. + +#ifndef WVCDM_UTIL_WV_ATTRIBUTES_H_ +#define WVCDM_UTIL_WV_ATTRIBUTES_H_ + +#ifndef UNUSED +# if defined(__GNUC__) || defined(__clang__) +# define UNUSED __attribute__((__unused__)) +# else +# define UNUSED +# endif +#endif + +#endif // WVCDM_UTIL_WV_ATTRIBUTES_H_ diff --git a/util/src/cdm_random.cpp b/util/src/cdm_random.cpp index ca4020a..ad6ab2a 100644 --- a/util/src/cdm_random.cpp +++ b/util/src/cdm_random.cpp @@ -77,10 +77,10 @@ std::string CdmRandomGenerator::RandomData(size_t length) { return std::string(); } CdmRandomLock lock(generator_lock_); - std::uniform_int_distribution dist; // Range of [0, 255]. + std::uniform_int_distribution dist(0, 255); // Range of [0, 255]. std::string random_data(length, '\0'); std::generate(random_data.begin(), random_data.end(), - [&]() { return dist(generator_); }); + [&]() { return static_cast(dist(generator_)); }); return random_data; } diff --git a/util/src/string_conversions.cpp b/util/src/string_conversions.cpp index e40e6f7..13fccb9 100644 --- a/util/src/string_conversions.cpp +++ b/util/src/string_conversions.cpp @@ -10,15 +10,18 @@ #include #include -#include #include "log.h" #include "platform.h" namespace wvcdm { - -static const char kBase64Codes[] = +namespace { +// Base64 character set, indexed for their 6-bit mapping, plus '='. +const char kBase64Codes[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; +// URL safe Base64 character set. +const char kBase64SafeCodes[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="; // Gets the low |n| bits of |in|. #define GET_LOW_BITS(in, n) ((in) & ((1 << (n)) - 1)) @@ -27,32 +30,139 @@ static const char kBase64Codes[] = // Calculates a/b using round-up division (only works for positive numbers). #define CEIL_DIVIDE(a, b) ((((a)-1) / (b)) + 1) -int DecodeBase64Char(char c) { - const char* it = strchr(kBase64Codes, c); - if (it == nullptr) return -1; - return it - kBase64Codes; +// Decodes a single Base64 encoded character into its 6-bit value. +// The provided |codes| must be a Base64 character map. +int DecodeBase64Char(char c, const char* codes) { + const char* c_in_codes = strchr(codes, c); + if (c_in_codes == nullptr) return -1; + const uintptr_t c_in_codes_int = reinterpret_cast(c_in_codes); + const uintptr_t codes_int = reinterpret_cast(codes); + return static_cast(c_in_codes_int - codes_int); } -bool DecodeHexChar(char ch, unsigned char* digit) { +bool DecodeHexChar(char ch, uint8_t* digit) { if (ch >= '0' && ch <= '9') { *digit = ch - '0'; - } else { - ch = tolower(ch); - if ((ch >= 'a') && (ch <= 'f')) { - *digit = ch - 'a' + 10; - } else { - return false; + return true; + } + ch = tolower(ch); + if ((ch >= 'a') && (ch <= 'f')) { + *digit = ch - 'a' + 10; + return true; + } + return false; +} + +// Encode for standard base64 encoding (RFC4648). +// https://en.wikipedia.org/wiki/Base64 +// Text | M | a | n | +// ASCI | 77 (0x4d) | 97 (0x61) | 110 (0x6e) | +// Bits | 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0 | +// Index | 19 | 22 | 5 | 46 | +// Base64 | T | W | F | u | +// | <----------------- 24-bits -----------------> | + +// The provided |codes| must be a Base64 character map. +std::string Base64EncodeInternal(const uint8_t* data, size_t length, + const char* codes) { + // |temp| stores a 24-bit block that is treated as an array where insertions + // occur from high to low. + uint32_t temp = 0; + size_t out_index = 0; + const size_t out_size = CEIL_DIVIDE(length, 3) * 4; + std::string result(out_size, '\0'); + for (size_t i = 0; i < length; i++) { + // "insert" 8-bits of data + temp |= (data[i] << ((2 - (i % 3)) * 8)); + if (i % 3 == 2) { + result[out_index++] = codes[GET_BITS(temp, 18, 24)]; + result[out_index++] = codes[GET_BITS(temp, 12, 18)]; + result[out_index++] = codes[GET_BITS(temp, 6, 12)]; + result[out_index++] = codes[GET_BITS(temp, 0, 6)]; + temp = 0; } } - return true; + if (length % 3 == 1) { + result[out_index++] = codes[GET_BITS(temp, 18, 24)]; + result[out_index++] = codes[GET_BITS(temp, 12, 18)]; + result[out_index++] = '='; + result[out_index++] = '='; + } else if (length % 3 == 2) { + result[out_index++] = codes[GET_BITS(temp, 18, 24)]; + result[out_index++] = codes[GET_BITS(temp, 12, 18)]; + result[out_index++] = codes[GET_BITS(temp, 6, 12)]; + result[out_index++] = '='; + } + return result; } +std::vector Base64DecodeInternal(const char* encoded, size_t length, + const char* codes) { + const size_t out_size_max = CEIL_DIVIDE(length * 3, 4); + std::vector result(out_size_max, '\0'); + // |temp| stores 24-bits of data that is treated as an array where insertions + // occur from high to low. + uint32_t temp = 0; + size_t out_index = 0; + size_t i; + for (i = 0; i < length; i++) { + if (encoded[i] == '=') { + // Verify an '=' only appears at the end. We want i to remain at the + // first '=', so we need an inner loop. + for (size_t j = i; j < length; j++) { + if (encoded[j] != '=') { + LOGE("base64Decode failed"); + return std::vector(); + } + } + if (length % 4 != 0) { + // If padded, then the length must be a multiple of 4. + // Unpadded messages are OK. + LOGE("base64Decode failed"); + return std::vector(); + } + break; + } + + const int decoded = DecodeBase64Char(encoded[i], codes); + if (decoded < 0) { + LOGE("base64Decode failed"); + return std::vector(); + } + // "insert" 6-bits of data + temp |= (decoded << ((3 - (i % 4)) * 6)); + + if (i % 4 == 3) { + result[out_index++] = GET_BITS(temp, 16, 24); + result[out_index++] = GET_BITS(temp, 8, 16); + result[out_index++] = GET_BITS(temp, 0, 8); + temp = 0; + } + } + + switch (i % 4) { + case 1: + LOGE("base64Decode failed"); + return std::vector(); + case 2: + result[out_index++] = GET_BITS(temp, 16, 24); + break; + case 3: + result[out_index++] = GET_BITS(temp, 16, 24); + result[out_index++] = GET_BITS(temp, 8, 16); + break; + } + result.resize(out_index); + return result; +} +} // namespace + // converts an ascii hex string(2 bytes per digit) into a decimal byte string std::vector a2b_hex(const std::string& byte) { std::vector array; - unsigned int count = byte.size(); + size_t count = byte.size(); if (count == 0 || (count % 2) != 0) { - LOGE("Invalid input size %u for string %s", count, byte.c_str()); + LOGE("Invalid input size %zu for string %s", count, byte.c_str()); return array; } @@ -91,174 +201,34 @@ std::string b2a_hex(const std::vector& byte) { return HexEncode(byte.data(), byte.size()); } +std::string unlimited_b2a_hex(const std::vector& byte) { + if (byte.empty()) return ""; + return UnlimitedHexEncode(byte.data(), byte.size()); +} + std::string b2a_hex(const std::string& byte) { if (byte.empty()) return ""; return HexEncode(reinterpret_cast(byte.data()), byte.length()); } -// Encode for standard base64 encoding (RFC4648). -// https://en.wikipedia.org/wiki/Base64 -// Text | M | a | n | -// ASCI | 77 (0x4d) | 97 (0x61) | 110 (0x6e) | -// Bits | 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0 | -// Index | 19 | 22 | 5 | 46 | -// Base64 | T | W | F | u | -// | <----------------- 24-bits -----------------> | -std::string Base64Encode(const std::vector& bin_input) { - if (bin_input.empty()) { - return std::string(); - } - - // |temp| stores a 24-bit block that is treated as an array where insertions - // occur from high to low. - uint32_t temp = 0; - size_t out_index = 0; - const size_t out_size = CEIL_DIVIDE(bin_input.size(), 3) * 4; - std::string result(out_size, '\0'); - for (size_t i = 0; i < bin_input.size(); i++) { - // "insert" 8-bits of data - temp |= (bin_input[i] << ((2 - (i % 3)) * 8)); - - if (i % 3 == 2) { - result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 6, 12)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 0, 6)]; - temp = 0; - } - } - - if (bin_input.size() % 3 == 1) { - result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)]; - result[out_index++] = '='; - result[out_index++] = '='; - } else if (bin_input.size() % 3 == 2) { - result[out_index++] = kBase64Codes[GET_BITS(temp, 18, 24)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 12, 18)]; - result[out_index++] = kBase64Codes[GET_BITS(temp, 6, 12)]; - result[out_index++] = '='; - } - - return result; +std::string unlimited_b2a_hex(const std::string& byte) { + if (byte.empty()) return ""; + return UnlimitedHexEncode(reinterpret_cast(byte.data()), + byte.length()); } -// Filename-friendly base64 encoding (RFC4648), commonly referred to -// as Base64WebSafeEncode. -// -// This is the encoding required to interface with the provisioning server, as -// well as for certain license server transactions. It is also used for logging -// certain strings. The difference between web safe encoding vs regular encoding -// is that the web safe version replaces '+' with '-' and '/' with '_'. -std::string Base64SafeEncode(const std::vector& bin_input) { - if (bin_input.empty()) { - return std::string(); - } - - std::string ret = Base64Encode(bin_input); - for (size_t i = 0; i < ret.size(); i++) { - if (ret[i] == '+') - ret[i] = '-'; - else if (ret[i] == '/') - ret[i] = '_'; - } - return ret; -} - -std::string Base64SafeEncodeNoPad(const std::vector& bin_input) { - std::string b64_output = Base64SafeEncode(bin_input); - // Output size: ceiling [ bin_input.size() * 4 / 3 ]. - b64_output.resize((bin_input.size() * 4 + 2) / 3); - return b64_output; -} - -// Decode for standard base64 encoding (RFC4648). -std::vector Base64Decode(const std::string& b64_input) { - if (b64_input.empty()) { - return std::vector(); - } - - const size_t out_size_max = CEIL_DIVIDE(b64_input.size() * 3, 4); - std::vector result(out_size_max, '\0'); - - // |temp| stores 24-bits of data that is treated as an array where insertions - // occur from high to low. - uint32_t temp = 0; - size_t out_index = 0; - size_t i; - for (i = 0; i < b64_input.size(); i++) { - if (b64_input[i] == '=') { - // Verify an '=' only appears at the end. We want i to remain at the - // first '=', so we need an inner loop. - for (size_t j = i; j < b64_input.size(); j++) { - if (b64_input[j] != '=') { - LOGE("base64Decode failed"); - return std::vector(); - } - } - break; - } - - const int decoded = DecodeBase64Char(b64_input[i]); - if (decoded < 0) { - LOGE("base64Decode failed"); - return std::vector(); - } - // "insert" 6-bits of data - temp |= (decoded << ((3 - (i % 4)) * 6)); - - if (i % 4 == 3) { - result[out_index++] = GET_BITS(temp, 16, 24); - result[out_index++] = GET_BITS(temp, 8, 16); - result[out_index++] = GET_BITS(temp, 0, 8); - temp = 0; - } - } - - switch (i % 4) { - case 1: - LOGE("base64Decode failed"); - return std::vector(); - case 2: - result[out_index++] = GET_BITS(temp, 16, 24); - break; - case 3: - result[out_index++] = GET_BITS(temp, 16, 24); - result[out_index++] = GET_BITS(temp, 8, 16); - break; - } - result.resize(out_index); - return result; -} - -// Decode for Filename-friendly base64 encoding (RFC4648), commonly referred -// as Base64WebSafeDecode. Add padding if needed. -std::vector Base64SafeDecode(const std::string& b64_input) { - if (b64_input.empty()) { - return std::vector(); - } - - // Make a copy so we can modify it to replace the web-safe special characters - // with the normal ones. - std::string input_copy = b64_input; - for (size_t i = 0; i < input_copy.size(); i++) { - if (input_copy[i] == '-') - input_copy[i] = '+'; - else if (input_copy[i] == '_') - input_copy[i] = '/'; - } - return Base64Decode(input_copy); -} - -std::string HexEncode(const uint8_t* in_buffer, unsigned int size) { - static const char kHexChars[] = "0123456789ABCDEF"; - if (size == 0) return ""; +std::string HexEncode(const uint8_t* in_buffer, size_t size) { constexpr unsigned int kMaxSafeSize = 2048; if (size > kMaxSafeSize) size = kMaxSafeSize; + return UnlimitedHexEncode(in_buffer, size); +} + +std::string UnlimitedHexEncode(const uint8_t* in_buffer, size_t size) { + static const char kHexChars[] = "0123456789ABCDEF"; + if (size == 0) return ""; // Each input byte creates two output hex characters. std::string out_buffer(size * 2, '\0'); - for (unsigned int i = 0; i < size; ++i) { char byte = in_buffer[i]; out_buffer[(i << 1)] = kHexChars[(byte >> 4) & 0xf]; @@ -267,19 +237,83 @@ std::string HexEncode(const uint8_t* in_buffer, unsigned int size) { return out_buffer; } -std::string IntToString(int value) { - // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4. - // So round up to allocate 3 output characters per byte, plus 1 for '-'. - const int kOutputBufSize = 3 * sizeof(int) + 1; - char buffer[kOutputBufSize]; - memset(buffer, 0, kOutputBufSize); - snprintf(buffer, kOutputBufSize, "%d", value); +// Standard Base64 encoding and decoding. - std::string out_string(buffer); - return out_string; +std::string Base64Encode(const std::vector& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal(bin_input.data(), bin_input.size(), kBase64Codes); } -int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order) +std::string Base64Encode(const std::string& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal( + reinterpret_cast(bin_input.data()), bin_input.size(), + kBase64Codes); +} + +// Decode for standard base64 encoding (RFC4648). +std::vector Base64Decode(const std::string& b64_input) { + if (b64_input.empty()) { + return std::vector(); + } + return Base64DecodeInternal(b64_input.data(), b64_input.size(), kBase64Codes); +} + +// URL/Filename Safe Base64 encoding and decoding. + +// This is the encoding required to interface with the provisioning server, as +// well as for certain license server transactions. It is also used for logging +// certain strings. The difference between web safe encoding vs regular encoding +// is that the web safe version replaces '+' with '-' and '/' with '_'. +std::string Base64SafeEncode(const std::vector& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal(bin_input.data(), bin_input.size(), + kBase64SafeCodes); +} + +std::string Base64SafeEncode(const std::string& bin_input) { + if (bin_input.empty()) { + return std::string(); + } + return Base64EncodeInternal( + reinterpret_cast(bin_input.data()), bin_input.size(), + kBase64SafeCodes); +} + +std::vector Base64SafeDecode(const std::string& b64_input) { + if (b64_input.empty()) { + return std::vector(); + } + return Base64DecodeInternal(b64_input.data(), b64_input.size(), + kBase64SafeCodes); +} + +// URL/Filename Safe Base64 encoding without padding. + +std::string Base64SafeEncodeNoPad(const std::vector& bin_input) { + std::string b64_output = Base64SafeEncode(bin_input); + // Output size: ceiling [ bin_input.size() * 4 / 3 ]. + b64_output.resize((bin_input.size() * 4 + 2) / 3); + return b64_output; +} + +std::string Base64SafeEncodeNoPad(const std::string& bin_input) { + std::string b64_output = Base64SafeEncode(bin_input); + // Output size: ceiling [ bin_input.size() * 4 / 3 ]. + b64_output.resize((bin_input.size() * 4 + 2) / 3); + return b64_output; +} + +// Host to Network/Network to Host conversion. + +// Convert to big endian (network-byte-order) +int64_t htonll64(int64_t x) { union { uint32_t array[2]; int64_t number; @@ -296,19 +330,13 @@ int64_t htonll64(int64_t x) { // Convert to big endian (network-byte-order) } } -std::string BytesToString(const uint8_t* bytes, unsigned size) { - if (!bytes || !size) return ""; - const char* char_bytes = reinterpret_cast(bytes); - return std::string(char_bytes, char_bytes + size); -} - // Encode unsigned integer into a big endian formatted string std::string EncodeUint32(unsigned int u) { std::string s; - s.append(1, (u >> 24) & 0xFF); - s.append(1, (u >> 16) & 0xFF); - s.append(1, (u >> 8) & 0xFF); - s.append(1, (u >> 0) & 0xFF); + s.push_back((u >> 24) & 0xFF); + s.push_back((u >> 16) & 0xFF); + s.push_back((u >> 8) & 0xFF); + s.push_back(u & 0xFF); return s; } diff --git a/util/test/base64_test.cpp b/util/test/base64_test.cpp index 81d32a9..647afbe 100644 --- a/util/test/base64_test.cpp +++ b/util/test/base64_test.cpp @@ -55,8 +55,14 @@ const std::pair kBase64TestVectors[] = { make_pair(&kTwoBytesOverData, &kTwoBytesOverB64Data), make_pair(&kTestData, &kB64TestData)}; -const std::string kBase64ErrorVectors[] = {"Foo$sa", "Foo\x99\x23\xfa\02", - "Foo==Foo", "FooBa"}; +// Arbitrary invalid base64 test vectors +const std::string kBase64ErrorVectors[] = {"Foo$sa", + "Foo\x99\x23\xfa\02", + "Foo==Foo", + "FooBa", + "SGVsbG8sIFdvcmxkI===", + "SGVsbG8sIFdvcmxkI======", + "SGVsbG8sIFdvcmxkIQp=="}; std::string ConvertToBase64WebSafe(const std::string& std_base64_string) { std::string str(std_base64_string); @@ -77,35 +83,97 @@ class Base64EncodeDecodeTest TEST_P(Base64EncodeDecodeTest, EncodeDecodeTest) { std::pair values = GetParam(); - std::vector decoded_vector = Base64Decode(values.second->data()); - std::string decoded_string(decoded_vector.begin(), decoded_vector.end()); - EXPECT_STREQ(values.first->data(), decoded_string.data()); - std::string b64_string = Base64Encode(decoded_vector); - EXPECT_STREQ(values.second->data(), b64_string.data()); + const std::string& plain_text_string = *(values.first); + const std::string& expected_encoded = *(values.second); + + // Encode from string. + const std::string b64_string_encoded = Base64Encode(plain_text_string); + EXPECT_EQ(b64_string_encoded, expected_encoded); + + // Encode from vector. + const std::vector plain_text_vector(plain_text_string.begin(), + plain_text_string.end()); + const std::string b64_vector_encoded = Base64Encode(plain_text_vector); + EXPECT_EQ(b64_vector_encoded, expected_encoded); + + // Decode from string. + const std::vector decoded_vector = Base64Decode(expected_encoded); + EXPECT_EQ(decoded_vector, plain_text_vector); } TEST_P(Base64EncodeDecodeTest, WebSafeEncodeDecodeTest) { std::pair values = GetParam(); - std::string encoded_string = ConvertToBase64WebSafe(*(values.second)); - std::vector decoded_vector = Base64SafeDecode(encoded_string); - std::string decoded_string(decoded_vector.begin(), decoded_vector.end()); - EXPECT_STREQ(values.first->data(), decoded_string.data()); - std::string b64_string = Base64SafeEncode(decoded_vector); - EXPECT_STREQ(encoded_string.data(), b64_string.data()); + const std::string& plain_text_string = *(values.first); + const std::string& expected_encoded = + ConvertToBase64WebSafe(*(values.second)); + + // Encode from string. + const std::string b64_string_encoded = Base64SafeEncode(plain_text_string); + EXPECT_EQ(b64_string_encoded, expected_encoded); + + // Encode from vector. + const std::vector plain_text_vector(plain_text_string.begin(), + plain_text_string.end()); + const std::string b64_vector_encoded = Base64SafeEncode(plain_text_vector); + EXPECT_EQ(b64_vector_encoded, expected_encoded); + + // Decode from string. + const std::vector decoded_vector = + Base64SafeDecode(expected_encoded); + EXPECT_EQ(decoded_vector, plain_text_vector); +} + +TEST_P(Base64EncodeDecodeTest, WebSafeEncodeNoPad) { + std::pair values = GetParam(); + const std::string& plain_text_string = *(values.first); + const std::string& padded_encoded = ConvertToBase64WebSafe(*(values.second)); + + // Encode from string. + const std::string b64_string_encoded = + Base64SafeEncodeNoPad(plain_text_string); + + // If input is empty, output will be empty. + if (plain_text_string.empty()) { + EXPECT_TRUE(b64_string_encoded.empty()); + return; + } + + if (padded_encoded.back() == '=') { + // If padding is present in the regular encoding, then it should be + // striped from the result. + EXPECT_NE(b64_string_encoded.back(), '='); + const std::string expected_encoded = + padded_encoded.substr(0, b64_string_encoded.size()); + EXPECT_EQ(b64_string_encoded, expected_encoded); + } else { + // If no padding is present, then results should be equal. + EXPECT_EQ(b64_string_encoded, padded_encoded); + } + + // Encode from vector. + const std::vector plain_text_vector(plain_text_string.begin(), + plain_text_string.end()); + const std::string b64_vector_encoded = + Base64SafeEncodeNoPad(plain_text_vector); + // Assuming the above has passed, the results should be the same as + // a result encoded from a string. + EXPECT_EQ(b64_vector_encoded, b64_string_encoded); } class Base64ErrorDecodeTest : public ::testing::TestWithParam {}; TEST_P(Base64ErrorDecodeTest, EncoderErrors) { - std::vector result = Base64Decode(GetParam()); - EXPECT_EQ(0u, result.size()); + const std::vector standard_result = Base64Decode(GetParam()); + EXPECT_TRUE(standard_result.empty()); + const std::vector safe_result = Base64SafeDecode(GetParam()); + EXPECT_TRUE(safe_result.empty()); } -INSTANTIATE_TEST_CASE_P(ExecutesBase64Test, Base64EncodeDecodeTest, - ::testing::ValuesIn(kBase64TestVectors)); +INSTANTIATE_TEST_SUITE_P(ExecutesBase64Test, Base64EncodeDecodeTest, + ::testing::ValuesIn(kBase64TestVectors)); -INSTANTIATE_TEST_CASE_P(ExecutesBase64Test, Base64ErrorDecodeTest, - ::testing::ValuesIn(kBase64ErrorVectors)); +INSTANTIATE_TEST_SUITE_P(ExecutesBase64Test, Base64ErrorDecodeTest, + ::testing::ValuesIn(kBase64ErrorVectors)); class HtoNLL64Test : public ::testing::Test {}; diff --git a/util/test/cdm_random_unittest.cpp b/util/test/cdm_random_unittest.cpp index 097a698..54c6e2a 100644 --- a/util/test/cdm_random_unittest.cpp +++ b/util/test/cdm_random_unittest.cpp @@ -173,8 +173,8 @@ TEST_P(CdmRandomGeneratorTest, ThreadSafety) { } } -INSTANTIATE_TEST_CASE_P(VariousSeeds, CdmRandomGeneratorTest, - testing::ValuesIn(kSeeds)); +INSTANTIATE_TEST_SUITE_P(VariousSeeds, CdmRandomGeneratorTest, + testing::ValuesIn(kSeeds)); TEST(CdmRandomTest, AllMethods) { CdmRandom::Rand(); diff --git a/util/test/file_store_unittest.cpp b/util/test/file_store_unittest.cpp index c89fe6e..64b7d8d 100644 --- a/util/test/file_store_unittest.cpp +++ b/util/test/file_store_unittest.cpp @@ -18,7 +18,10 @@ const std::string kTestFileName2 = "test2.txt"; const std::string kTestFileName3 = "test3.other"; const std::string kTestFileNameExt = ".txt"; const std::string kTestFileNameExt3 = ".other"; +const std::string kTestIdentifier1 = "some_identifier"; +const std::string kTestIdentifier2 = "some_other_identifier"; const std::string kWildcard = "*"; +const std::string kUnderscore = "_"; } // namespace class FileTest : public testing::Test { @@ -28,51 +31,51 @@ class FileTest : public testing::Test { void TearDown() override { RemoveTestDir(); } void RemoveTestDir() { - EXPECT_TRUE(file_system.Remove(test_vectors::kTestDir)); + EXPECT_TRUE(file_system_.Remove(test_vectors::kTestDir)); } - FileSystem file_system; + FileSystem file_system_; }; TEST_F(FileTest, FileExists) { - EXPECT_TRUE(file_system.Exists(test_vectors::kExistentFile)); - EXPECT_TRUE(file_system.Exists(test_vectors::kExistentDir)); - EXPECT_FALSE(file_system.Exists(test_vectors::kNonExistentFile)); - EXPECT_FALSE(file_system.Exists(test_vectors::kNonExistentDir)); + EXPECT_TRUE(file_system_.Exists(test_vectors::kExistentFile)); + EXPECT_TRUE(file_system_.Exists(test_vectors::kExistentDir)); + EXPECT_FALSE(file_system_.Exists(test_vectors::kNonExistentFile)); + EXPECT_FALSE(file_system_.Exists(test_vectors::kNonExistentDir)); } TEST_F(FileTest, RemoveDir) { - EXPECT_TRUE(file_system.Remove(test_vectors::kTestDir)); - EXPECT_FALSE(file_system.Exists(test_vectors::kTestDir)); + EXPECT_TRUE(file_system_.Remove(test_vectors::kTestDir)); + EXPECT_FALSE(file_system_.Exists(test_vectors::kTestDir)); } TEST_F(FileTest, OpenFile) { std::string path = test_vectors::kTestDir + kTestFileName; - EXPECT_TRUE(file_system.Remove(path)); + EXPECT_TRUE(file_system_.Remove(path)); - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); } TEST_F(FileTest, RemoveDirAndFile) { std::string path = test_vectors::kTestDir + kTestFileName; - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path)); - EXPECT_TRUE(file_system.Remove(path)); - EXPECT_FALSE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); + EXPECT_TRUE(file_system_.Remove(path)); + EXPECT_FALSE(file_system_.Exists(path)); - file = file_system.Open(path, FileSystem::kCreate); + file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); RemoveTestDir(); - EXPECT_FALSE(file_system.Exists(test_vectors::kTestDir)); - EXPECT_FALSE(file_system.Exists(path)); + EXPECT_FALSE(file_system_.Exists(test_vectors::kTestDir)); + EXPECT_FALSE(file_system_.Exists(path)); } TEST_F(FileTest, RemoveWildcardFiles) { @@ -81,47 +84,47 @@ TEST_F(FileTest, RemoveWildcardFiles) { std::string wildcard_path = test_vectors::kTestDir + kWildcard + kTestFileNameExt; - std::unique_ptr file = file_system.Open(path1, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); ASSERT_TRUE(file); - file = file_system.Open(path2, FileSystem::kCreate); + file = file_system_.Open(path2, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path1)); - EXPECT_TRUE(file_system.Exists(path2)); - EXPECT_TRUE(file_system.Remove(wildcard_path)); - EXPECT_FALSE(file_system.Exists(path1)); - EXPECT_FALSE(file_system.Exists(path2)); + EXPECT_TRUE(file_system_.Exists(path1)); + EXPECT_TRUE(file_system_.Exists(path2)); + EXPECT_TRUE(file_system_.Remove(wildcard_path)); + EXPECT_FALSE(file_system_.Exists(path1)); + EXPECT_FALSE(file_system_.Exists(path2)); } TEST_F(FileTest, FileSize) { std::string path = test_vectors::kTestDir + kTestFileName; - file_system.Remove(path); + file_system_.Remove(path); std::string write_data = CdmRandom::RandomData(600); size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); - EXPECT_EQ(static_cast(write_data_size), file_system.FileSize(path)); + EXPECT_EQ(static_cast(write_data_size), file_system_.FileSize(path)); } TEST_F(FileTest, WriteReadBinaryFile) { std::string path = test_vectors::kTestDir + kTestFileName; - file_system.Remove(path); + file_system_.Remove(path); std::string write_data = CdmRandom::RandomData(600); size_t write_data_size = write_data.size(); - std::unique_ptr file = file_system.Open(path, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path, FileSystem::kCreate); ASSERT_TRUE(file); EXPECT_EQ(file->Write(write_data.data(), write_data_size), write_data_size); - EXPECT_TRUE(file_system.Exists(path)); + EXPECT_TRUE(file_system_.Exists(path)); std::string read_data; - read_data.resize(file_system.FileSize(path)); + read_data.resize(file_system_.FileSize(path)); size_t read_data_size = read_data.size(); - file = file_system.Open(path, FileSystem::kReadOnly); + file = file_system_.Open(path, FileSystem::kReadOnly); ASSERT_TRUE(file); EXPECT_EQ(file->Read(&read_data[0], read_data_size), read_data_size); EXPECT_EQ(write_data, read_data); @@ -136,25 +139,25 @@ TEST_F(FileTest, ListFiles) { std::string path3 = test_vectors::kTestDir + kTestFileName3; std::string path_dir = test_vectors::kTestDir; - std::unique_ptr file = file_system.Open(path1, FileSystem::kCreate); + std::unique_ptr file = file_system_.Open(path1, FileSystem::kCreate); ASSERT_TRUE(file); - file = file_system.Open(path2, FileSystem::kCreate); + file = file_system_.Open(path2, FileSystem::kCreate); ASSERT_TRUE(file); - file = file_system.Open(path3, FileSystem::kCreate); + file = file_system_.Open(path3, FileSystem::kCreate); ASSERT_TRUE(file); - EXPECT_TRUE(file_system.Exists(path1)); - EXPECT_TRUE(file_system.Exists(path2)); - EXPECT_TRUE(file_system.Exists(path3)); + EXPECT_TRUE(file_system_.Exists(path1)); + EXPECT_TRUE(file_system_.Exists(path2)); + EXPECT_TRUE(file_system_.Exists(path3)); // Ask for non-existent path. - EXPECT_FALSE(file_system.List(not_path, &names)); + EXPECT_FALSE(file_system_.List(not_path, &names)); // Valid path, but no way to return names. - EXPECT_FALSE(file_system.List(path_dir, nullptr)); + EXPECT_FALSE(file_system_.List(path_dir, nullptr)); // Valid path, valid return. - EXPECT_TRUE(file_system.List(path_dir, &names)); + EXPECT_TRUE(file_system_.List(path_dir, &names)); // Should find three files. Order not important. EXPECT_EQ(3u, names.size()); @@ -162,17 +165,195 @@ TEST_F(FileTest, ListFiles) { kTestFileName, kTestFileName2, kTestFileName3)); std::string wild_card_path = path_dir + kWildcard + kTestFileNameExt; - EXPECT_TRUE(file_system.Remove(wild_card_path)); - EXPECT_TRUE(file_system.List(path_dir, &names)); + EXPECT_TRUE(file_system_.Remove(wild_card_path)); + EXPECT_TRUE(file_system_.List(path_dir, &names)); EXPECT_EQ(1u, names.size()); EXPECT_TRUE(names[0].compare(kTestFileName3) == 0); std::string wild_card_path2 = path_dir + kWildcard + kTestFileNameExt3; - EXPECT_TRUE(file_system.Remove(wild_card_path2)); - EXPECT_TRUE(file_system.List(path_dir, &names)); + EXPECT_TRUE(file_system_.Remove(wild_card_path2)); + EXPECT_TRUE(file_system_.List(path_dir, &names)); EXPECT_EQ(0u, names.size()); } +TEST_F(FileTest, CreateGlobalCertificates) { + // Clear directory + std::vector names; + std::string path_dir = test_vectors::kTestDir; + std::string wild_card_path = path_dir + kWildcard; + file_system_.Remove(wild_card_path); + if (file_system_.List(path_dir, &names)) { + EXPECT_EQ(0u, names.size()); + } + + // Create certificates and verify that they exist + std::string certificate_path = test_vectors::kTestDir + kCertificateFileName; + std::string legacy_certificate_path = + test_vectors::kTestDir + kLegacyCertificateFileName; + + std::unique_ptr file = + file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(file_system_.IsGlobal()); + + EXPECT_TRUE(file_system_.Exists(certificate_path)); + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + + EXPECT_TRUE(file_system_.List(path_dir, &names)); + + // Should find two files. Order not important. + EXPECT_EQ(2u, names.size()); + EXPECT_THAT(names, ::testing::UnorderedElementsAre( + kCertificateFileName, kLegacyCertificateFileName)); +} + +TEST_F(FileTest, CreateCertificates) { + // Clear directory + std::vector names; + std::string path_dir = test_vectors::kTestDir; + std::string wild_card_path = path_dir + kWildcard; + file_system_.Remove(wild_card_path); + if (file_system_.List(path_dir, &names)) { + EXPECT_EQ(0u, names.size()); + } + + std::string certificate_path = test_vectors::kTestDir + kCertificateFileName; + std::string legacy_certificate_path = + test_vectors::kTestDir + kLegacyCertificateFileName; + + // Create Global certificates + std::unique_ptr file = + file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(file_system_.IsGlobal()); + + // Create certificates with first identifier + file_system_.set_identifier(kTestIdentifier1); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + // Create certificates with second identifier + file_system_.set_identifier(kTestIdentifier2); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + EXPECT_TRUE(file_system_.Exists(certificate_path)); + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + + EXPECT_TRUE(file_system_.List(path_dir, &names)); + + // Should find six files. Order not important. + bool is_global_certificate_present = false; + bool is_global_legacy_certificate_present = false; + size_t certificate_count = 0; + size_t legacy_certificate_count = 0; + EXPECT_EQ(6u, names.size()); + for (size_t i = 0; i < names.size(); ++i) { + if (names[i].size() > kCertificateFileName.size()) { + if (names[i].compare(0, kCertificateFileNamePrefix.size(), + kCertificateFileNamePrefix) == 0) + ++certificate_count; + else if (names[i].compare(0, kLegacyCertificateFileNamePrefix.size(), + kLegacyCertificateFileNamePrefix) == 0) + ++legacy_certificate_count; + } else if (names[i].compare(kCertificateFileName) == 0) { + is_global_certificate_present = true; + } else if (names[i].compare(kLegacyCertificateFileName) == 0) { + is_global_legacy_certificate_present = true; + } else { + EXPECT_TRUE(false); + } + } + EXPECT_EQ(2, certificate_count); + EXPECT_EQ(2, legacy_certificate_count); + EXPECT_TRUE(is_global_certificate_present); + EXPECT_TRUE(is_global_legacy_certificate_present); +} + +TEST_F(FileTest, RemoveCertificates) { + // Clear directory + std::vector names; + std::string path_dir = test_vectors::kTestDir; + std::string wild_card_path = path_dir + kWildcard; + file_system_.Remove(wild_card_path); + if (file_system_.List(path_dir, &names)) { + EXPECT_EQ(0u, names.size()); + } + + std::string certificate_path = test_vectors::kTestDir + kCertificateFileName; + std::string legacy_certificate_path = + test_vectors::kTestDir + kLegacyCertificateFileName; + + // Create Global certificates + std::unique_ptr file = + file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(file_system_.IsGlobal()); + + // Create certificates with first identifier + file_system_.set_identifier(kTestIdentifier1); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + // Create certificates with second identifier + file_system_.set_identifier(kTestIdentifier2); + file = file_system_.Open(certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + file = file_system_.Open(legacy_certificate_path, FileSystem::kCreate); + ASSERT_TRUE(file); + EXPECT_TRUE(!file_system_.IsGlobal()); + + EXPECT_TRUE(file_system_.Exists(certificate_path)); + EXPECT_TRUE(file_system_.Exists(legacy_certificate_path)); + + EXPECT_TRUE(file_system_.List(path_dir, &names)); + + EXPECT_EQ(6u, names.size()); + + // Remove all even number listed files + for (size_t i = 0; i < names.size(); ++i) { + if (i % 2 == 0) { + EXPECT_TRUE(file_system_.Remove(test_vectors::kTestDir + names[i])); + } + } + + // Verify that they have been removed + for (size_t i = 0; i < names.size(); ++i) { + if (i % 2 == 1) { + EXPECT_TRUE(file_system_.Exists(test_vectors::kTestDir + names[i])); + } else { + EXPECT_FALSE(file_system_.Exists(test_vectors::kTestDir + names[i])); + } + } + + // Remove all odd number listed files + for (size_t i = 0; i < names.size(); ++i) { + if (i % 2 == 1) { + EXPECT_TRUE(file_system_.Remove(test_vectors::kTestDir + names[i])); + } + } + + // Verify that all have been removed + for (size_t i = 0; i < names.size(); ++i) { + EXPECT_FALSE(file_system_.Exists(test_vectors::kTestDir + names[i])); + } +} + } // namespace wvcdm diff --git a/util/test/test_clock.cpp b/util/test/test_clock.cpp index 5c2df32..5b9572a 100644 --- a/util/test/test_clock.cpp +++ b/util/test/test_clock.cpp @@ -14,10 +14,10 @@ namespace wvcdm { namespace { // A fake clock that only advances when TestSleep::Sleep is called. -class FakeClock : public wvcdm::TestSleep::CallBack { +class FakeClock : public TestSleep::CallBack { public: FakeClock() { - auto now = std::chrono::steady_clock().now(); + auto now = std::chrono::system_clock().now(); now_ = now.time_since_epoch() / std::chrono::milliseconds(1); TestSleep::set_callback(this); } @@ -35,7 +35,7 @@ FakeClock* g_fake_clock = nullptr; // On devices running a fake OEMCrypto, we can use a fake sleep and fake time. int64_t Clock::GetCurrentTime() { - wvcdm::TestSleep::SyncFakeClock(); + TestSleep::SyncFakeClock(); if (g_fake_clock == nullptr) g_fake_clock = new FakeClock(); return g_fake_clock->now() / 1000; } diff --git a/util/test/test_sleep.cpp b/util/test/test_sleep.cpp index f3f219c..5f6075f 100644 --- a/util/test/test_sleep.cpp +++ b/util/test/test_sleep.cpp @@ -9,6 +9,9 @@ #else # include #endif +#ifdef __APPLE__ +# include +#endif #include #include @@ -55,6 +58,21 @@ void TestSleep::SyncFakeClock() { Sleep(0); } +void TestSleep::SetFakeClock(int64_t time_seconds) { + if (real_sleep_) { + LOGE("SetFakeClock when using a real clock. Expect other failures."); + } + // Delta could be positive or negative. If the fake clock had been initialized + // by the current time on a real clock, and then the command line + // re-initializes it to 0, then delta is negative. + int64_t delta = time_seconds - Clock().GetCurrentTime(); + if (callback_ != nullptr) { + callback_->ElapseTime(delta * 1000); + } else { + LOGE("Setting fake clock with no callback. This won't work."); + } +} + bool TestSleep::RollbackSystemTime(int seconds) { if (real_sleep_) { #ifdef _WIN32 @@ -73,10 +91,13 @@ bool TestSleep::RollbackSystemTime(int seconds) { file_time.dwHighDateTime = long_time >> 32; if (!FileTimeToSystemTime(&file_time, &time)) return false; if (!SetSystemTime(&time)) return false; +#elif TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE + LOGE("iOS time rollback: cannot set system time."); + return false; #else auto time = std::chrono::system_clock::now(); auto modified_time = time - std::chrono::seconds(seconds); - ; + timespec time_spec; time_spec.tv_sec = std::chrono::duration_cast( modified_time.time_since_epoch()) @@ -140,6 +161,9 @@ bool TestSleep::CanChangeSystemTime() { } LOGE("Win32 time rollback: cannot set system time."); return false; +#elif TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE + LOGE("iOS time rollback: cannot set system time."); + return false; #else // Otherwise, the test needs to be run as root. const uid_t uid = getuid(); diff --git a/util/test/test_sleep.h b/util/test/test_sleep.h index 9658ca3..1c00025 100644 --- a/util/test/test_sleep.h +++ b/util/test/test_sleep.h @@ -41,6 +41,10 @@ class TestSleep { // verify this function does not roll back the clock used by OEMCrypto. static bool RollbackSystemTime(int seconds); + // Set the system clock to the specified time. This is only expected to work + // when real_sleep is false. + static void SetFakeClock(int64_t time_seconds); + // Roll the system clock forward to undo all previous calls to // RollBackSystemTime. Returns true on success. static bool ResetRollback() {