Merges to android Pi release (part 6)
These are a set of CLs merged from the wv cdm repo to the android repo. * Enable Cast for Android Things build. Author: Thoren Paulson <thoren@google.com> [ Merge of http://go/wvgerrit/29941 ] Added a path to make_cast_libwvlevel3 for Android Things. Added the new system id to the preprocessor guards in android_keybox.cpp. Guarded the references to stderr in page_allocator.cpp because for some reason they don't get resolved when we link against the resulting library. BUG: 63443584 * Resolve memory leaks in use of OpenSSL. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/32700 ] Use of EVP_CIPHER_CTX requires a call to EVP_CIPHER_CTX_cleanup(). * Memory leak in OpenSSL RSA key handling. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/32621 ] This fixes a range of tests. --gtest_filter="CdmDecrypt*" runs five tests and still loses 5 objects totalling 1320 bytes (down from 6200 bytes). * Unit test and mock OEMCrypto memory leaks. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/32640 ] More memory leak cleanup. All remaining leaks are due to calls to CRYPTO_malloc() without the matching free (i.e., calls into openssl). * Clean up memory leaks in tests. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/32600 ] This is the first pass at cleaning up memory leaks. These leaks were affecting a lot of tests, making it hard to identify more serious leaks. Switch to unique_ptr<> pointers for CdmEngine in generic_crypto_unittest tests for FileSystem object in mock OEMCrypto's CryptoEngine object. * Fix broken tests - linux-only & address sanitizer failures. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/32460 ] Fix broken test: WvCdmEnginePreProvTestStaging.ServiceCertificateInitialNoneTest Fix failures found by address sanitizer: DeviceFilesUsageInfoTest.RetrieveByProviderSessionToken DeviceFilesUsageInfoTest.UpdateUsageInfo NOTE: address sanitizer cannot handle EXPECT_CALL macros containing a call with a Contains matcher as an argument, e.g.: EXPECT_CALL(file, Write(Contains(certificate, wrapped_private_key, 0), Gt(certificate.size() + wrapped_private_key.size()))) The address sanitizer reports a crash, issues a report, and stops. A temporary fix is to replace the "Contains()" argument with "_". * Usage license handling corrections Author: Rahul Frias <rfrias@google.com> [ Merge of http://go/wvgerrit/28540 ] Validate that offline licenses that do not contain a provider session token are not handled by the TEE. BUG: 38490468 Test: WV Unit/integration tests, GtsMediaTestCases, WvCdmRequestLicenseTest.ReleaseRetryL3OfflineKeySessionUsageDisabledTest * UsageTableEntry::CopyOldUsageEntry memcpy read out of range. Author: Gene Morgan <gmorgan@google.com> [ Merge of http://go/wvgerrit/32220 ] The function copies the pst from a variable length input vector into a 256 byte character array. But the length argument was a fixed value - MAC_KEY_SIZE. Depending on the actual PST length this can lead to memcpy reading out of bounds or the PST getting truncated. BUG: 71650075 Test: Not currently passing. Will be addressed in a subsequent commit in the chain. Change-Id: I81a4593d7d04d0ef6069ce48d0601b6fbdd85de9
This commit is contained in:
@@ -78,6 +78,7 @@ typedef enum OEMCryptoResult {
|
||||
OEMCrypto_ERROR_LICENSE_INACTIVE = 47,
|
||||
OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE = 48,
|
||||
OEMCrypto_ERROR_ENTRY_IN_USE = 49,
|
||||
OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE = 50, // Reserved. Do not use.
|
||||
} OEMCryptoResult;
|
||||
|
||||
/*
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
|
||||
namespace wvoec_mock {
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(wvcdm::FileSystem* file_system) {
|
||||
return new CryptoEngine(file_system);
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::unique_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new CryptoEngine(std::move(file_system));
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace wvoec_mock {
|
||||
|
||||
class L1CryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
explicit L1CryptoEngine(wvcdm::FileSystem* file_system)
|
||||
: CryptoEngine(file_system) {}
|
||||
explicit L1CryptoEngine(std::unique_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(std::move(file_system)) {}
|
||||
|
||||
bool config_local_display_only() { return true; }
|
||||
|
||||
@@ -28,8 +28,9 @@ class L1CryptoEngine : public CryptoEngine {
|
||||
uint8_t config_security_patch_level() { return 3; }
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(wvcdm::FileSystem* file_system) {
|
||||
return new L1CryptoEngine(file_system);
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::unique_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new L1CryptoEngine(std::move(file_system));
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace wvoec_mock {
|
||||
|
||||
class CertOnlyCryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
explicit CertOnlyCryptoEngine(wvcdm::FileSystem* file_system)
|
||||
: CryptoEngine(file_system) {}
|
||||
explicit CertOnlyCryptoEngine(std::unique_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(std::move(file_system)) {}
|
||||
|
||||
bool config_local_display_only() { return true; }
|
||||
|
||||
@@ -27,8 +27,9 @@ class CertOnlyCryptoEngine : public CryptoEngine {
|
||||
const char* config_security_level() { return "L2"; }
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(wvcdm::FileSystem* file_system) {
|
||||
return new CertOnlyCryptoEngine(file_system);
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::unique_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new CertOnlyCryptoEngine(std::move(file_system));
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
@@ -92,8 +92,8 @@ const std::string kDefaultOptionsFile = "/data/mediadrm/oemcrypto/options.txt";
|
||||
|
||||
class AndroidModifiableCryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
AndroidModifiableCryptoEngine(wvcdm::FileSystem *file_system)
|
||||
: CryptoEngine(file_system),
|
||||
AndroidModifiableCryptoEngine(std::unique_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(std::move(file_system)),
|
||||
options_file_(kDefaultOptionsFile),
|
||||
srm_loaded_(false),
|
||||
srm_version_(0),
|
||||
@@ -587,8 +587,9 @@ class AndroidModifiableCryptoEngine : public CryptoEngine {
|
||||
size_t temp_buffer_length_; // Length of temp buffer currently in use.
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(wvcdm::FileSystem *file_system) {
|
||||
return new AndroidModifiableCryptoEngine(file_system);
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::unique_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new AndroidModifiableCryptoEngine(std::move(file_system));
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace wvoec_mock {
|
||||
|
||||
class Prov30CryptoEngine : public CryptoEngine {
|
||||
public:
|
||||
explicit Prov30CryptoEngine(wvcdm::FileSystem* file_system)
|
||||
: CryptoEngine(file_system) {}
|
||||
explicit Prov30CryptoEngine(std::unique_ptr<wvcdm::FileSystem> file_system)
|
||||
: CryptoEngine(std::move(file_system)) {}
|
||||
|
||||
bool config_local_display_only() { return true; }
|
||||
|
||||
@@ -74,8 +74,9 @@ class Prov30CryptoEngine : public CryptoEngine {
|
||||
const char* config_security_level() { return "L2"; }
|
||||
};
|
||||
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(wvcdm::FileSystem* file_system) {
|
||||
return new Prov30CryptoEngine(file_system);
|
||||
CryptoEngine* CryptoEngine::MakeCryptoEngine(
|
||||
std::unique_ptr<wvcdm::FileSystem> file_system) {
|
||||
return new Prov30CryptoEngine(std::move(file_system));
|
||||
}
|
||||
|
||||
} // namespace wvoec_mock
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace wvoec_mock {
|
||||
// all configurations. See the files oemcrypto_engine_device_properties*.cpp
|
||||
// for methods that are configured for specific configurations.
|
||||
|
||||
CryptoEngine::CryptoEngine(wvcdm::FileSystem* file_system)
|
||||
CryptoEngine::CryptoEngine(std::unique_ptr<wvcdm::FileSystem> file_system)
|
||||
: root_of_trust_(config_provisioning_method()),
|
||||
file_system_(file_system),
|
||||
file_system_(std::move(file_system)),
|
||||
usage_table_(this) {
|
||||
ERR_load_crypto_strings();
|
||||
}
|
||||
@@ -41,6 +41,7 @@ CryptoEngine::~CryptoEngine() {
|
||||
delete it->second;
|
||||
}
|
||||
sessions_.clear();
|
||||
ERR_free_strings();
|
||||
}
|
||||
|
||||
SessionId CryptoEngine::CreateSession() {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
@@ -29,9 +30,12 @@ typedef std::map<SessionId, SessionContext*> ActiveSessions;
|
||||
class CryptoEngine {
|
||||
public:
|
||||
// This is like a factory method, except we choose which version to use at
|
||||
// compile time. It is defined in several source files. The build system
|
||||
// compile time. It is defined in several source files. The build system
|
||||
// should choose which one to use by only linking in the correct one.
|
||||
static CryptoEngine* MakeCryptoEngine(wvcdm::FileSystem* file_system);
|
||||
// NOTE: The caller must instantiate a FileSystem object - ownership
|
||||
// will be transferred to the new CryptoEngine object.
|
||||
static CryptoEngine* MakeCryptoEngine(
|
||||
std::unique_ptr<wvcdm::FileSystem> file_system);
|
||||
|
||||
virtual ~CryptoEngine();
|
||||
|
||||
@@ -86,7 +90,7 @@ class CryptoEngine {
|
||||
virtual OEMCrypto_HDCP_Capability config_maximum_hdcp_capability();
|
||||
|
||||
UsageTable& usage_table() { return usage_table_; }
|
||||
wvcdm::FileSystem* file_system() { return file_system_; }
|
||||
wvcdm::FileSystem* file_system() { return file_system_.get(); }
|
||||
|
||||
// If config_local_display_only() returns true, we pretend we are using a
|
||||
// built-in display, instead of HDMI or WiFi output.
|
||||
@@ -159,14 +163,14 @@ class CryptoEngine {
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit CryptoEngine(wvcdm::FileSystem* file_system);
|
||||
explicit CryptoEngine(std::unique_ptr<wvcdm::FileSystem> file_system);
|
||||
uint8_t* destination_;
|
||||
|
||||
private:
|
||||
ActiveSessions sessions_;
|
||||
AuthenticationRoot root_of_trust_;
|
||||
wvcdm::Lock session_table_lock_;
|
||||
wvcdm::FileSystem* file_system_;
|
||||
std::unique_ptr<wvcdm::FileSystem> file_system_;
|
||||
UsageTable usage_table_;
|
||||
|
||||
CORE_DISALLOW_COPY_AND_ASSIGN(CryptoEngine);
|
||||
|
||||
@@ -51,8 +51,9 @@ extern "C" OEMCryptoResult OEMCrypto_Initialize(void) {
|
||||
crypto_engine = NULL;
|
||||
}
|
||||
// NOTE: This requires a compatible Filesystem implementation.
|
||||
wvcdm::FileSystem* fs = new wvcdm::FileSystem();
|
||||
crypto_engine = CryptoEngine::MakeCryptoEngine(fs);
|
||||
// NOTE: Ownership of the FileSystem object is transferred to CryptoEngine
|
||||
std::unique_ptr<wvcdm::FileSystem> fs(new wvcdm::FileSystem());
|
||||
crypto_engine = CryptoEngine::MakeCryptoEngine(std::move(fs));
|
||||
|
||||
if (!crypto_engine || !crypto_engine->Initialize()) {
|
||||
LOGE("[OEMCrypto_Initialize(): failed]");
|
||||
|
||||
@@ -56,7 +56,7 @@ OldUsageTable::OldUsageTable(CryptoEngine *ce) {
|
||||
table_.clear();
|
||||
|
||||
// Load saved table.
|
||||
wvcdm::FileSystem *file_system = ce->file_system();
|
||||
wvcdm::FileSystem* file_system = ce->file_system();
|
||||
wvcdm::File *file;
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
@@ -208,7 +208,7 @@ void OldUsageTable::Clear() {
|
||||
}
|
||||
|
||||
void OldUsageTable::DeleteFile(CryptoEngine *ce) {
|
||||
wvcdm::FileSystem *file_system = ce->file_system();
|
||||
wvcdm::FileSystem* file_system = ce->file_system();
|
||||
std::string path;
|
||||
// Note: this path is OK for a real implementation, but using security level 1
|
||||
// would be better.
|
||||
|
||||
@@ -74,8 +74,14 @@ bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
|
||||
const EVP_CIPHER* cipher = EVP_aes_128_cbc();
|
||||
CMAC_CTX* cmac_ctx = CMAC_CTX_new();
|
||||
|
||||
if (!cmac_ctx) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CMAC_Init(cmac_ctx, &key[0], key.size(), cipher, 0)) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -85,6 +91,7 @@ bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
|
||||
|
||||
if (!CMAC_Update(cmac_ctx, &message[0], message.size())) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -92,6 +99,7 @@ bool SessionContext::DeriveKey(const std::vector<uint8_t>& key,
|
||||
uint8_t res[128];
|
||||
if (!CMAC_Final(cmac_ctx, res, &reslen)) {
|
||||
LOGE("[DeriveKey(): OEMCrypto_ERROR_CMAC_FAILURE]");
|
||||
CMAC_CTX_free(cmac_ctx);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1291,6 +1299,7 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
|
||||
EVP_CIPHER_CTX_set_padding(&ctx, 0);
|
||||
if (!EVP_DecryptInit_ex(&ctx, EVP_aes_128_ctr(), NULL, key_u8, aes_iv_u8)) {
|
||||
LOGE("[DecryptCTR(): EVP_INIT ERROR]");
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
|
||||
@@ -1310,6 +1319,7 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
|
||||
if (!EVP_DecryptUpdate(&ctx, &clear_data[l], &out_len, &cipher_data[l],
|
||||
decrypt_length)) {
|
||||
LOGE("[DecryptCTR(): EVP_UPDATE_ERROR]");
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
l += decrypt_length;
|
||||
@@ -1319,6 +1329,7 @@ OEMCryptoResult SessionContext::DecryptCTR(const uint8_t* key_u8,
|
||||
if (!EVP_DecryptFinal_ex(
|
||||
&ctx, &clear_data[cipher_data_length - remaining], & final)) {
|
||||
LOGE("[DecryptCTR(): EVP_FINAL_ERROR]");
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
return OEMCrypto_ERROR_DECRYPT_FAILED;
|
||||
}
|
||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||
|
||||
@@ -314,7 +314,8 @@ OEMCryptoResult UsageTableEntry::CopyOldUsageEntry(
|
||||
} else {
|
||||
data_.pst_length = pst.size();
|
||||
}
|
||||
memcpy(data_.pst, &pst[0], wvcdm::MAC_KEY_SIZE);
|
||||
memcpy(data_.pst, &pst[0], data_.pst_length);
|
||||
data_.pst[data_.pst_length] = '\0';
|
||||
return OEMCrypto_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -656,7 +657,8 @@ bool UsageTable::LoadGenerationNumber(bool or_make_new_one) {
|
||||
// On a real implementation, you should NOT put the generation number in
|
||||
// a file in user space. It should be stored in secure memory.
|
||||
std::string filename = path + "GenerationNumber.dat";
|
||||
wvcdm::File* file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
|
||||
wvcdm::File* file = file_system->Open(filename,
|
||||
wvcdm::FileSystem::kReadOnly);
|
||||
if (!file) {
|
||||
if (or_make_new_one) {
|
||||
RAND_bytes(reinterpret_cast<uint8_t*>(&master_generation_number_),
|
||||
|
||||
@@ -6,6 +6,7 @@ LOCAL_MODULE:=oemcrypto_test
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
LOCAL_MODULE_OWNER := widevine
|
||||
LOCAL_PROPRIETARY_MODULE := true
|
||||
|
||||
# When built, explicitly put it in the DATA/bin directory.
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/bin
|
||||
|
||||
@@ -30,7 +30,7 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils \
|
||||
libdl \
|
||||
liblog \
|
||||
libmedia \
|
||||
libmedia_omx \
|
||||
libstagefright_foundation \
|
||||
libutils \
|
||||
libz \
|
||||
|
||||
@@ -2600,6 +2600,7 @@ TEST_F(OEMCryptoLoadsCertificate, RSAPerformance) {
|
||||
sts = OEMCrypto_GenerateRSASignature(s.session_id(), &licenseRequest[0],
|
||||
licenseRequest.size(), signature,
|
||||
&signature_length, kSign_RSASSA_PSS);
|
||||
delete[] signature;
|
||||
ASSERT_EQ(OEMCrypto_SUCCESS, sts);
|
||||
count++;
|
||||
gettimeofday(&end_time, NULL);
|
||||
|
||||
Reference in New Issue
Block a user