From 9f7e2c4413f150ff30541bbc20c347ea58c40101 Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Thu, 18 Feb 2021 20:00:15 -0800 Subject: [PATCH] Restructed reference root of trust (3/3 OEM Cert) [ Merge of http://go/wvgerrit/116944 ] This change is the last part of a three part change for restructing the root of trust used by the reference implementation. OEM Certificates are now managed by the root of trust of the crypto engine. Previously, OEM certs where handled separately on a session by session basis. Bug: 135283522 Test: oemcrypto_unittests ce_cdm_tests Change-Id: I6cf1fa3fade28baad85b5fce57a8eab6f2ed17c1 --- .../oemcrypto/ref/src/oemcrypto_auth_ref.cpp | 75 +++++++++++++------ .../oemcrypto/ref/src/oemcrypto_auth_ref.h | 29 +++++-- ...crypto_engine_device_properties_prov30.cpp | 34 +++------ .../oemcrypto/ref/src/oemcrypto_engine_ref.h | 33 +++++--- .../oemcrypto/ref/src/oemcrypto_ref.cpp | 9 +-- .../oemcrypto/ref/src/oemcrypto_session.cpp | 9 +++ .../oemcrypto/ref/src/oemcrypto_session.h | 3 + 7 files changed, 120 insertions(+), 72 deletions(-) diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp index 984de937..b62cd39f 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.cpp @@ -177,9 +177,6 @@ static const uint8_t kTestRSAPKCS8PrivateKeyInfo2_2048[] = { 0x72, 0x2c, 0xf7, 0xc1, 0x22, 0x36, 0xd9, 0x18, 0x56, 0xfe, 0x39, 0x28, 0x33, 0xe0, 0xdb, 0x03 }; - -// Filler for returning vector references. -const std::vector kEmptyVector; } // namespace bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) { @@ -187,10 +184,12 @@ bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) { // If provisioning method is something other than ProvisioningError // indicates it has already been initialized before. Must // existing data. - rsa_key_.reset(); - test_rsa_key_.reset(); + drm_cert_key_.reset(); + test_drm_cert_key_.reset(); keybox_.reset(); test_keybox_.reset(); + oem_cert_.reset(); + oem_cert_key_.reset(); } prov_method_ = method; switch (method) { @@ -198,7 +197,7 @@ bool AuthenticationRoot::Initialize(OEMCrypto_ProvisioningMethod method) { std::unique_ptr key = RsaPrivateKey::Load(kPrivateKey, kPrivateKeySize); if (key) { - rsa_key_ = std::move(key); + drm_cert_key_ = std::move(key); } else { // This error message is OK in unit tests which use test certificate. LOGE( @@ -230,8 +229,7 @@ bool AuthenticationRoot::IsValid() const { return HasDeviceKey(); } case OEMCrypto_OEMCertificate: { - // TODO(sigquit): Add OEM Certificate validation. - return true; + return HasOemCertKey() && HasDeviceKey(); } default: { LOGE("Root of trust is not properly initialized"); @@ -251,8 +249,11 @@ OEMCryptoResult AuthenticationRoot::IsKeyboxOrOemCertValid() const { return kb->IsKeyboxValid(); } case OEMCrypto_OEMCertificate: { - LOGW("OEM certificate validation is not implemented"); - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + if (!oem_cert_) { + LOGW("OEM cert is not installed"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + return oem_cert_->IsCertificateValid(); } case OEMCrypto_DrmCertificate: { return OEMCrypto_ERROR_NOT_IMPLEMENTED; @@ -300,7 +301,7 @@ std::vector AuthenticationRoot::DeviceId() const { } if (prov_method_ == OEMCrypto_Keybox) { LOGE("Expected keybox to be set for a device ID"); - return kEmptyVector; + return std::vector(); } return std::vector(kFakeDeviceId.begin(), kFakeDeviceId.end()); } @@ -311,7 +312,7 @@ std::vector AuthenticationRoot::DeviceKey() const { return kb->DeviceKey(); } LOGE("No device key has been set"); - return kEmptyVector; + return std::vector(); } bool AuthenticationRoot::HasDeviceKey() const { return keybox() != nullptr; } @@ -326,7 +327,7 @@ OEMCryptoResult AuthenticationRoot::LoadTestRsaKey() { LOGE("System does not support DRM certificates"); return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - if (test_rsa_key_) { + if (test_drm_cert_key_) { LOGE("Test RSA key is already loaded"); return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; } @@ -337,7 +338,7 @@ OEMCryptoResult AuthenticationRoot::LoadTestRsaKey() { LOGE("Failed to load test RSA key"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - test_rsa_key_ = std::move(key); + test_drm_cert_key_ = std::move(key); return OEMCrypto_SUCCESS; } @@ -399,22 +400,48 @@ OEMCryptoResult AuthenticationRoot::GetKeyData(uint8_t* key_data, return kb->GetKeyData(key_data, key_data_length); } +OEMCryptoResult AuthenticationRoot::InstallOemCertificate( + const uint8_t* private_key, size_t private_key_size, + const uint8_t* public_cert, size_t public_cert_size) { + if (prov_method_ != OEMCrypto_OEMCertificate) { + LOGE("System does not support OEM certificates"); + return OEMCrypto_ERROR_NOT_IMPLEMENTED; + } + if (oem_cert_ || oem_cert_key_) { + LOGE("OEM certificate is already installed"); + return OEMCrypto_ERROR_INSUFFICIENT_RESOURCES; + } + std::unique_ptr oem_cert = OemCertificate::Create( + private_key, private_key_size, public_cert, public_cert_size); + if (!oem_cert) { + LOGE("Failed to install OEM certificate as root of trust"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + if (oem_cert->key_type() != OemCertificate::kRsa) { + LOGE("Only RSA-based OEM certificates supported"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + std::unique_ptr oem_cert_key = + RsaPrivateKey::Load(oem_cert->GetPrivateKey()); + if (!oem_cert_key) { + LOGE("Failed to parse OEM certificate private key"); + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } + oem_cert_ = std::move(oem_cert); + oem_cert_key_ = std::move(oem_cert_key); + return OEMCrypto_SUCCESS; +} + 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; + if (!oem_cert_) { + LOGE("OEM certificate is not installed"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; } - LOGE("OEM certificates have not been implemented on auth root"); - return kEmptyVector; + return oem_cert_->GetPublicCertificate(public_cert, public_cert_length); } } // namespace wvoec_ref diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h index 9050b983..c1ae01db 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_auth_ref.h @@ -15,6 +15,7 @@ #include "OEMCryptoCENC.h" // Needed for enums only. #include "disallow_copy_and_assign.h" #include "oemcrypto_keybox_ref.h" +#include "oemcrypto_oem_cert.h" #include "oemcrypto_rsa_key.h" namespace wvoec_ref { @@ -67,12 +68,12 @@ class AuthenticationRoot { // Returns the shared RSA private key from the built-in DRM // Certificate. std::shared_ptr ShareDrmCertKey() { - return test_rsa_key_ ? test_rsa_key_ : rsa_key_; + return test_drm_cert_key_ ? test_drm_cert_key_ : drm_cert_key_; } RsaPrivateKey* DrmCertKey() const { - return test_rsa_key_ ? test_rsa_key_.get() : rsa_key_.get(); + return test_drm_cert_key_ ? test_drm_cert_key_.get() : drm_cert_key_.get(); } - bool HasDrmCertKey() const { return test_rsa_key_ || rsa_key_; } + bool HasDrmCertKey() const { return test_drm_cert_key_ || drm_cert_key_; } // Loads the system's built-in RSA key. Only implemented for // devices that are that pre-provisioned with a built-in DRM @@ -82,7 +83,7 @@ class AuthenticationRoot { OEMCryptoResult LoadTestRsaKey(); // Removes any installed test RSA key. - void RemoveTestRsaKey() { test_rsa_key_.reset(); } + void RemoveTestRsaKey() { test_drm_cert_key_.reset(); } // Keybox-based root of trust API. @@ -124,6 +125,14 @@ class AuthenticationRoot { // OEM Certificate-base root of trust API. + // Installs an OEM certificate as the root of trust. The provided + // private key and public cert are parsed, but not validated. The + // private key will be made available for sessions to load. + OEMCryptoResult InstallOemCertificate(const uint8_t* private_key, + size_t private_key_size, + const uint8_t* public_cert, + size_t public_cert_size); + // For OEM Cert-based devices, returns the OEM Public Certificate // component of the OEM Certificate. // This method implements the expected behavior of @@ -135,7 +144,9 @@ class AuthenticationRoot { // the OEM private key into a session. // Should only be called for devices that use OEM Certificates // for provisioning. - const std::vector& GetOemPrivateKey() const; + std::shared_ptr ShareOemCertKey() { return oem_cert_key_; } + RsaPrivateKey* OemCertKey() const { return oem_cert_key_.get(); } + bool HasOemCertKey() const { return static_cast(oem_cert_key_); } private: OEMCrypto_ProvisioningMethod prov_method_ = OEMCrypto_ProvisioningError; @@ -143,13 +154,17 @@ class AuthenticationRoot { // DRM certificate. // If no keybox, this is the private key of the baked-in DRM // Certificate. - std::shared_ptr rsa_key_; - std::shared_ptr test_rsa_key_; + std::shared_ptr drm_cert_key_; + std::shared_ptr test_drm_cert_key_; // Keybox data. std::unique_ptr keybox_; std::unique_ptr test_keybox_; + // OEM certificate. + std::unique_ptr oem_cert_; + std::shared_ptr oem_cert_key_; + CORE_DISALLOW_COPY_AND_ASSIGN(AuthenticationRoot); }; } // namespace wvoec_ref diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp index 3b17bb63..96134b99 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_device_properties_prov30.cpp @@ -24,6 +24,15 @@ class Prov30CryptoEngine : public CryptoEngine { explicit Prov30CryptoEngine(std::unique_ptr&& file_system) : CryptoEngine(std::move(file_system)) {} + bool Initialize() override { + if (!CryptoEngine::Initialize()) { + return false; + } + const OEMCryptoResult result = InstallOemCertificate( + kOEMPrivateKey, kOEMPrivateKeySize, kOEMPublicCert, kOEMPublicCertSize); + return result == OEMCrypto_SUCCESS; + } + bool config_local_display_only() { return true; } // Returns the max HDCP version supported. @@ -47,31 +56,6 @@ class Prov30CryptoEngine : public CryptoEngine { return OEMCrypto_OEMCertificate; } - OEMCryptoResult get_oem_certificate(SessionContext* session, - uint8_t* public_cert, - size_t* public_cert_length) { - if (kOEMPublicCertSize == 0) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - if (public_cert_length == nullptr) { - return OEMCrypto_ERROR_UNKNOWN_FAILURE; - } - if (*public_cert_length < kOEMPublicCertSize) { - *public_cert_length = kOEMPublicCertSize; - return OEMCrypto_ERROR_SHORT_BUFFER; - } - *public_cert_length = kOEMPublicCertSize; - if (public_cert == nullptr) { - return OEMCrypto_ERROR_SHORT_BUFFER; - } - memcpy(public_cert, kOEMPublicCert, kOEMPublicCertSize); - if (!session->LoadRsaDrmKey(kOEMPrivateKey, kOEMPrivateKeySize)) { - LOGE("Private RSA Key did not load correctly."); - return OEMCrypto_ERROR_INVALID_RSA_KEY; - } - return OEMCrypto_SUCCESS; - } - // Returns "L3" for a software only library. L1 is for hardware protected // keys and data paths. L2 is for hardware protected keys but no data path // protection. diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h index 70613aff..0fddd30f 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_engine_ref.h @@ -75,8 +75,8 @@ class CryptoEngine { OEMCryptoResult LoadTestRsaKey() { return root_of_trust_.LoadTestRsaKey(); } - OEMCryptoResult IsKeyboxValid() const { - return root_of_trust_.IsKeyboxValid(); + OEMCryptoResult IsKeyboxOrOemCertValid() const { + return root_of_trust_.IsKeyboxOrOemCertValid(); } std::vector DeviceRootKey() const { @@ -97,6 +97,26 @@ class CryptoEngine { return root_of_trust_.GetKeyData(key_data, key_data_length); } + OEMCryptoResult InstallOemCertificate(const uint8_t* private_key, + size_t private_key_size, + const uint8_t* public_cert, + size_t public_cert_size) { + return root_of_trust_.InstallOemCertificate(private_key, private_key_size, + public_cert, public_cert_size); + } + + OEMCryptoResult GetOemPublicCertificate(uint8_t* public_cert, + size_t* public_cert_length) const { + return root_of_trust_.GetOemPublicCertificate(public_cert, + public_cert_length); + } + + std::shared_ptr ShareOemPrivateKey() { + return root_of_trust_.ShareOemCertKey(); + } + + bool HasOemPrivateKey() const { return root_of_trust_.HasOemCertKey(); } + virtual void Terminate(); virtual SessionId OpenSession(); @@ -155,15 +175,6 @@ class CryptoEngine { return OEMCrypto_Keybox; } - virtual OEMCryptoResult get_oem_certificate(uint8_t* public_cert, - size_t* public_cert_length) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - - virtual OEMCryptoResult load_oem_private_key(SessionContext* session) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; - } - // Used for OEMCrypto_IsAntiRollbackHwPresent. virtual bool config_is_anti_rollback_hw_present() { return false; } diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp index 09b78315..0f65f489 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -762,10 +762,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_IsKeyboxOrOEMCertValid(void) { case OEMCrypto_DrmCertificate: return OEMCrypto_SUCCESS; case OEMCrypto_Keybox: - return crypto_engine->IsKeyboxValid(); case OEMCrypto_OEMCertificate: - // TODO(sigquit): verify that the certificate exists and is valid. - return OEMCrypto_SUCCESS; + return crypto_engine->IsKeyboxOrOemCertValid(); default: LOGE("Invalid provisioning method: %d.", crypto_engine->config_provisioning_method()); @@ -797,7 +795,7 @@ OEMCrypto_LoadOEMPrivateKey(OEMCrypto_SESSION session) { LOGE("OEMCrypto_ERROR_INVALID_SESSION"); return OEMCrypto_ERROR_INVALID_SESSION; } - return crypto_engine->load_oem_private_key(session_ctx); + return session_ctx->LoadOemPrivateKey(); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( @@ -811,7 +809,8 @@ OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetOEMPublicCertificate( crypto_engine->config_provisioning_method()); return OEMCrypto_ERROR_NOT_IMPLEMENTED; } - return crypto_engine->get_oem_certificate(public_cert, public_cert_length); + return crypto_engine->GetOemPublicCertificate(public_cert, + public_cert_length); } OEMCRYPTO_API OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* device_id, diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp index 69e219f6..96f0b8ea 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.cpp @@ -296,6 +296,15 @@ OEMCryptoResult SessionContext::RSADeriveKeys( return DeriveKeys(session_key_, mac_key_context, enc_key_context); } +OEMCryptoResult SessionContext::LoadOemPrivateKey() { + if (!ce_->HasOemPrivateKey()) { + LOGE("No OEM private key"); + return OEMCrypto_ERROR_UNKNOWN_FAILURE; + } + rsa_key_ = ce_->ShareOemPrivateKey(); + return OEMCrypto_SUCCESS; +} + OEMCryptoResult SessionContext::PrepAndSignLicenseRequest( uint8_t* message, size_t message_length, size_t* core_message_length, uint8_t* signature, size_t* signature_length) { diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h index fe942ad6..e01054eb 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_session.h @@ -75,6 +75,9 @@ class SessionContext { const std::vector& enc_session_key, const std::vector& mac_context, const std::vector& enc_context); + + virtual OEMCryptoResult LoadOemPrivateKey(); + virtual OEMCryptoResult PrepAndSignLicenseRequest(uint8_t* message, size_t message_length, size_t* core_message_length,