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

@@ -6,14 +6,20 @@
// //
#include "oemcrypto_auth_ref.h" #include "oemcrypto_auth_ref.h"
#include <string.h>
#include <string>
#include <vector> #include <vector>
#include "keys.h" #include "keys.h"
#include "log.h" #include "log.h"
#include "oemcrypto_rsa_key_shared.h"
namespace wvoec_ref {
namespace { 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 // A 2048 bit RSA key in PKCS#8 PrivateKeyInfo format
// This is the RSA Test Key. This key is not derived // This is the RSA Test Key. This key is not derived
// from any Widevine authentication root. // from any Widevine authentication root.
@@ -172,32 +178,240 @@ static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03
}; };
// Filler for returning vector references.
const std::vector<uint8_t> kEmptyVector;
} // namespace } // namespace
namespace wvoec_ref { bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) {
if (prov_method_ != OEMCrypto_ProvisioningError) {
AuthenticationRoot::AuthenticationRoot(OEMCrypto_ProvisioningMethod method) : // If provisioning method is something other than ProvisioningError
provisioning_method_(method), // indicates it has already been initialized before. Must
use_test_keybox_(false) { // existing data.
if ((provisioning_method_ == OEMCrypto_DrmCertificate) && rsa_key_set_ = false;
!rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) { rsa_key_.reset();
test_rsa_key_.reset();
keybox_.reset();
test_keybox_.reset();
}
prov_method_ = method;
switch (method) {
case OEMCrypto_DrmCertificate: {
rsa_key_set_ = rsa_key_.LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize);
if (!rsa_key_set_) {
// This error message is OK in unit tests which use test certificate. // This error message is OK in unit tests which use test certificate.
LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a " LOGE(
"FATAL ERROR: Platform uses a baked-in certificate instead of a "
"keybox, but the certificate could not be loaded."); "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<int>(method));
prov_method_ = OEMCrypto_ProvisioningError;
return false;
}
}
} }
KeyboxError AuthenticationRoot::ValidateKeybox() { bool AuthenticationRoot::IsValid() const {
return keybox().Validate(); switch (prov_method_) {
case OEMCrypto_DrmCertificate: {
return rsa_key_set_ && HasDeviceKey();
}
case OEMCrypto_Keybox: {
return HasDeviceKey();
}
case OEMCrypto_OEMCertificate: {
// TODO(sigquit): Add OEM Certificate validation.
return true;
}
default: {
LOGE("Root of trust is not properly initialized");
return false;
}
}
} }
bool AuthenticationRoot::LoadTestRsaKey() { OEMCryptoResult AuthenticationRoot::IsKeyboxOrOemCertValid() const {
return rsa_key_.LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048, switch (prov_method_) {
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); case OEMCrypto_Keybox: {
WvKeybox* kb = keybox();
if (kb == nullptr) {
LOGW("Null keybox cannot be validated");
return OEMCrypto_ERROR_KEYBOX_INVALID;
}
return kb->IsKeyboxValid();
}
case OEMCrypto_OEMCertificate: {
LOGW("OEM certificate validation is not implemented");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
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() { OEMCryptoResult AuthenticationRoot::GetDeviceId(
return NO_ERROR == ValidateKeybox(); 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<uint8_t> 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 kEmptyVector;
}
return std::vector<uint8_t>(kFakeDeviceId.begin(), kFakeDeviceId.end());
}
std::vector<uint8_t> AuthenticationRoot::DeviceKey() const {
WvKeybox* kb = keybox();
if (kb != nullptr) {
return kb->DeviceKey();
}
LOGE("No device key has been set");
return kEmptyVector;
}
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_rsa_key_.get() != nullptr) {
LOGE("Test RSA key is already loaded");
return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES;
}
if (!test_rsa_key_.LoadPkcs8RsaKey(
kTestRSAPKCS8PrivateKeyInfo2_2048,
sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048))) {
LOGE("Failed to load test RSA key");
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
}
rsa_key_set_ = true;
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::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;
}
LOGE("OEM certificates have not been implemented on auth root");
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
}
const std::vector<uint8_t>& AuthenticationRoot::GetOemPrivateKey() const {
if (prov_method_ != OEMCrypto_OEMCertificate) {
LOGE("System does not support OEM certificates");
return kEmptyVector;
}
LOGE("OEM certificates have not been implemented on auth root");
return kEmptyVector;
}
} // namespace wvoec_ref } // namespace wvoec_ref

View File

