From ac5f0135d5972a8c2a77aa4f0e6ae1b7bf25257e Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Wed, 13 Sep 2023 15:09:01 -0700 Subject: [PATCH] Cleanup install_keybox_tool This tool will soon be used in LUCI tests. It seemed necessary to clean it up to make the build cop's job easier if there is a problem. The following was completed: * Removed stub for install XML based keyboxes * This is handled externally * Improved error checking * Replace C-style prints with C++ styled prints * Keybox information is still printed to stdout * Major erros are printed to stderr * Updated to follow Google style guide * Fixed header includes * Removed unused headers * Added headers that are used, but were included indirectly * Ensures OEMCrypto_Terminate() is called * Particularly if there is an error encountered. Bug: 299108238 Test: Tested in later CL Change-Id: Ie6dafc44d050d0c6ae288f88cd5d6f3737d4a88c --- .../oemcrypto/test/install_keybox_tool.cpp | 283 +++++++++++++----- 1 file changed, 206 insertions(+), 77 deletions(-) diff --git a/libwvdrmengine/oemcrypto/test/install_keybox_tool.cpp b/libwvdrmengine/oemcrypto/test/install_keybox_tool.cpp index 265cb11b..1d521ecf 100644 --- a/libwvdrmengine/oemcrypto/test/install_keybox_tool.cpp +++ b/libwvdrmengine/oemcrypto/test/install_keybox_tool.cpp @@ -1,104 +1,233 @@ -#include "stdio.h" +// Copyright 2023 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 +#include +#include +#include #include #include -#include #include - -#include +#include #include "OEMCryptoCENC.h" -#include "clock.h" -#include "file_store.h" -#include "oemcrypto_types.h" #include "string_conversions.h" -// 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) { - // Ignore any trailing 0s. - const size_t actual_length = - strnlen(reinterpret_cast(data), length); - for (size_t i = actual_length; i < length; i++) { - // But check that there is nothing nonzero after the first 0. - if (data[i] != 0) return "0x" + wvutil::HexEncode(data, length); - } - // if there are any non-printable characters, just use hex. - for (size_t i = 0; i < actual_length; i++) { - if (!isprint(data[i])) return "0x" + wvutil::HexEncode(data, length); - } - return std::string(reinterpret_cast(data), actual_length); -} +namespace { +// Size of a valid keybox. +constexpr size_t kKeyboxSize = 128; +// Size of a valid keybox token section. +constexpr size_t kKeyDataSize = 72; +// Offset of the system ID in key data. +constexpr size_t kSystemIdOffset = 4; +// Offset of the keybox version in key data. +constexpr size_t kVersionOffset = 0; -bool install_binary_keybox(const uint8_t* keybox, size_t keybox_length) { - printf("Installing keybox %s\n", - wvutil::HexEncode(keybox, keybox_length).c_str()); - OEMCryptoResult status = OEMCrypto_Initialize(); - printf("Init status = %d\n", status); - if (status != OEMCrypto_SUCCESS) { - printf("OEMCrypto Initialize failed: %d\n", status); +// == Utils == + +bool IsRegularFile(const std::string& path) { + struct stat st; + if (stat(path.c_str(), &st) != 0) { + if (errno == ENOENT || errno == ENOTDIR) { + std::cerr << "File does not exist: path = " << path << std::endl; + return false; + } + std::cerr << "Failed to call stat: path = " << path; + std::cerr << ", errno = " << errno << std::endl; return false; } - - status = OEMCrypto_InstallKeyboxOrOEMCert(keybox, keybox_length); - if (status != OEMCrypto_SUCCESS) { - printf("OEMCrypto Install keybox failed: %d\n", status); + if (!S_ISREG(st.st_mode)) { + std::cerr << "Not a regular file: path = " << path << ", mode = "; + std::cerr << std::setfill('0') << std::setw(7) << std::oct << st.st_mode; + std::cerr << std::endl; return false; } - - uint8_t dev_id[128] = {0}; - size_t dev_id_len = 128; - status = OEMCrypto_GetDeviceID(dev_id, &dev_id_len); - if (status != OEMCrypto_SUCCESS) { - printf("OEMCrypto_GetDeviceID failed: %d\n", status); - return false; - } - printf("Device Id = '%s'\n", MaybeHex(dev_id, dev_id_len).c_str()); - - uint8_t key_data[256]; - size_t key_data_len = sizeof(key_data); - status = OEMCrypto_GetKeyData(key_data, &key_data_len); - if (status != OEMCrypto_SUCCESS) { - printf("OEMCrypto_GetKeyData failed: %d\n", status); - return false; - } - uint32_t* data = reinterpret_cast(key_data); - printf("KeyData system_id = %u = 0x%04X, version=%u\n", htonl(data[1]), - htonl(data[1]), htonl(data[0])); - - status = OEMCrypto_Terminate(); - printf("Term status = %d\n", status); return true; } -bool install_xml_keybox(const std::string& xml) { - // This does not yet work. - return false; +void PrintDeviceId(const uint8_t* device_id_u8, size_t device_id_length) { + std::string device_id(reinterpret_cast(device_id_u8), + device_id_length); + // Trim null bytes. + while (!device_id.empty() && device_id.back() == '\0') device_id.pop_back(); + // Check if empty. + if (device_id.empty()) { + std::cerr << "Device ID was all null bytes: "; + std::cerr << "length = " << device_id_length << std::endl; + std::cout << "device_id = " << std::endl; + return; + } + // Check if printable. + if (!std::all_of(device_id.begin(), device_id.end(), ::isprint)) { + device_id = wvutil::b2a_hex(device_id); + } + std::cout << "device_id = " << device_id << std::endl; } -bool install_keybox(const std::string& keybox) { - // Try to install the keybox as binary. if that doesn't work, try xml. - if (install_binary_keybox(reinterpret_cast(keybox.c_str()), - keybox.length())) { - return true; - } - if (install_xml_keybox(keybox)) { - return true; - } - return false; +void PrintSystemId(const uint8_t* key_data) { + // Assumes that |key_data| length as already been verified. + const uint32_t* system_id_ptr = + reinterpret_cast(&key_data[kSystemIdOffset]); + const uint32_t system_id = ntohl(*system_id_ptr); + std::cout << "system_id = " << system_id << std::endl; + std::cout << "hex(system_id) = 0x"; + std::cout << std::setfill('0') << std::setw(8) << std::hex << system_id; + std::cout << std::endl; } +void PrintKeyboxVersion(const uint8_t* key_data) { + // Assumes that |key_data| length as already been verified. + const uint32_t* version_ptr = + reinterpret_cast(&key_data[kVersionOffset]); + const uint32_t version = ntohl(*version_ptr); + std::cout << "version = " << version << std::endl; +} + +// == Primary == + +bool RetrieveKeybox(const std::string& path, std::vector* keybox) { + using StreamIter = std::istreambuf_iterator; + using PosType = std::iostream::pos_type; + std::ifstream fin(path, std::ios::in | std::ios::binary); + if (!fin) { + std::cerr << "Failed to open input file: path = " << path << std::endl; + return false; + } + + // Verify size. + fin.seekg(0, std::ios::end); + if (!fin) { + std::cerr << "Failed to seek to end of file: path = " << path << std::endl; + return false; + } + const PosType keybox_size_pt = fin.tellg(); + if (keybox_size_pt == PosType(-1)) { + std::cerr << "Failed to obtain the file size: path = " << path << std::endl; + return false; + } + const size_t keybox_size = static_cast(keybox_size_pt); + fin.seekg(0, std::ios::beg); + if (!fin) { + std::cerr << "Failed to seek to beginning of file: path = "; + std::cerr << path << std::endl; + return false; + } + if (keybox_size != kKeyboxSize) { + std::cerr << "Unexpected keybox size: "; + std::cerr << "size = " << keybox_size; + std::cerr << ", expected = " << kKeyboxSize; + std::cerr << ", path = " << path << std::endl; + return false; + } + + // Read keybox data. + keybox->clear(); + keybox->reserve(kKeyboxSize); + keybox->assign(StreamIter(fin), StreamIter()); + + if (keybox->size() != kKeyboxSize) { + std::cerr << "Failed to read entire keybox: "; + std::cerr << "read = " << keybox->size(); + std::cerr << ", expected = " << kKeyboxSize; + std::cerr << ", path = " << path << std::endl; + keybox->clear(); + return false; + } + return true; +} + +bool InstallKeyboxAndPrintInfo(const std::vector& keybox) { + std::cout << "Install keybox: " << wvutil::b2a_hex(keybox) << std::endl; + + // Step 1: Initialize. + OEMCryptoResult result = OEMCrypto_Initialize(); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to initialize: result = " << result << std::endl; + return false; + } + std::cout << "OEMCrypto initialized" << std::endl; + + // Step 2: Install keybox. + const OEMCrypto_ProvisioningMethod method = OEMCrypto_GetProvisioningMethod(); + if (method != OEMCrypto_Keybox) { + std::cerr << "OEMCrypto is not keybox type: method = "; + std::cerr << method << std::endl; + OEMCrypto_Terminate(); + return false; + } + result = OEMCrypto_InstallKeyboxOrOEMCert(keybox.data(), keybox.size()); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to install keybox: result = " << result << std::endl; + OEMCrypto_Terminate(); + return false; + } + std::cout << "OEMCrypto keybox installed" << std::endl; + + // Step 3: Verify device ID. + uint8_t buffer[128] = {}; + memset(buffer, 0, sizeof(buffer)); + size_t buffer_length = sizeof(buffer); + result = OEMCrypto_GetDeviceID(buffer, &buffer_length); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to get device ID: result = " << result << std::endl; + OEMCrypto_Terminate(); + return false; + } + PrintDeviceId(buffer, buffer_length); + + // Step 4: Verify system ID and keybox version. + memset(buffer, 0, sizeof(buffer)); + buffer_length = sizeof(buffer); + + result = OEMCrypto_GetKeyData(buffer, &buffer_length); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to get key data: result = " << result << std::endl; + OEMCrypto_Terminate(); + return false; + } + if (buffer_length != kKeyDataSize) { + std::cerr << "Unexpected key data size: "; + std::cerr << "size = " << buffer_length; + std::cerr << ", expected = " << kKeyDataSize << std::endl; + OEMCrypto_Terminate(); + return false; + } + PrintSystemId(buffer); + PrintKeyboxVersion(buffer); + + // Step 5: Cleanup. + result = OEMCrypto_Terminate(); + if (result != OEMCrypto_SUCCESS) { + std::cerr << "Failed to terminate: result = " << result << std::endl; + return false; + } + std::cout << "OEMCrypto terminated" << std::endl; + return true; +} +} // namespace + int main(int argc, char** argv) { if (argc != 2) { - printf("Usage: %s \n", argv[0]); + std::cerr << "Usage: " << argv[0] << " " << std::endl; return 1; } - std::ifstream file(argv[1]); - if (!file) { - printf("Error opening file %s\n", argv[1]); + const std::string keybox_path = argv[1]; + if (!IsRegularFile(keybox_path)) { + std::cerr << "Bad keybox path: " << keybox_path << std::endl; return 1; } - std::stringstream buffer; - buffer << file.rdbuf(); - return install_keybox(buffer.str()) ? 0 : 1; + std::vector keybox; + if (!RetrieveKeybox(keybox_path, &keybox)) { + std::cerr << "Failed to retrieve keybox" << std::endl; + return 1; + } + if (!InstallKeyboxAndPrintInfo(keybox)) { + std::cerr << "Failed to install keybox" << std::endl; + return 1; + } + return 0; }