Restructed reference root of trust (1/3 Keybox)

[ Merge of http://go/wvgerrit/115550 ]

This change is the first part of a three part change for restructing
the root of trust used by the reference implementation.

The API of the AuthenticationRoot class has been updated to reflect
the OEMCrypto functions that relate to the root of trust.  This
involves changing the keybox and DRM Cert methods and adding in new
stubs for OEM Certificates.

The WvKeybox now uses a RAII-like interface to ensure that keyboxes
are provisioned correctly or not at all.

Bug: 135283522
Test: oemcrypto_unittests ce_cdm_tests
Change-Id: I3f2baf29c1022e1806b6196fa6650d761785c626
This commit is contained in:
Alex Dale
2021-02-18 19:33:33 -08:00
parent 8c6ce2e4c9
commit e4ee4eb404
8 changed files with 524 additions and 199 deletions

View File

@@ -17,58 +17,113 @@
#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 <size_t N>
std::vector<uint8_t> ToVector(const uint8_t (&field)[N]) {
return std::vector<uint8_t>(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> WvKeybox::Create(const uint8_t* keybox_data,
size_t keybox_length) {
std::unique_ptr<WvKeybox> keybox;
if (keybox_length != kKeyboxSize) {
LOGE("Invalid keybox length: length = %zu", keybox_length);
return keybox;
}
if (strncmp(reinterpret_cast<char*>(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<uint8_t*>(&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<uint8_t*>(&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<const wvoec::WidevineKeybox*>(buffer);
size_t device_id_length =
strnlen(reinterpret_cast<const char*>(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<uint8_t> WvKeybox::DeviceId() const {
return ToVector(raw_keybox_.device_id_);
}
std::vector<uint8_t> 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<const uint8_t*>(&raw_keybox_),
kKeyboxSize);
}
} // namespace wvoec_ref