From 3fd20d9b280725d2970635d8ba351e9319abdc2c Mon Sep 17 00:00:00 2001 From: Rahul Frias Date: Mon, 14 Mar 2022 01:55:20 -0700 Subject: [PATCH] Policy integration tests: use license holder [ Merge of http://go/wvgerrit/143634 ] Refactor the policy integration tests to use the license holder. Bug: 195691232 Test: GtsMediaTestCases on sunfish Change-Id: I58ffa64caec05c617065e4781657e85914f8369e --- .../cdm/core/test/policy_integration_test.cpp | 282 ++++-------------- 1 file changed, 56 insertions(+), 226 deletions(-) diff --git a/libwvdrmengine/cdm/core/test/policy_integration_test.cpp b/libwvdrmengine/cdm/core/test/policy_integration_test.cpp index f3318f4e..2135b951 100644 --- a/libwvdrmengine/cdm/core/test/policy_integration_test.cpp +++ b/libwvdrmengine/cdm/core/test/policy_integration_test.cpp @@ -13,27 +13,15 @@ #include #include "cdm_engine.h" -#include "clock.h" -#include "config_test_env.h" -#include "initialization_data.h" -#include "license_request.h" +#include "license_holder.h" #include "log.h" -#include "metrics_collections.h" #include "oec_device_features.h" #include "test_base.h" #include "test_printers.h" -#include "test_sleep.h" -#include "url_request.h" -#include "wv_cdm_constants.h" + #include "wv_cdm_types.h" namespace wvcdm { - -namespace { -constexpr int kHttpOk = 200; -const std::string kCencMimeType = "cenc"; -} // namespace - // Core Policy Integration Test class CorePIGTest : public WvCdmTestBaseWithEngine { protected: @@ -41,210 +29,44 @@ class CorePIGTest : public WvCdmTestBaseWithEngine { WvCdmTestBase::SetUp(); EnsureProvisioned(); } - - void OpenSession(CdmSessionId* session_id) { - CdmResponseType status = cdm_engine_.OpenSession( - config_.key_system(), nullptr, nullptr, session_id); - ASSERT_EQ(NO_ERROR, status); - ASSERT_TRUE(cdm_engine_.IsOpenSession(*session_id)); - } - - void CloseSession(const CdmSessionId& session_id) { - CdmResponseType status = cdm_engine_.CloseSession(session_id); - ASSERT_EQ(NO_ERROR, status); - ASSERT_FALSE(cdm_engine_.IsOpenSession(session_id)); - } - - // Create a license request for the given content_id and requesting the - // specified license_type. - void GenerateKeyRequest(const CdmSessionId& session_id, - const std::string& content_id, - CdmKeyRequest* key_request, - CdmLicenseType license_type) { - video_widevine::WidevinePsshData pssh; - pssh.set_content_id(content_id); - const std::string init_data_string = MakePSSH(pssh); - const InitializationData init_data(kCencMimeType, init_data_string); - init_data.DumpToLogs(); - CdmAppParameterMap empty_app_parameters; - CdmKeySetId empty_key_set_id; - CdmResponseType result = cdm_engine_.GenerateKeyRequest( - session_id, empty_key_set_id, init_data, license_type, - empty_app_parameters, key_request); - ASSERT_EQ(KEY_MESSAGE, result); - ASSERT_EQ(kKeyRequestTypeInitial, key_request->type); - } - - // Send the request to the server and get the response. - void GetKeyResponse(const CdmKeyRequest& key_request, - std::string* key_response) { - const std::string url = config_.license_server() + config_.client_auth(); - UrlRequest url_request(url); - ASSERT_TRUE(url_request.is_connected()); - - std::string http_response; - url_request.PostRequest(key_request.message); - ASSERT_TRUE(url_request.GetResponse(&http_response)); - int status_code = url_request.GetStatusCode(http_response); - ASSERT_EQ(kHttpOk, status_code); - - LicenseRequest license_request; - license_request.GetDrmMessage(http_response, *key_response); - } - - // Load the license response into the specified session. Verify it has the - // correct license type (either streaming or offline). - void AddKey(const CdmSessionId& session_id, const std::string& key_response, - CdmLicenseType expected_license_type, CdmKeySetId* key_set_id) { - CdmLicenseType license_type; - CdmResponseType status = - cdm_engine_.AddKey(session_id, key_response, &license_type, key_set_id); - ASSERT_EQ(KEY_ADDED, status); - ASSERT_EQ(expected_license_type, license_type); - } - - // Reload the license response into the specified session. - void RestoreKey(const CdmSessionId& session_id, - const CdmKeySetId& key_set_id) { - CdmResponseType status = cdm_engine_.RestoreKey(session_id, key_set_id); - ASSERT_EQ(KEY_ADDED, status); - } - - // Use the key to decrypt. - void Decrypt(const CdmSessionId& session_id, const KeyId& key_id) { - constexpr size_t buffer_size = 500; - const std::vector input(buffer_size, 0); - std::vector output(buffer_size, 0); - const std::vector iv(KEY_IV_SIZE, 0); - ASSERT_EQ(NO_ERROR, Decrypt(session_id, key_id, input, iv, &output)); - } - - // Try to use the key to decrypt, but expect the key has expired. - void FailDecrypt(const CdmSessionId& session_id, const KeyId& key_id, - CdmResponseType expected_status) { - constexpr size_t buffer_size = 500; - const std::vector input(buffer_size, 0); - std::vector output(buffer_size, 0); - const std::vector iv(KEY_IV_SIZE, 0); - CdmResponseType status = Decrypt(session_id, key_id, input, iv, &output); - // If the server knows we cannot handle the key, it would not have given us - // the key. In that case, the status should indicate no key. - if (status != NEED_KEY) { - // Otherwise, we should have gotten the expected error. - ASSERT_EQ(expected_status, status); - } - } - - // Decrypt or fail to decrypt, with the expected status. - CdmResponseType Decrypt(const CdmSessionId& session_id, const KeyId& key_id, - const std::vector& input, - const std::vector& iv, - std::vector* output) { - CdmDecryptionParametersV16 params(key_id); - params.is_secure = false; - CdmDecryptionSample sample(input.data(), output->data(), 0, input.size(), - iv); - CdmDecryptionSubsample subsample(0, input.size()); - sample.subsamples.push_back(subsample); - params.samples.push_back(sample); - return cdm_engine_.DecryptV16(session_id, params); - } - - // Use the key to decrypt to a secure buffer. - void DecryptSecure(const CdmSessionId& session_id, const KeyId& key_id) { - ASSERT_TRUE(wvoec::global_features.test_secure_buffers); - constexpr size_t buffer_size = 500; - const std::vector input(buffer_size, 0); - const std::vector iv(KEY_IV_SIZE, 0); - - // To create a secure buffer, we need to know the OEMCrypto session id. - CdmQueryMap query_map; - cdm_engine_.QueryOemCryptoSessionId(session_id, &query_map); - const std::string oec_session_id_string = - query_map[QUERY_KEY_OEMCRYPTO_SESSION_ID]; - uint32_t oec_session_id = std::stoi(oec_session_id_string); - - int secure_buffer_fid; - OEMCrypto_DestBufferDesc output_descriptor; - output_descriptor.type = OEMCrypto_BufferType_Secure; - output_descriptor.buffer.secure.secure_buffer_length = buffer_size; - ASSERT_EQ( - OEMCrypto_AllocateSecureBuffer(oec_session_id, buffer_size, - &output_descriptor, &secure_buffer_fid), - OEMCrypto_SUCCESS); - - ASSERT_NE(output_descriptor.buffer.secure.secure_buffer, nullptr); - // It is OK if OEMCrypto changes the maximum size, but there must - // still be enough room for our data. - ASSERT_GE(output_descriptor.buffer.secure.secure_buffer_length, - buffer_size); - output_descriptor.buffer.secure.offset = 0; - - // Now create a sample array for the CDM layer. - CdmDecryptionParametersV16 params(key_id); - params.is_secure = true; - CdmDecryptionSample sample(input.data(), - output_descriptor.buffer.secure.secure_buffer, 0, - input.size(), iv); - CdmDecryptionSubsample subsample(0, input.size()); - sample.subsamples.push_back(subsample); - params.samples.push_back(sample); - CdmResponseType status = cdm_engine_.DecryptV16(session_id, params); - - // Free the secure buffer before we check the return status. - OEMCrypto_FreeSecureBuffer(oec_session_id, &output_descriptor, - secure_buffer_fid); - - ASSERT_EQ(status, NO_ERROR); - } }; // An offline license with nonce not required. TEST_F(CorePIGTest, OfflineNoNonce) { - const std::string content_id = "2015_tears"; + LicenseHolder holder("CDM_OfflineNoNonce", &cdm_engine_, config_); + holder.set_can_persist(true); const KeyId key_id = "0000000000000000"; - const CdmLicenseType license_type = kLicenseTypeOffline; - CdmSessionId session_id; - ASSERT_NO_FATAL_FAILURE(OpenSession(&session_id)); - CdmKeyRequest key_request; - ASSERT_NO_FATAL_FAILURE( - GenerateKeyRequest(session_id, content_id, &key_request, license_type)); - std::string key_response; - ASSERT_NO_FATAL_FAILURE(GetKeyResponse(key_request, &key_response)); - CdmKeySetId key_set_id; - ASSERT_NO_FATAL_FAILURE( - AddKey(session_id, key_response, license_type, &key_set_id)); - ASSERT_NO_FATAL_FAILURE(Decrypt(session_id, key_id)); - ASSERT_NO_FATAL_FAILURE(CloseSession(session_id)); - ASSERT_NO_FATAL_FAILURE(OpenSession(&session_id)); - ASSERT_NO_FATAL_FAILURE(RestoreKey(session_id, key_set_id)); - ASSERT_NO_FATAL_FAILURE(Decrypt(session_id, key_id)); - ASSERT_NO_FATAL_FAILURE(CloseSession(session_id)); + ASSERT_NO_FATAL_FAILURE(holder.OpenSession()); + ASSERT_NO_FATAL_FAILURE(holder.FetchLicense()); + ASSERT_NO_FATAL_FAILURE(holder.LoadLicense()); + EXPECT_EQ(NO_ERROR, holder.Decrypt(key_id)); + ASSERT_NO_FATAL_FAILURE(holder.CloseSession()); + // Should be able to close the previous session, open a new session, + // and reload the license. + ASSERT_NO_FATAL_FAILURE(holder.OpenSession()); + ASSERT_NO_FATAL_FAILURE(holder.ReloadLicense()); + EXPECT_EQ(NO_ERROR, holder.Decrypt(key_id)); + ASSERT_NO_FATAL_FAILURE(holder.CloseSession()); } // An offline license with nonce and provider session token. TEST_F(CorePIGTest, OfflineWithPST) { - const std::string content_id = "offline_clip2"; - const KeyId key_id = - "\x32\x60\xF3\x9E\x12\xCC\xF6\x53\x52\x99\x90\x16\x8A\x35\x83\xFF"; - const CdmLicenseType license_type = kLicenseTypeOffline; - CdmSessionId session_id; - ASSERT_NO_FATAL_FAILURE(OpenSession(&session_id)); - CdmKeyRequest key_request; - ASSERT_NO_FATAL_FAILURE( - GenerateKeyRequest(session_id, content_id, &key_request, license_type)); - std::string key_response; - ASSERT_NO_FATAL_FAILURE(GetKeyResponse(key_request, &key_response)); - CdmKeySetId key_set_id; - ASSERT_NO_FATAL_FAILURE( - AddKey(session_id, key_response, license_type, &key_set_id)); - ASSERT_NO_FATAL_FAILURE(Decrypt(session_id, key_id)); - ASSERT_NO_FATAL_FAILURE(CloseSession(session_id)); - ASSERT_NO_FATAL_FAILURE(OpenSession(&session_id)); - ASSERT_NO_FATAL_FAILURE(RestoreKey(session_id, key_set_id)); - ASSERT_NO_FATAL_FAILURE(Decrypt(session_id, key_id)); - ASSERT_NO_FATAL_FAILURE(CloseSession(session_id)); + LicenseHolder holder("CDM_OfflineWithPST", &cdm_engine_, config_); + holder.set_can_persist(true); + const KeyId key_id = "0000000000000000"; + + ASSERT_NO_FATAL_FAILURE(holder.OpenSession()); + ASSERT_NO_FATAL_FAILURE(holder.FetchLicense()); + ASSERT_NO_FATAL_FAILURE(holder.LoadLicense()); + EXPECT_EQ(NO_ERROR, holder.Decrypt(key_id)); + ASSERT_NO_FATAL_FAILURE(holder.CloseSession()); + // Should be able to close the previous session, open a new session, + // and reload the license. + ASSERT_NO_FATAL_FAILURE(holder.OpenSession()); + ASSERT_NO_FATAL_FAILURE(holder.ReloadLicense()); + EXPECT_EQ(NO_ERROR, holder.Decrypt(key_id)); + ASSERT_NO_FATAL_FAILURE(holder.CloseSession()); } // This test verifies that the system can download and install license with a @@ -252,31 +74,39 @@ TEST_F(CorePIGTest, OfflineWithPST) { // a non-secure buffer using this key, but that we can decrypt to a secure // buffer, if the test harness supports secure buffers. TEST_F(CorePIGTest, OfflineHWSecureRequired) { - const std::string content_id = "GTS_HW_SECURE_ALL"; - const KeyId key_id = "0000000000000002"; + LicenseHolder holder("CDM_OfflineHWSecureRequired", &cdm_engine_, config_); + holder.set_can_persist(true); + const KeyId sw_key_id = "0000000000000000"; + const KeyId hw_key_id = "0000000000000001"; - const CdmLicenseType license_type = kLicenseTypeOffline; - CdmSessionId session_id; - ASSERT_NO_FATAL_FAILURE(OpenSession(&session_id)); - CdmKeyRequest key_request; - ASSERT_NO_FATAL_FAILURE( - GenerateKeyRequest(session_id, content_id, &key_request, license_type)); - std::string key_response; - ASSERT_NO_FATAL_FAILURE(GetKeyResponse(key_request, &key_response)); - CdmKeySetId key_set_id; - ASSERT_NO_FATAL_FAILURE( - AddKey(session_id, key_response, license_type, &key_set_id)); - // First we try to decrypt to a non-secure buffer and verify that it fails. - // TODO(b/164517875): This error code should be something actionable. - ASSERT_NO_FATAL_FAILURE(FailDecrypt(session_id, key_id, DECRYPT_ERROR)); + ASSERT_NO_FATAL_FAILURE(holder.OpenSession()); + ASSERT_NO_FATAL_FAILURE(holder.FetchLicense()); + ASSERT_NO_FATAL_FAILURE(holder.LoadLicense()); + EXPECT_EQ(NO_ERROR, holder.Decrypt(sw_key_id)); + ASSERT_NO_FATAL_FAILURE(holder.FailDecrypt(hw_key_id, DECRYPT_ERROR)); // Next, if possible, we try to decrypt to a secure buffer, and verify // success. if (wvoec::global_features.test_secure_buffers) { - ASSERT_NO_FATAL_FAILURE(DecryptSecure(session_id, key_id)); + ASSERT_NO_FATAL_FAILURE(holder.DecryptSecure(hw_key_id)); } else { LOGI("Test harness cannot create secure buffers. test skipped."); } - ASSERT_NO_FATAL_FAILURE(CloseSession(session_id)); + ASSERT_NO_FATAL_FAILURE(holder.CloseSession()); + + // Should be able to close the previous session, open a new session, + // and reload the license. + ASSERT_NO_FATAL_FAILURE(holder.OpenSession()); + ASSERT_NO_FATAL_FAILURE(holder.ReloadLicense()); + EXPECT_EQ(NO_ERROR, holder.Decrypt(sw_key_id)); + ASSERT_NO_FATAL_FAILURE(holder.FailDecrypt(hw_key_id, DECRYPT_ERROR)); + // Next, if possible, we try to decrypt to a secure buffer, and verify + // success. + if (wvoec::global_features.test_secure_buffers) { + ASSERT_NO_FATAL_FAILURE(holder.DecryptSecure(hw_key_id)); + } else { + LOGI("Test harness cannot create secure buffers. test skipped."); + } + ASSERT_NO_FATAL_FAILURE(holder.CloseSession()); } } // namespace wvcdm