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:
@@ -6,14 +6,20 @@
|
||||
//
|
||||
#include "oemcrypto_auth_ref.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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.
|
||||
@@ -172,32 +178,240 @@ static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = {
|
||||
0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03
|
||||
};
|
||||
|
||||
// Filler for returning vector references.
|
||||
const std::vector<uint8_t> kEmptyVector;
|
||||
} // 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.
|
||||
rsa_key_set_ = false;
|
||||
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.
|
||||
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<int>(method));
|
||||
prov_method_ = OEMCrypto_ProvisioningError;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyboxError AuthenticationRoot::ValidateKeybox() {
|
||||
return keybox().Validate();
|
||||
bool AuthenticationRoot::IsValid() const {
|
||||
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() {
|
||||
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("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() {
|
||||
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<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
|
||||
|
||||
@@ -21,61 +21,141 @@
|
||||
#include "oemcrypto_types.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<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) {
|
||||
return use_real_keybox ? real_keybox().device_key() :
|
||||
keybox().device_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_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() {
|
||||
return keybox().device_id();
|
||||
}
|
||||
// Checks the validity of the keybox regardless of the provisioning
|
||||
// method.
|
||||
OEMCryptoResult IsKeyboxValid() const;
|
||||
|
||||
size_t DeviceTokenLength() {
|
||||
return keybox().key_data_length();
|
||||
}
|
||||
// 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);
|
||||
|
||||
const uint8_t* DeviceToken() {
|
||||
return keybox().key_data();
|
||||
}
|
||||
// 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);
|
||||
|
||||
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);
|
||||
}
|
||||
// Removes any installed test keybox.
|
||||
void RemoveTestKeybox() { test_keybox_.reset(); }
|
||||
|
||||
RSA_shared_ptr& SharedRsaKey() { return rsa_key_; }
|
||||
RSA* rsa_key() { return rsa_key_.get(); }
|
||||
bool LoadTestRsaKey();
|
||||
void Clear() { use_test_keybox_ = false; }
|
||||
// Gets the keybox key data.
|
||||
// Implements the expected behavior of OEMCrypto_GetKeyData().
|
||||
OEMCryptoResult GetKeyData(uint8_t* key_data, size_t* key_data_length) const;
|
||||
|
||||
// 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:
|
||||
OEMCrypto_ProvisioningMethod provisioning_method_;
|
||||
WvKeybox& real_keybox() { return keybox_; }
|
||||
|
||||
WvKeybox keybox_;
|
||||
WvKeybox test_keybox_;
|
||||
bool use_test_keybox_;
|
||||
OEMCrypto_ProvisioningMethod prov_method_ = OEMCrypto_ProvisioningError;
|
||||
|
||||
// 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 test_rsa_key_;
|
||||
|
||||
// Keybox data.
|
||||
std::unique_ptr<WvKeybox> keybox_;
|
||||
std::unique_ptr<WvKeybox> test_keybox_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot);
|
||||
};
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
#endif // OEMCRYPTO_AUTH_REF_H_
|
||||
|
||||
@@ -39,9 +39,7 @@ namespace wvoec_ref {
|
||||
// for methods that are configured for specific configurations.
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -65,31 +65,40 @@ 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) {
|
||||
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 IsKeyboxValid() const {
|
||||
return root_of_trust_.IsKeyboxValid();
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& DeviceRootKey() {
|
||||
std::vector<uint8_t> DeviceRootKey() const {
|
||||
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();
|
||||
}
|
||||
|
||||
size_t DeviceRootTokenLength() { return root_of_trust_.DeviceTokenLength(); }
|
||||
|
||||
const uint8_t* DeviceRootToken() { return root_of_trust_.DeviceToken(); }
|
||||
OEMCryptoResult GetRootKeyData(uint8_t* key_data,
|
||||
size_t* key_data_length) const {
|
||||
return root_of_trust_.GetKeyData(key_data, key_data_length);
|
||||
}
|
||||
|
||||
virtual void Terminate();
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,38 +7,58 @@
|
||||
#ifndef 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 {
|
||||
|
||||
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<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() {}
|
||||
|
||||
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:
|
||||
bool loaded_;
|
||||
std::vector<uint8_t> device_id_;
|
||||
std::vector<uint8_t> device_key_;
|
||||
WvKeyboxKeyData key_data_;
|
||||
uint8_t magic_[4];
|
||||
uint8_t crc_[4];
|
||||
WvKeybox() {}
|
||||
|
||||
wvoec::WidevineKeybox raw_keybox_;
|
||||
};
|
||||
|
||||
} // namespace wvoec_ref
|
||||
|
||||
@@ -733,7 +733,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 +741,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 +753,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 +765,10 @@ 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;
|
||||
return crypto_engine->IsKeyboxValid();
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
LOGE("Invalid provisioning method: %d.",
|
||||
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);
|
||||
}
|
||||
|
||||
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<uint8_t>& 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 +835,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,
|
||||
@@ -1259,8 +1209,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(
|
||||
|
||||
@@ -430,7 +430,7 @@ OEMCryptoResult SessionContext::PrepAndSignProvisioningRequest(
|
||||
}
|
||||
const size_t required_signature_size = ROTSignatureSize();
|
||||
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(
|
||||
message, message_length, core_message_length, &nonce_values_,
|
||||
device_id.data(), device_id.size());
|
||||
|
||||
Reference in New Issue
Block a user