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
This commit is contained in:
Alex Dale
2023-09-13 15:09:01 -07:00
committed by Robert Shih
parent e0d30c5fc0
commit ac5f0135d5

View File

@@ -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 <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <string.h>
#include <vector>
#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<const char*>(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<const char*>(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;
}
status = OEMCrypto_InstallKeyboxOrOEMCert(keybox, keybox_length);
if (status != OEMCrypto_SUCCESS) {
printf("OEMCrypto Install keybox failed: %d\n", status);
std::cerr << "Failed to call stat: path = " << path;
std::cerr << ", errno = " << errno << 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);
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;
}
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<uint32_t*>(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.
void PrintDeviceId(const uint8_t* device_id_u8, size_t device_id_length) {
std::string device_id(reinterpret_cast<const char*>(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 = <empty>" << 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;
}
void PrintSystemId(const uint8_t* key_data) {
// Assumes that |key_data| length as already been verified.
const uint32_t* system_id_ptr =
reinterpret_cast<const uint32_t*>(&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<const uint32_t*>(&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<uint8_t>* keybox) {
using StreamIter = std::istreambuf_iterator<char>;
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;
}
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<const uint8_t*>(keybox.c_str()),
keybox.length())) {
return true;
}
if (install_xml_keybox(keybox)) {
return true;
}
// 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<size_t>(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<uint8_t>& 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 <filename>\n", argv[0]);
std::cerr << "Usage: " << argv[0] << " <filename>" << 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<uint8_t> 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;
}