Updates to OTA Keybox Reprovisioning
[ Cherry pick of http://ag/15847758 ] Adjust OTA code to account for some design changes and add integration tests. Merge from Widevine repo of http://go/wvgerrit/133775 Change use_test_key to uint32_t type Merge from Widevine repo of http://go/wvgerrit/133774 Cleanup CDM OKP info before tests. Merge from Widevine repo of http://go/wvgerrit/133773 Change context for derivation in OTA keybox solution Merge from Widevine repo of http://go/wvgerrit/133772 Updated OTA keybox key derivation. Merge from Widevine repo of http://go/wvgerrit/133771 Use double provisioning step in integration tests Merge from Widevine repo of http://go/wvgerrit/133770 Erase keybox on initialization for OEMCrypto testbed Merge from Widevine repo of http://go/wvgerrit/133769 Add session id to OEMCrypto OTA functions Merge from Widevine repo of http://go/wvgerrit/133768 Integration test for OTA Keybox reprovisioning Merge from Widevine repo of http://go/wvgerrit/133767 Add test x509 cert for testing Merge from Widevine repo of http://go/wvgerrit/133766 OTA Keybox basic functionality in testbed Merge from Widevine repo of http://go/wvgerrit/133765 Update OTA test script to use newer build scripts Merge from Widevine repo of http://go/wvgerrit/133764 Adjust comment stype for doxygen Test: MediaDrmTest and Android unittests Bug: 190505461 Bug: 190505461 Bug: 190505461 bug: 187646550 Bug: 187646550 Bug: 187646550 Bug: 187646550 Bug: 190505461 Bug: 187646550 Bug: 188228998 Bug: 190505461 Bug: 187646550 Change-Id: I41ff819a1fd8aca2e20adb25127fa0d9c4879b01
This commit is contained in:
committed by
Alex Dale
parent
6afcbab5cf
commit
7397f77343
@@ -329,6 +329,7 @@ class CryptoSession {
|
||||
#if defined(UNIT_TEST)
|
||||
friend class CertificateProvisioningTest;
|
||||
friend class WvCdmTestBase;
|
||||
friend class CdmOtaKeyboxTest;
|
||||
#endif
|
||||
|
||||
// The global factory method can be set to generate special crypto sessions
|
||||
|
||||
@@ -3041,9 +3041,10 @@ okp::SystemFallbackPolicy* CryptoSession::GetOkpFallbackPolicy() {
|
||||
CdmResponseType CryptoSession::PrepareOtaProvisioningRequest(
|
||||
bool use_test_key, std::string* request) {
|
||||
RETURN_IF_NULL(request, PARAMETER_NULL);
|
||||
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
|
||||
size_t buffer_length = 0;
|
||||
OEMCryptoResult status =
|
||||
OEMCrypto_GenerateOTARequest(nullptr, &buffer_length, use_test_key);
|
||||
OEMCryptoResult status = OEMCrypto_GenerateOTARequest(
|
||||
oec_session_id_, nullptr, &buffer_length, use_test_key);
|
||||
if (status != OEMCrypto_ERROR_SHORT_BUFFER)
|
||||
return MapOEMCryptoResult(status, UNKNOWN_ERROR,
|
||||
"PrepareOtaProvisioningRequest");
|
||||
@@ -3053,7 +3054,8 @@ CdmResponseType CryptoSession::PrepareOtaProvisioningRequest(
|
||||
}
|
||||
request->resize(buffer_length);
|
||||
uint8_t* buf = reinterpret_cast<uint8_t*>(&request->front());
|
||||
status = OEMCrypto_GenerateOTARequest(buf, &buffer_length, use_test_key);
|
||||
status = OEMCrypto_GenerateOTARequest(oec_session_id_, buf, &buffer_length,
|
||||
use_test_key ? 1 : 0);
|
||||
if (OEMCrypto_SUCCESS != status) {
|
||||
request->clear();
|
||||
} else if (buffer_length != request->size()) {
|
||||
@@ -3065,9 +3067,10 @@ CdmResponseType CryptoSession::PrepareOtaProvisioningRequest(
|
||||
|
||||
CdmResponseType CryptoSession::LoadOtaProvisioning(
|
||||
bool use_test_key, const std::string& response) {
|
||||
RETURN_IF_NOT_OPEN(CRYPTO_SESSION_NOT_OPEN);
|
||||
const OEMCryptoResult status = OEMCrypto_ProcessOTAKeybox(
|
||||
reinterpret_cast<const uint8_t*>(response.data()), response.size(),
|
||||
use_test_key);
|
||||
oec_session_id_, reinterpret_cast<const uint8_t*>(response.data()),
|
||||
response.size(), use_test_key ? 1 : 0);
|
||||
return MapOEMCryptoResult(status, UNKNOWN_ERROR, "LoadOtaProvisioning");
|
||||
}
|
||||
|
||||
|
||||
@@ -318,12 +318,14 @@ typedef OEMCryptoResult (*L1_LoadProvisioning_t)(
|
||||
size_t signature_length, uint8_t* wrapped_private_key,
|
||||
size_t* wrapped_private_key_length);
|
||||
typedef uint32_t (*L1_MinorAPIVersion_t)();
|
||||
typedef OEMCryptoResult (*L1_GenerateOTARequest_t)(uint8_t* buffer,
|
||||
typedef OEMCryptoResult (*L1_GenerateOTARequest_t)(OEMCrypto_SESSION session,
|
||||
uint8_t* buffer,
|
||||
size_t* buffer_length,
|
||||
bool use_test_key);
|
||||
typedef OEMCryptoResult (*L1_ProcessOTAKeybox_t)(const uint8_t* buffer,
|
||||
uint32_t use_test_key);
|
||||
typedef OEMCryptoResult (*L1_ProcessOTAKeybox_t)(OEMCrypto_SESSION session,
|
||||
const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
bool use_test_key);
|
||||
uint32_t use_test_key);
|
||||
struct FunctionPointers {
|
||||
wvcdm::CdmSecurityLevel security_level;
|
||||
uint32_t version;
|
||||
@@ -2797,23 +2799,24 @@ extern "C" OEMCryptoResult OEMCrypto_FreeSecureBuffer(
|
||||
return pair.fcn->FreeSecureBuffer(pair.session, output_descriptor, secure_fd);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateOTARequest(uint8_t* buffer,
|
||||
size_t* buffer_length,
|
||||
bool use_test_key) {
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateOTARequest(
|
||||
OEMCrypto_SESSION session, uint8_t* buffer, size_t* buffer_length,
|
||||
uint32_t use_test_key) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (fcn->GenerateOTARequest == nullptr)
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->GenerateOTARequest(buffer, buffer_length, use_test_key);
|
||||
return fcn->GenerateOTARequest(session, buffer, buffer_length, use_test_key);
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ProcessOTAKeybox(const uint8_t* buffer,
|
||||
extern "C" OEMCryptoResult OEMCrypto_ProcessOTAKeybox(OEMCrypto_SESSION session,
|
||||
const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
bool use_test_key) {
|
||||
uint32_t use_test_key) {
|
||||
if (!gAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
const FunctionPointers* fcn = gAdapter->GetFunctionPointers(kLevelDefault);
|
||||
if (!fcn) return OEMCrypto_ERROR_UNKNOWN_FAILURE;
|
||||
if (fcn->ProcessOTAKeybox == nullptr) return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
return fcn->ProcessOTAKeybox(buffer, buffer_length, use_test_key);
|
||||
return fcn->ProcessOTAKeybox(session, buffer, buffer_length, use_test_key);
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateOTARequest(uint8_t* buffer,
|
||||
size_t* buffer_length,
|
||||
bool use_test_key) {
|
||||
extern "C" OEMCryptoResult OEMCrypto_GenerateOTARequest(
|
||||
OEMCrypto_SESSION session, uint8_t* buffer, size_t* buffer_length,
|
||||
uint32_t use_test_key) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
extern "C" OEMCryptoResult OEMCrypto_ProcessOTAKeybox(const uint8_t* buffer,
|
||||
extern "C" OEMCryptoResult OEMCrypto_ProcessOTAKeybox(OEMCrypto_SESSION session,
|
||||
const uint8_t* buffer,
|
||||
size_t buffer_length,
|
||||
bool use_test_key) {
|
||||
uint32_t use_test_key) {
|
||||
return OEMCrypto_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,120 @@
|
||||
// License Agreement.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "crypto_session.h"
|
||||
#include "properties.h"
|
||||
#include "test_base.h"
|
||||
#include "test_printers.h"
|
||||
#include "test_sleep.h"
|
||||
#include "url_request.h"
|
||||
|
||||
using wvcdm::metrics::EngineMetrics;
|
||||
|
||||
namespace wvcdm {
|
||||
TEST(OTAKeyboxTest, TestThatTheBuildFilesWork) { ASSERT_TRUE(true); }
|
||||
class CdmOtaKeyboxTest : public ::testing::Test {
|
||||
public:
|
||||
void SetUp() override {
|
||||
::testing::Test::SetUp();
|
||||
Properties::Init();
|
||||
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());
|
||||
// Some test environments allow the model name of the device to be set
|
||||
// dynamically using an environment variable. The model name will show up
|
||||
// in the license server logs as the part of the device idenfication as
|
||||
// "model_name".
|
||||
std::string model_name =
|
||||
std::string(test_info->test_case_name()) + "." + test_info->name();
|
||||
int overwrite = 1; // Set value even if already set.
|
||||
setenv("MODEL_NAME", model_name.c_str(), overwrite);
|
||||
// Reset the crypto session factory, so that a default one will be created.
|
||||
// For these tests, we do *not* want to use the test crypto session factory
|
||||
// because it automatically installs the test keybox on initialization. We
|
||||
// do not want that because we are testing keybox provisioning.
|
||||
CryptoSession::SetCryptoSessionFactory(nullptr);
|
||||
}
|
||||
|
||||
void Provision(TestCdmEngine* cdm_engine) {
|
||||
ConfigTestEnv config = WvCdmTestBase::default_config_;
|
||||
CdmCertificateType cert_type = kCertificateWidevine;
|
||||
std::string cert_authority;
|
||||
CdmProvisioningRequest prov_request;
|
||||
std::string provisioning_server_url;
|
||||
CdmResponseType result = cdm_engine->GetProvisioningRequest(
|
||||
cert_type, cert_authority, config.provisioning_service_certificate(),
|
||||
kLevelDefault, &prov_request, &provisioning_server_url);
|
||||
ASSERT_EQ(NO_ERROR, result);
|
||||
|
||||
LOGV("Provisioning request: req = %s", prov_request.c_str());
|
||||
|
||||
// Ignore URL provided by CdmEngine. Use ours, as configured
|
||||
// for test vs. production server.
|
||||
provisioning_server_url.assign(config.provisioning_server());
|
||||
|
||||
// Make request.
|
||||
UrlRequest url_request(provisioning_server_url);
|
||||
if (!url_request.is_connected()) {
|
||||
LOGE("Failed to connect to provisioning server: url = %s",
|
||||
provisioning_server_url.c_str());
|
||||
}
|
||||
url_request.PostCertRequestInQueryString(prov_request);
|
||||
|
||||
// Receive and parse response.
|
||||
std::string http_message;
|
||||
ASSERT_TRUE(url_request.GetResponse(&http_message))
|
||||
<< "Failed to get provisioning response";
|
||||
LOGV("http_message: \n%s\n", http_message.c_str());
|
||||
|
||||
std::string cert, wrapped_key;
|
||||
ASSERT_EQ(NO_ERROR, cdm_engine->HandleProvisioningResponse(
|
||||
http_message, kLevelDefault, &cert, &wrapped_key));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CdmOtaKeyboxTest, TestThatTheBuildFilesWork) { ASSERT_TRUE(true); }
|
||||
|
||||
TEST_F(CdmOtaKeyboxTest, BasicTest) {
|
||||
FileSystem file_system;
|
||||
TestCdmEngine cdm_engine(&file_system,
|
||||
std::shared_ptr<EngineMetrics>(new EngineMetrics));
|
||||
CdmSessionId session_id;
|
||||
ConfigTestEnv config = WvCdmTestBase::default_config_;
|
||||
|
||||
CdmResponseType status = cdm_engine.OpenSession(config.key_system(), nullptr,
|
||||
nullptr, &session_id);
|
||||
// If there is no keybox or there is no drm cert, we should get a
|
||||
// NEED_PROVISIONING response. If there is a keybox and a drm cert, there
|
||||
// should be no other error and this test is finished.
|
||||
if (status != NEED_PROVISIONING) {
|
||||
ASSERT_EQ(NO_ERROR, status);
|
||||
std::cout << "Device does not need provisioning. Skipping rest of test.\n";
|
||||
return;
|
||||
}
|
||||
std::cout << "First provisioning process.\n";
|
||||
Provision(&cdm_engine);
|
||||
|
||||
// After the first provisioning pass, we try to open a session again. If the
|
||||
// first provisioning was to install a keybox, this provisioning should be to
|
||||
// install a drm cert. If the first provisioning step installed a drm cert,
|
||||
// there should be no other error and this test is finished.
|
||||
status = cdm_engine.OpenSession(config.key_system(), nullptr, nullptr,
|
||||
&session_id);
|
||||
if (status != NEED_PROVISIONING) {
|
||||
ASSERT_EQ(NO_ERROR, status);
|
||||
std::cout << "Device does not need provisioning. Skipping rest of test.\n";
|
||||
return;
|
||||
}
|
||||
std::cout << "Second provisioning process.\n";
|
||||
Provision(&cdm_engine);
|
||||
|
||||
// After the second provisioning pass, we should be able to open a session
|
||||
// and continue.
|
||||
status = cdm_engine.OpenSession(config.key_system(), nullptr, nullptr,
|
||||
&session_id);
|
||||
ASSERT_EQ(NO_ERROR, status);
|
||||
// Full recovery will be tested with higher level integration tests.
|
||||
}
|
||||
} // namespace wvcdm
|
||||
|
||||
@@ -419,7 +419,6 @@ void WvCdmTestBase::EnsureProvisioned() {
|
||||
std::shared_ptr<EngineMetrics>(new EngineMetrics));
|
||||
CdmResponseType status = cdm_engine.OpenSession(config_.key_system(), nullptr,
|
||||
nullptr, &session_id);
|
||||
|
||||
CdmAppParameterMap app_parameters;
|
||||
CdmKeySetId key_set_id;
|
||||
InitializationData init_data(ISO_BMFF_VIDEO_MIME_TYPE, binary_key_id());
|
||||
@@ -430,7 +429,8 @@ void WvCdmTestBase::EnsureProvisioned() {
|
||||
app_parameters, &key_request);
|
||||
}
|
||||
|
||||
if (status == NEED_PROVISIONING) {
|
||||
// There are situations where we need two provisioning steps.
|
||||
for (int count = 0; count < 2 && status == NEED_PROVISIONING; count++) {
|
||||
Provision();
|
||||
status = cdm_engine.OpenSession(config_.key_system(), nullptr, nullptr,
|
||||
&session_id);
|
||||
@@ -439,7 +439,6 @@ void WvCdmTestBase::EnsureProvisioned() {
|
||||
status = cdm_engine.GenerateKeyRequest(session_id, key_set_id, init_data,
|
||||
kLicenseTypeStreaming,
|
||||
app_parameters, &key_request);
|
||||
ASSERT_EQ(KEY_MESSAGE, status);
|
||||
}
|
||||
ASSERT_EQ(KEY_MESSAGE, status);
|
||||
ASSERT_NE("", session_id) << "Could not open CDM session.";
|
||||
|
||||
@@ -97,9 +97,11 @@ test_name := initialization_data_unittest
|
||||
test_src_dir := ../core/test
|
||||
include $(LOCAL_PATH)/unit-test.mk
|
||||
|
||||
# This test is only intended for devices that support OTA keybox provisioning.
|
||||
test_name := keybox_ota_test
|
||||
test_src_dir := ../core/test
|
||||
include $(LOCAL_PATH)/unit-test.mk
|
||||
test_main := ../core/test/test_main.cpp
|
||||
include $(LOCAL_PATH)/integration-test.mk
|
||||
|
||||
test_name := license_keys_unittest
|
||||
test_src_dir := ../core/test
|
||||
|
||||
Reference in New Issue
Block a user