@@ -21,61 +21,141 @@
#include "oemcrypto_types.h" #include "oemcrypto_types.h"
namespace wvoec_ref { namespace wvoec_ref {
// The AuthenticationRoot class contains the OEMCrypto information
// which makes up the "root of trust" of a device.
class AuthenticationRoot { class AuthenticationRoot {
public: public:
explicit AuthenticationRoot(OEMCrypto_ProvisioningMethod method); AuthenticationRoot() {}
~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) { // Checks that the auth root has been properly initialized and can
return keybox().InstallKeybox(keybox_data, keybox_length); // 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<uint8_t> 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<uint8_t> 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.
RSA_shared_ptr& SharedRsaKey() {
return test_rsa_key_.get() != nullptr ? test_rsa_key_ : rsa_key_;
}
RSA* rsa_key() {
return test_rsa_key_.get() != nullptr ? test_rsa_key_.get()
: rsa_key_.get();
} }
const std::vector<uint8_t>& DeviceKey(bool use_real_keybox = false) { // Loads the system's built-in RSA key. Only implemented for
return use_real_keybox ? real_keybox().device_key() : // devices that are that pre-provisioned with a built-in DRM
keybox().device_key(); // Certificate,
// This method implements the expected behavior of
// OEMCrypto_LoadTestRSAKey().
OEMCryptoResult LoadTestRsaKey();
// Removes any installed test RSA key.
void RemoveTestRsaKey() { test_rsa_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<uint8_t>& DeviceId() { // Checks the validity of the keybox regardless of the provisioning
return keybox().device_id(); // method.
} OEMCryptoResult IsKeyboxValid() const;
size_t DeviceTokenLength() { // Installs a clear WV keybox as the root of trust.
return keybox().key_data_length(); // 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);
const uint8_t* DeviceToken() { // Installs a clear test WV keybox. Only settable for devices that
return keybox().key_data(); // 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);
WvKeybox& keybox() { return use_test_keybox_ ? test_keybox_ : keybox_; } // Removes any installed test keybox.
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) { void RemoveTestKeybox() { test_keybox_.reset(); }
use_test_keybox_ = true;
return test_keybox_.InstallKeybox(keybox_data, keybox_length);
}
RSA_shared_ptr& SharedRsaKey() { return rsa_key_; } // Gets the keybox key data.
RSA* rsa_key() { return rsa_key_.get(); } // Implements the expected behavior of OEMCrypto_GetKeyData().
bool LoadTestRsaKey(); OEMCryptoResult GetKeyData(uint8_t* key_data, size_t* key_data_length) const;
void Clear() { use_test_keybox_ = false; }
// OEM Certificate-base root of trust API.
// 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;
// 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.
const std::vector<uint8_t>& GetOemPrivateKey() const;
private: private:
OEMCrypto_ProvisioningMethod provisioning_method_; OEMCrypto_ProvisioningMethod prov_method_ = OEMCrypto_ProvisioningError;
WvKeybox& real_keybox() { return keybox_; }
WvKeybox keybox_;
WvKeybox test_keybox_;
bool use_test_keybox_;
// DRM certificate.
// TODO(b/168544740): Remove |rsa_key_set_| when RSA_shared_ptr has
// been replaced with scoped RsaPrivateKey.
bool rsa_key_set_ = false;
RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate. RSA_shared_ptr rsa_key_; // If no keybox, this is baked in certificate.
RSA_shared_ptr test_rsa_key_;
// Keybox data.
std::unique_ptr<WvKeybox> keybox_;
std::unique_ptr<WvKeybox> test_keybox_;
CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot); CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot);
}; };
} // namespace wvoec_ref } // namespace wvoec_ref
#endif // OEMCRYPTO_AUTH_REF_H_ #endif // OEMCRYPTO_AUTH_REF_H_

View File

@@ -39,9 +39,7 @@ namespace wvoec_ref {
// for methods that are configured for specific configurations. // for methods that are configured for specific configurations.
CryptoEngine::CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& file_system) CryptoEngine::CryptoEngine(std::unique_ptr<wvcdm::FileSystem>&& 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(); ERR_load_crypto_strings();
} }
@@ -53,7 +51,7 @@ bool CryptoEngine::Initialize() {
std::string file_path = GetUsageTimeFileFullPath(); std::string file_path = GetUsageTimeFileFullPath();
LoadOfflineTimeInfo(file_path); LoadOfflineTimeInfo(file_path);
usage_table_.reset(MakeUsageTable()); usage_table_.reset(MakeUsageTable());
return true; return root_of_trust_.Initialize(config_provisioning_method());
} }
void CryptoEngine::Terminate() { void CryptoEngine::Terminate() {

View File

@@ -65,31 +65,40 @@ class CryptoEngine {
virtual bool Initialize(); 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) { OEMCryptoResult InstallKeybox(const uint8_t* keybox, size_t keybox_length) {
return root_of_trust_.InstallKeybox(keybox, keybox_length); return root_of_trust_.InstallKeybox(keybox, keybox_length);
} }
bool UseTestKeybox(const uint8_t* keybox_data, size_t keybox_length) { OEMCryptoResult InstallTestKeybox(const uint8_t* keybox_data,
return root_of_trust_.UseTestKeybox(keybox_data, keybox_length); 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 IsKeyboxValid() const {
return root_of_trust_.IsKeyboxValid();
}
const std::vector<uint8_t>& DeviceRootKey() { std::vector<uint8_t> DeviceRootKey() const {
return root_of_trust_.DeviceKey(); return root_of_trust_.DeviceKey();
} }
const std::vector<uint8_t>& 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<uint8_t> DeviceRootId() const {
return root_of_trust_.DeviceId(); 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 {
const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); } return root_of_trust_.GetKeyData(key_data, key_data_length);
}
virtual void Terminate(); virtual void Terminate();

View File

@@ -17,58 +17,113 @@
#include "wvcrc32.h" #include "wvcrc32.h"
namespace wvoec_ref { 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_assert(sizeof(wvoec::WidevineKeybox) == kKeyboxSize,
static std::string fake_device_id = "device_with_no_keybox"; "Unexpected keybox size");
device_id_.assign(fake_device_id.begin(), fake_device_id.end());
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() { // static
if (!loaded_) { std::unique_ptr<WvKeybox> WvKeybox::Create(const uint8_t* keybox_data,
LOGE("[KEYBOX NOT LOADED]"); size_t keybox_length) {
return OTHER_ERROR; 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) { keybox.reset(new WvKeybox());
LOGE("[KEYBOX HAS BAD MAGIC]"); memcpy(reinterpret_cast<uint8_t*>(&keybox->raw_keybox_), keybox_data,
return BAD_MAGIC; kKeyboxSize);
} return keybox;
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;
} }
bool WvKeybox::InstallKeybox(const uint8_t* buffer, size_t keyBoxLength) { OEMCryptoResult WvKeybox::GetDeviceId(uint8_t* device_id,
if (keyBoxLength != 128) { size_t* device_id_length) const {
return false; if (device_id_length == nullptr) {
LOGE("Output device ID length buffer is null");
return OEMCrypto_ERROR_INVALID_CONTEXT;
} }
const wvoec::WidevineKeybox* keybox = if (device_id == nullptr && *device_id_length > 0) {
reinterpret_cast<const wvoec::WidevineKeybox*>(buffer); LOGE("Output device ID buffer is null");
size_t device_id_length = return OEMCrypto_ERROR_INVALID_CONTEXT;
strnlen(reinterpret_cast<const char*>(keybox->device_id_), 32); }
device_id_.assign(keybox->device_id_, keybox->device_id_ + device_id_length); if (*device_id_length < kDeviceIdSize) {
device_key_.assign(keybox->device_key_, *device_id_length = kDeviceIdSize;
keybox->device_key_ + sizeof(keybox->device_key_)); return OEMCrypto_ERROR_SHORT_BUFFER;
memcpy(key_data_, keybox->data_, sizeof(keybox->data_)); }
memcpy(magic_, keybox->magic_, sizeof(keybox->magic_)); *device_id_length = kDeviceIdSize;
memcpy(crc_, keybox->crc_, sizeof(keybox->crc_)); memcpy(device_id, raw_keybox_.device_id_, kDeviceIdSize);
loaded_ = true; return OEMCrypto_SUCCESS;
return true; }
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 } // namespace wvoec_ref

View File

@@ -7,38 +7,58 @@
#ifndef OEMCRYPTO_KEYBOX_REF_H_ #ifndef OEMCRYPTO_KEYBOX_REF_H_
#define OEMCRYPTO_KEYBOX_REF_H_ #define OEMCRYPTO_KEYBOX_REF_H_
#include "oemcrypto_key_ref.h" #include <memory>
#include <vector>
#include "OEMCryptoCENCCommon.h"
#include "oemcrypto_types.h"
namespace wvoec_ref { 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 // Widevine keybox
class WvKeybox { class WvKeybox {
public: 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<WvKeybox> 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<uint8_t> DeviceId() const;
// Returns the keybox device key directly. Intended to be used
// for key derivation.
std::vector<uint8_t> 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() {} ~WvKeybox() {}
KeyboxError Validate();
const std::vector<uint8_t>& device_id() { return device_id_; }
std::vector<uint8_t>& 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: private:
bool loaded_; WvKeybox() {}
std::vector<uint8_t> device_id_;
std::vector<uint8_t> device_key_; wvoec::WidevineKeybox raw_keybox_;
WvKeyboxKeyData key_data_;
uint8_t magic_[4];
uint8_t crc_[4];
}; };
} // namespace wvoec_ref } // namespace wvoec_ref

View File

@@ -733,7 +733,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_WrapKeyboxOrOEMCert(
} }
OEMCRYPTO_API OEMCryptoResult 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) { if (crypto_engine == nullptr) {
LOGE("OEMCrypto_InstallKeyboxOrOEMCert: OEMCrypto Not Initialized."); LOGE("OEMCrypto_InstallKeyboxOrOEMCert: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -741,10 +741,7 @@ OEMCrypto_InstallKeyboxOrOEMCert(const uint8_t* keybox, size_t keyBoxLength) {
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED; return OEMCrypto_ERROR_NOT_IMPLEMENTED;
} }
if (crypto_engine->InstallKeybox(keybox, keyBoxLength)) { return crypto_engine->InstallKeybox(keybox, keybox_length);
return OEMCrypto_SUCCESS;
}
return OEMCrypto_ERROR_WRITE_KEYBOX;
} }
OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer, OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer,
@@ -756,10 +753,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestKeybox(const uint8_t* buffer,
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED; return OEMCrypto_ERROR_NOT_IMPLEMENTED;
} }
if (crypto_engine->UseTestKeybox(buffer, length)) { return crypto_engine->InstallTestKeybox(buffer, length);
return OEMCrypto_SUCCESS;
}
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} }
OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) {
@@ -771,22 +765,10 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) {
case OEMCrypto_DrmCertificate: case OEMCrypto_DrmCertificate:
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
case OEMCrypto_Keybox: case OEMCrypto_Keybox:
switch (crypto_engine->ValidateKeybox()) { return crypto_engine->IsKeyboxValid();
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: case OEMCrypto_OEMCertificate:
// TODO(fredgc): verify that the certificate exists and is valid. // TODO(sigquit): verify that the certificate exists and is valid.
return OEMCrypto_SUCCESS; return OEMCrypto_SUCCESS;
break;
default: default:
LOGE("Invalid provisioning method: %d.", LOGE("Invalid provisioning method: %d.",
crypto_engine->config_provisioning_method()); crypto_engine->config_provisioning_method());
@@ -835,32 +817,17 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate(
return crypto_engine->get_oem_certificate(public_cert, public_cert_length); return crypto_engine->get_oem_certificate(public_cert, public_cert_length);
} }
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id,
size_t* idLength) { size_t* device_id_length) {
if (crypto_engine == nullptr) { if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetDeviceID: OEMCrypto Not Initialized."); LOGE("OEMCrypto_GetDeviceID: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} }
const std::vector<uint8_t>& dev_id_string = crypto_engine->DeviceRootId(); return crypto_engine->GetDeviceRootId(device_id, device_id_length);
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;
} }
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* key_data,
size_t* keyDataLength) { size_t* key_data_length) {
if (crypto_engine == nullptr) { if (crypto_engine == nullptr) {
LOGE("OEMCrypto_GetKeyData: OEMCrypto Not Initialized."); LOGE("OEMCrypto_GetKeyData: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
@@ -868,24 +835,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData,
if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) { if (crypto_engine->config_provisioning_method() != OEMCrypto_Keybox) {
return OEMCrypto_ERROR_NOT_IMPLEMENTED; return OEMCrypto_ERROR_NOT_IMPLEMENTED;
} }
size_t length = crypto_engine->DeviceRootTokenLength(); return crypto_engine->GetRootKeyData(key_data, key_data_length);
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;
} }
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData,
@@ -1259,8 +1209,7 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_LoadTestRSAKey() {
LOGE("OEMCrypto_LoadTestRSAKey: OEMCrypto Not Initialized."); LOGE("OEMCrypto_LoadTestRSAKey: OEMCrypto Not Initialized.");
return OEMCrypto_ERROR_UNKNOWN_FAILURE; return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} }
if (crypto_engine->LoadTestRsaKey()) return OEMCrypto_SUCCESS; return crypto_engine->LoadTestRsaKey();
return OEMCrypto_ERROR_UNKNOWN_FAILURE;
} }
OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature( OEMCRYPTO_API OEMCryptoResult OEMCrypto_GenerateRSASignature(

View File

@@ -430,7 +430,7 @@ OEMCryptoResult SessionContext::PrepAndSignProvisioningRequest(
} }
const size_t required_signature_size = ROTSignatureSize(); const size_t required_signature_size = ROTSignatureSize();
if (required_signature_size == 0) return OEMCrypto_ERROR_UNKNOWN_FAILURE; if (required_signature_size == 0) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
const std::vector<uint8_t>& device_id = ce_->DeviceRootId(); const std::vector<uint8_t> device_id = ce_->DeviceRootId();
OEMCryptoResult result = ODK_PrepareCoreProvisioningRequest( OEMCryptoResult result = ODK_PrepareCoreProvisioningRequest(
message, message_length, core_message_length, &nonce_values_, message, message_length, core_message_length, &nonce_values_,
device_id.data(), device_id.size()); device_id.data(), device_id.size());