diff --git a/libwvdrmengine/oemcrypto/mock/Android.mk b/libwvdrmengine/oemcrypto/mock/Android.mk index de1378dd..e90fa063 100644 --- a/libwvdrmengine/oemcrypto/mock/Android.mk +++ b/libwvdrmengine/oemcrypto/mock/Android.mk @@ -3,6 +3,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + src/keys.cpp \ src/oemcrypto_engine_device_properties.cpp \ src/oemcrypto_engine_mock.cpp \ src/oemcrypto_key_mock.cpp \ diff --git a/libwvdrmengine/oemcrypto/mock/src/keys.cpp b/libwvdrmengine/oemcrypto/mock/src/keys.cpp new file mode 100644 index 00000000..380e0324 --- /dev/null +++ b/libwvdrmengine/oemcrypto/mock/src/keys.cpp @@ -0,0 +1,10 @@ +// If you are using a baked-in certificate instead of supporting keyboxes, +// you should have received a keys.cpp from Widevine that replaces this file. +// +// If you are not using a baked-in certificate, then you may ignore this file, +// as it intentionally defines an empty key. + +#include "keys.h" + +const uint8_t kPrivateKey[] = { 0, }; +const size_t kPrivateKeySize = 0; diff --git a/libwvdrmengine/oemcrypto/mock/src/keys.h b/libwvdrmengine/oemcrypto/mock/src/keys.h new file mode 100644 index 00000000..e6c0145d --- /dev/null +++ b/libwvdrmengine/oemcrypto/mock/src/keys.h @@ -0,0 +1,11 @@ +// This header is used to access the baked-in certificate if one is in use. +#ifndef KEYS_H_ +#define KEYS_H_ + +#include +#include + +extern const uint8_t kPrivateKey[]; +extern const size_t kPrivateKeySize; + +#endif // KEYS_H_ diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp index 4bfe8ac9..f0b85fb8 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.cpp @@ -5,6 +5,7 @@ #include "oemcrypto_engine_mock.h" #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include +#include "keys.h" #include "log.h" #include "oemcrypto_key_mock.h" #include "oemcrypto_logging.h" @@ -1165,6 +1167,11 @@ CryptoEngine::CryptoEngine() : current_session_(NULL), use_test_keybox_(false), usage_table_(new UsageTable(this)), rsa_key_(NULL) { ERR_load_crypto_strings(); + + if (!supports_keybox() && !LoadPkcs8RsaKey(kPrivateKey, kPrivateKeySize)) { + LOGE("FATAL ERROR: Platform uses a baked-in certificate instead of a " + "keybox, but the certificate could not be loaded."); + } } CryptoEngine::~CryptoEngine() { @@ -1183,59 +1190,8 @@ bool CryptoEngine::LoadTestRSAKey() { RSA_free(rsa_key_); rsa_key_ = NULL; } - uint8_t *pkcs8_rsa_key - = const_cast(kTestRSAPKCS8PrivateKeyInfo2_2048); - size_t rsa_key_length = sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048); - BIO *bio = BIO_new_mem_buf(pkcs8_rsa_key, rsa_key_length); - if ( bio == NULL ) { - LOGE("[LoadTestRSAKey(): Could not allocate bio buffer]"); - return false; - } - bool success = true; - PKCS8_PRIV_KEY_INFO *pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); - if (pkcs8_pki == NULL) { - LOGE("d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL."); - success = false; - } - EVP_PKEY *evp = NULL; - if (success) { - evp = EVP_PKCS82PKEY(pkcs8_pki); - if (evp == NULL) { - LOGE("EVP_PKCS82PKEY returned NULL."); - success = false; - } - } - if (success) { - rsa_key_ = EVP_PKEY_get1_RSA(evp); - if (rsa_key_ == NULL) { - LOGE("PrivateKeyInfo did not contain an RSA key."); - success = false; - } - } - if (evp != NULL) { - EVP_PKEY_free(evp); - } - if (pkcs8_pki != NULL) { - PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); - } - BIO_free(bio); - if (!success) { - return false; - } - switch (RSA_check_key(rsa_key_)) { - case 1: // valid. - return true; - case 0: // not valid. - LOGE("[LoadTestRSAKey(): rsa key not valid]"); - dump_openssl_error(); - return false; - default: // -1 == check failed. - LOGE("[LoadTestRSAKey(): error checking rsa key]"); - dump_openssl_error(); - return false; - } - - + return LoadPkcs8RsaKey(kTestRSAPKCS8PrivateKeyInfo2_2048, + sizeof(kTestRSAPKCS8PrivateKeyInfo2_2048)); } SessionId CryptoEngine::CreateSession() { @@ -1268,6 +1224,59 @@ SessionContext* CryptoEngine::FindSession(SessionId sid) { return NULL; } +bool CryptoEngine::LoadPkcs8RsaKey(const uint8_t* buffer, size_t length) { + assert(buffer != NULL); + uint8_t* pkcs8_rsa_key = const_cast(buffer); + BIO* bio = BIO_new_mem_buf(pkcs8_rsa_key, length); + if (bio == NULL) { + LOGE("[LoadPkcs8RsaKey(): Could not allocate bio buffer]"); + return false; + } + bool success = true; + PKCS8_PRIV_KEY_INFO* pkcs8_pki = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL); + if (pkcs8_pki == NULL) { + LOGE("[LoadPkcs8RsaKey(): d2i_PKCS8_PRIV_KEY_INFO_bio returned NULL]"); + success = false; + } + EVP_PKEY* evp = NULL; + if (success) { + evp = EVP_PKCS82PKEY(pkcs8_pki); + if (evp == NULL) { + LOGE("[LoadPkcs8RsaKey(): EVP_PKCS82PKEY returned NULL]"); + success = false; + } + } + if (success) { + rsa_key_ = EVP_PKEY_get1_RSA(evp); + if (rsa_key_ == NULL) { + LOGE("[LoadPkcs8RsaKey(): PrivateKeyInfo did not contain an RSA key]"); + success = false; + } + } + if (evp != NULL) { + EVP_PKEY_free(evp); + } + if (pkcs8_pki != NULL) { + PKCS8_PRIV_KEY_INFO_free(pkcs8_pki); + } + BIO_free(bio); + if (!success) { + return false; + } + switch (RSA_check_key(rsa_key_)) { + case 1: // valid. + return true; + case 0: // not valid. + LOGE("[LoadPkcs8RsaKey(): rsa key not valid]"); + dump_openssl_error(); + return false; + default: // -1 == check failed. + LOGE("[LoadPkcs8RsaKey(): error checking rsa key]"); + dump_openssl_error(); + return false; + } +} + // Internal utility function to decrypt the message bool SessionContext::DecryptMessage(const std::vector& key, const std::vector& iv, diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h index 27eeb8df..560d131c 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_engine_mock.h @@ -261,6 +261,8 @@ class CryptoEngine { const char* security_level(); private: + bool LoadPkcs8RsaKey(const uint8_t* buffer, size_t length); + SessionContext* current_session_; ActiveSessions sessions_; WvKeybox keybox_; diff --git a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp index 58fb0392..39105df2 100644 --- a/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp +++ b/libwvdrmengine/oemcrypto/mock/src/oemcrypto_mock.cpp @@ -4,7 +4,9 @@ // #include "OEMCryptoCENC.h" +#include #include +#include #include #include #include @@ -22,6 +24,10 @@ #include "string_conversions.h" #include "wv_cdm_constants.h" +namespace { +const uint8_t kBakedInCertificateMagicBytes[] = { 0xDE, 0xAD, 0xBE, 0xEF }; +} // namespace + namespace wvoec_mock { static CryptoEngine* crypto_engine = NULL; @@ -994,7 +1000,15 @@ OEMCryptoResult OEMCrypto_LoadDeviceRSAKey(OEMCrypto_SESSION session, return OEMCrypto_ERROR_UNKNOWN_FAILURE; } if (!crypto_engine->supports_keybox()) { - return OEMCrypto_ERROR_NOT_IMPLEMENTED; + // If we are not using keyboxes, the "wrapped RSA key" should actually be + // the magic value for baked-in certificates. + if (wrapped_rsa_key_length != sizeof(kBakedInCertificateMagicBytes) || + memcmp(kBakedInCertificateMagicBytes, wrapped_rsa_key, + wrapped_rsa_key_length) != 0) { + return OEMCrypto_ERROR_INVALID_RSA_KEY; + } else { + return OEMCrypto_SUCCESS; + } } const WrappedRSAKey* wrapped = reinterpret_cast(wrapped_rsa_key);