diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp index 9ed3f6de..e6ab7cec 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp @@ -6,14 +6,20 @@ // #include "oemcrypto_auth_ref.h" +#include + +#include #include #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 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(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 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(kFakeDeviceId.begin(), kFakeDeviceId.end()); +} + +std::vector 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& 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 diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h index f6ee9ded..3650c557 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h @@ -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 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 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& 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& 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& 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 keybox_; + std::unique_ptr test_keybox_; CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot); }; - } // namespace wvoec_ref #endif // OEMCRYPTO_AUTH_REF_H_ diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp index e329f271..e85cebff 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.cpp @@ -39,9 +39,7 @@ namespace wvoec_ref { // for methods that are configured for specific configurations. CryptoEngine::CryptoEngine(std::unique_ptr&& 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() { diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h index 07d31cfc..394c17e7 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -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& DeviceRootKey() { + std::vector DeviceRootKey() const { return root_of_trust_.DeviceKey(); } - const std::vector& 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 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(); diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp index 0e4a6307..cfb070ad 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.cpp @@ -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 +std::vector ToVector(const uint8_t (&field)[N]) { + return std::vector(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::Create(const uint8_t* keybox_data, + size_t keybox_length) { + std::unique_ptr keybox; + if (keybox_length != kKeyboxSize) { + LOGE("Invalid keybox length: length = %zu", keybox_length); + return keybox; } - if (strncmp(reinterpret_cast(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(&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(&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(buffer); - size_t device_id_length = - strnlen(reinterpret_cast(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 WvKeybox::DeviceId() const { + return ToVector(raw_keybox_.device_id_); +} + +std::vector 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(&raw_keybox_), + kKeyboxSize); } } // namespace wvoec_ref diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.h index 5f65ea70..47b8c070 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_keybox_ref.h @@ -7,38 +7,58 @@ #ifndef OEMCRYPTO_KEYBOX_REF_H_ #define OEMCRYPTO_KEYBOX_REF_H_ -#include "oemcrypto_key_ref.h" +#include +#include + +#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 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 DeviceId() const; + + // Returns the keybox device key directly. Intended to be used + // for key derivation. + std::vector 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& device_id() { return device_id_; } - std::vector& 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 device_id_; - std::vector device_key_; - WvKeyboxKeyData key_data_; - uint8_t magic_[4]; - uint8_t crc_[4]; + WvKeybox() {} + + wvoec::WidevineKeybox raw_keybox_; }; } // namespace wvoec_ref diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp index 3f256466..68728809 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -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& 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( diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp index 15671234..ed58fcf0 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp @@ -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& device_id = ce_->DeviceRootId(); + const std::vector device_id = ce_->DeviceRootId(); OEMCryptoResult result = ODK_PrepareCoreProvisioningRequest( message, message_length, core_message_length, &nonce_values_, device_id.data(), device_id.size());