From 4fa255ea51e19fc9e094013b55e403dcff0a9822 Mon Sep 17 00:00:00 2001 From: Fred Gylys-Colwell Date: Mon, 12 Nov 2018 14:20:29 -0800 Subject: [PATCH] Add Sandbox ID support Merge from master branch of Widevine repo of http://go/wvgerrit/66078 Merge from oemcrypto-v15 branch of Widevine repo of http://go/wvgerrit/64022 This CL updates OEMCrypto ref code, unit tests, and core code for setting the sandbox id before initializing OEMCrypto. Test: unit tests only Test: tested as part of http://go/ag/5501993 Bug: 115834255 Change-Id: Id9831680fe4db1c69413815931cae4bc80df0c01 --- libwvdrmengine/cdm/core/include/properties.h | 1 + .../cdm/core/src/crypto_session.cpp | 7 +++++ .../core/src/oemcrypto_adapter_dynamic.cpp | 28 +++++++++++++++++++ libwvdrmengine/cdm/src/properties_android.cpp | 11 ++++++++ .../oemcrypto/ref/src/oemcrypto_ref.cpp | 5 ++++ .../oemcrypto/test/oec_device_features.cpp | 1 + libwvdrmengine/oemcrypto/test/oec_test_data.h | 2 ++ .../oemcrypto/test/oemcrypto_test.cpp | 3 ++ .../oemcrypto/test/oemcrypto_test_android.cpp | 5 +++- 9 files changed, 62 insertions(+), 1 deletion(-) diff --git a/libwvdrmengine/cdm/core/include/properties.h b/libwvdrmengine/cdm/core/include/properties.h index 6efdf7a3..32d4c40c 100644 --- a/libwvdrmengine/cdm/core/include/properties.h +++ b/libwvdrmengine/cdm/core/include/properties.h @@ -64,6 +64,7 @@ class Properties { std::string* base_path); static bool GetFactoryKeyboxPath(std::string* keybox); static bool GetOEMCryptoPath(std::string* library_name); + static bool GetSandboxId(std::string *sandbox_id); static bool AlwaysUseKeySetIds(); static bool UseProviderIdInProvisioningRequest(); diff --git a/libwvdrmengine/cdm/core/src/crypto_session.cpp b/libwvdrmengine/cdm/core/src/crypto_session.cpp index 976a2cc0..62262056 100644 --- a/libwvdrmengine/cdm/core/src/crypto_session.cpp +++ b/libwvdrmengine/cdm/core/src/crypto_session.cpp @@ -216,7 +216,14 @@ void CryptoSession::Init() { AutoLock auto_lock(crypto_lock_); session_count_ += 1; if (!initialized_) { + std::string sandbox_id; OEMCryptoResult sts; + if (Properties::GetSandboxId(&sandbox_id) && !sandbox_id.empty()) { + sts = OEMCrypto_SetSandbox( + reinterpret_cast(sandbox_id.c_str()), + sandbox_id.length()); + // TODO(blueeyes): it might be worth saving the sandbox id in a metric. + } M_TIME(sts = OEMCrypto_Initialize(), metrics_, oemcrypto_initialize_, sts); if (OEMCrypto_SUCCESS != sts) { LOGE("OEMCrypto_Initialize failed: %d", sts); diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 4c01a5ad..1bc00074 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -41,6 +41,8 @@ static const size_t kMaxGenericEncryptChunkSize = 100*1024; const OEMCryptoResult kOemCryptoResultVendorSpecificError1 = static_cast(10008); +typedef OEMCryptoResult (*L1_SetSandbox_t)(const uint8_t* sandbox_id, + size_t sandbox_id_length); typedef OEMCryptoResult (*L1_Initialize_t)(void); typedef OEMCryptoResult (*L1_Terminate_t)(void); typedef OEMCryptoResult (*L1_OpenSession_t)(OEMCrypto_SESSION* session); @@ -279,6 +281,7 @@ typedef uint32_t (*L1_ResourceRatingTier_t)(void); struct FunctionPointers { uint32_t version; L1_Initialize_t Initialize; + L1_SetSandbox_t SetSandbox; L1_Terminate_t Terminate; L1_OpenSession_t OpenSession; L1_CloseSession_t CloseSession; @@ -398,6 +401,8 @@ class WatchDog { // Called by worker thread. void DoInit() { + // TODO(b/117558570): Level3 does not currently support sandbox. + // Level3_SetSandbox(&sandbox_id_[0], sandbox_id_.length()); status_ = Level3_Initialize(); } @@ -569,6 +574,11 @@ class Adapter { } } + void SetSandbox(const uint8_t* sandbox_id, + size_t sandbox_id_length) { + sandbox_id_.assign(sandbox_id, sandbox_id + sandbox_id_length); + } + OEMCryptoResult Initialize() { /* * To avoid changing the function signature and function contract, use a @@ -652,6 +662,13 @@ class Adapter { wvcdm::metrics::OEMCrypto_INITIALIZED_USING_L3_INVALID_L1); return false; } + if (!sandbox_id_.empty()) { + level1_.SetSandbox = (L1_SetSandbox_t)dlsym(level1_library_, + QUOTE(OEMCrypto_SetSandbox)); + if (level1_.SetSandbox != NULL) { + level1_.SetSandbox(&sandbox_id_[0], sandbox_id_.size()); + } + } OEMCryptoResult st = level1_.Initialize(); if (st != OEMCrypto_SUCCESS) { LOGW("Could not initialize L1. Falling Back to L3."); @@ -961,6 +978,7 @@ class Adapter { struct FunctionPointers level3_; std::map session_map_; wvcdm::Lock session_map_lock_; + std::vector sandbox_id_; // This is just for debugging the map between session ids. // If we add this to the level 3 session id, then the external session // id will match the internal session id in the last two digits. @@ -1212,6 +1230,16 @@ OEMCryptoResult OEMCrypto_CreateOldUsageEntry( } } // namespace wvcdm +extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* sandbox_id, + size_t sandbox_id_length) { + if (!gAdapter.get()) { + gAdapter.reset(new Adapter()); + } + gAdapter->SetSandbox(sandbox_id, sandbox_id_length); + return OEMCrypto_SUCCESS; +} + + extern "C" OEMCryptoResult OEMCrypto_Initialize(void) { if (!gAdapter.get()) { gAdapter.reset(new Adapter()); diff --git a/libwvdrmengine/cdm/src/properties_android.cpp b/libwvdrmengine/cdm/src/properties_android.cpp index c791b501..b469858e 100644 --- a/libwvdrmengine/cdm/src/properties_android.cpp +++ b/libwvdrmengine/cdm/src/properties_android.cpp @@ -151,6 +151,17 @@ bool Properties::GetOEMCryptoPath(std::string* library_name) { return true; } +bool Properties::GetSandboxId(std::string* /* sandbox_id */) { + // TODO(fredgc): If needed, we could support android running on a VM by + // reading the sandbox ID from the file system. If the file system + // does not have a sandbox id, we would generate a random + // one. Another option is to have sandbox id be a system property. + // However, that is enough work not to do it pre-emptively. This + // TODO is just to let future coders know that the framework is in + // place, and should be pretty easy to plumb. + return false; +} + bool Properties::AlwaysUseKeySetIds() { return false; } diff --git a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp index bbe064dc..85affef0 100644 --- a/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp +++ b/libwvdrmengine/oemcrypto/ref/src/oemcrypto_ref.cpp @@ -75,6 +75,11 @@ extern "C" OEMCryptoResult OEMCrypto_Initialize(void) { return OEMCrypto_SUCCESS; } +extern "C" OEMCryptoResult OEMCrypto_SetSandbox(const uint8_t* /*sandbox_id*/, + size_t /*sandbox_id_length*/) { + return OEMCrypto_ERROR_NOT_IMPLEMENTED; +} + extern "C" OEMCryptoResult OEMCrypto_Terminate(void) { if (!crypto_engine) { LOGE("[OEMCrypto_Terminate(): not initialized]"); diff --git a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp index 7f6e7061..8b9dafd1 100644 --- a/libwvdrmengine/oemcrypto/test/oec_device_features.cpp +++ b/libwvdrmengine/oemcrypto/test/oec_device_features.cpp @@ -29,6 +29,7 @@ void DeviceFeatures::Initialize(bool is_cast_receiver, supports_rsa_3072 = false; api_version = 0; derive_key_method = NO_METHOD; + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) { printf("OEMCrypto_Initialize failed. All tests will fail.\n"); return; diff --git a/libwvdrmengine/oemcrypto/test/oec_test_data.h b/libwvdrmengine/oemcrypto/test/oec_test_data.h index 099888dd..390e81a1 100644 --- a/libwvdrmengine/oemcrypto/test/oec_test_data.h +++ b/libwvdrmengine/oemcrypto/test/oec_test_data.h @@ -716,6 +716,8 @@ static const uint8_t kTestKeyRSAEuler_2048[] = { 0x33, 0xe0, 0xdb, 0x03, }; +static const uint8_t kTestSandbox[] = { 0x01, 0x02, 0x03 }; + } // namespace wvoec #endif // CDM_OEC_TEST_DATA_H_ diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp index a0308ec1..d5f00888 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test.cpp @@ -95,6 +95,7 @@ class OEMCryptoClientTest : public ::testing::Test, public SessionUtil { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); LOGD("Running test %s.%s", test_info->test_case_name(), test_info->name()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } @@ -225,6 +226,7 @@ TEST_F(OEMCryptoClientTest, CheckMaxNumberOfSessionsAPI10) { TEST_F(OEMCryptoClientTest, NormalInitTermination) { // Should be able to terminate OEMCrypto, and then restart it. ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Terminate()); + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } @@ -4629,6 +4631,7 @@ class UsageTableTest : public GenericCryptoTest { } virtual void Restart() { + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); EnsureTestKeys(); ASSERT_NO_FATAL_FAILURE(session_.open()); diff --git a/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp b/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp index 21da36c7..77a12ffe 100644 --- a/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp +++ b/libwvdrmengine/oemcrypto/test/oemcrypto_test_android.cpp @@ -23,7 +23,10 @@ namespace wvoec { // These tests are required for LollyPop Android devices. class OEMCryptoAndroidLMPTest : public ::testing::Test { protected: - virtual void SetUp() { ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); } + virtual void SetUp() { + OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox)); + ASSERT_EQ(OEMCrypto_SUCCESS, OEMCrypto_Initialize()); + } virtual void TearDown() { OEMCrypto_Terminate(); } };