Files
android/libwvdrmengine/oemcrypto/test/oec_device_features.cpp
Fred Gylys-Colwell d7ee89bab0 Filter Cast Reciver tests
Merge from Widevine repo of http://go/wvgerrit/169070

This turns on the cast receiver tests for any device that
claims to support this feature. Previously, we had to
explicitly request these tests on the command line.

But since they do not pass for Prov 4.0, we fitler them out
in this case and reference a bug tracking that work.

We also switch to using GTEST_SKIP to skip the tests instead
of modifying the GTEST_FILTER.

Bug: 251240681
Bug: 269310676
Bug: 259455058
Bug: 259454969
Merged from https://widevine-internal-review.googlesource.com/166497

Change-Id: I1bcd749243a474b3f638547aa43c2805e86731af
2023-03-28 20:30:22 +00:00

285 lines
10 KiB
C++

// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine
// License Agreement.
//
// OEMCrypto device features for unit tests
//
#include "oec_device_features.h"
#include <stdio.h>
#include <cstring>
#include "oec_test_data.h"
#include "test_sleep.h"
namespace wvoec {
DeviceFeatures global_features;
void DeviceFeatures::Initialize() {
if (initialized_) return;
uses_keybox = false;
loads_certificate = false;
generic_crypto = false;
usage_table = false;
supports_rsa_3072 = false;
supports_secp256r1 = false;
api_version = 0;
derive_key_method = NO_METHOD;
OEMCrypto_SetSandbox(kTestSandbox, sizeof(kTestSandbox));
const OEMCryptoResult init_status = OEMCrypto_Initialize();
if (OEMCrypto_SUCCESS != init_status) {
printf("OEMCrypto_Initialize failed %d. All tests will fail.\n",
init_status);
return;
}
const OEMCryptoResult api_status = OEMCrypto_SetMaxAPIVersion(kCurrentAPI);
if (api_status != OEMCrypto_SUCCESS &&
api_status != OEMCrypto_ERROR_NOT_IMPLEMENTED) {
// Log error, but continue assuming no error.
printf("OEMCrypto_SetMaxAPIVersion returned %d\n", api_status);
}
const OEMCryptoResult test_mode_status = OEMCrypto_EnterTestMode();
if (OEMCrypto_SUCCESS != test_mode_status) {
printf("OEMCrypto_EnterTestMode returned %d. Tests might fail.\n",
test_mode_status);
};
uint8_t buffer[1];
uint8_t iv[16] = {};
size_t size = 0;
provisioning_method = OEMCrypto_GetProvisioningMethod();
printf("provisioning_method = %s\n",
ProvisioningMethodName(provisioning_method));
uses_keybox =
(OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_GetKeyData(buffer, &size));
printf("uses_keybox = %s.\n", uses_keybox ? "true" : "false");
OEMCrypto_SESSION session;
OEMCryptoResult result = OEMCrypto_OpenSession(&session);
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not open session: %d ----\n", result);
}
// If the device uses a keybox, check to see if loading a certificate is
// installed.
if (provisioning_method == OEMCrypto_Keybox ||
provisioning_method == OEMCrypto_OEMCertificate ||
provisioning_method == OEMCrypto_BootCertificateChain) {
// Devices with a keybox or OEM Certificate are required to support loading
// a DRM certificate.
loads_certificate = true;
} else {
// Other devices are either broken, or they have a baked in certificate.
loads_certificate = false;
}
printf("loads_certificate = %s.\n", loads_certificate ? "true" : "false");
generic_crypto =
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_Generic_Encrypt(buffer, 0, buffer, 0, iv,
OEMCrypto_AES_CBC_128_NO_PADDING, buffer));
printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false");
supports_cas =
(OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_LoadCasECMKeys(session, nullptr, 0, nullptr, nullptr));
printf("supports_cas = %s.\n", supports_cas ? "true" : "false");
OEMCrypto_CloseSession(session);
api_version = OEMCrypto_APIVersion();
printf("api_version = %u.\n", api_version);
if (api_version < kCoreMessagesAPI) {
printf("--------- WARNING: minimum API is %d ----------\n", api_version);
printf("--------- Expect most tests will fail. --------\n");
}
// These unit tests only work with new usage tables. We do not test v12
// usage tables.
usage_table = OEMCrypto_SupportsUsageTable();
printf("usage_table = %s.\n", usage_table ? "true" : "false");
PickDerivedKey();
const uint32_t supported_cert = OEMCrypto_SupportedCertificates();
if (supported_cert & OEMCrypto_Supports_RSA_CAST) {
cast_receiver = true;
}
if (supported_cert & OEMCrypto_Supports_RSA_3072bit) {
supports_rsa_3072 = true;
}
if (supported_cert & OEMCrypto_Supports_ECC_secp256r1) {
supports_secp256r1 = true;
}
printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false");
printf("supports_rsa_3072 = %s.\n", supports_rsa_3072 ? "true" : "false");
printf("supports_secp256r1 = %s.\n", supports_secp256r1 ? "true" : "false");
resource_rating = OEMCrypto_ResourceRatingTier();
printf("resource_rating = %u, security level %u.\n", resource_rating,
static_cast<unsigned int>(OEMCrypto_SecurityLevel()));
uint32_t decrypt_hash_type = OEMCrypto_SupportsDecryptHash();
supports_crc = (decrypt_hash_type == OEMCrypto_CRC_Clear_Buffer);
if (supports_crc) {
printf("Decrypt hashes will be tested.\n");
} else {
printf("Decrypt hashes will not be tested -- %s.\n",
decrypt_hash_type == OEMCrypto_Hash_Not_Supported
? "not supported"
: "partner defined hash");
}
switch (derive_key_method) {
case NO_METHOD:
printf("NO_METHOD: Cannot derive known session keys.\n");
uses_keybox = false;
loads_certificate = false;
generic_crypto = false;
usage_table = false;
break;
case LOAD_TEST_KEYBOX:
printf("LOAD_TEST_KEYBOX: Call LoadTestKeybox before deriving keys.\n");
break;
case LOAD_TEST_RSA_KEY:
printf("LOAD_TEST_RSA_KEY: Call LoadTestRSAKey before deriving keys.\n");
break;
case TEST_PROVISION_30:
printf("TEST_PROVISION_30: Device provisioned with OEM Cert.\n");
break;
case TEST_PROVISION_40:
printf("TEST_PROVISION_40: Device has boot certificate chain.\n");
break;
}
OEMCrypto_Security_Level security_level = OEMCrypto_SecurityLevel();
supports_level_1 = (security_level == OEMCrypto_Level1);
printf("SecurityLevel is %s (L%u)\n",
supports_level_1 ? "Level 1" : "Not Level 1",
static_cast<unsigned int>(security_level));
CheckSecureBuffers();
OEMCrypto_Terminate();
initialized_ = true;
}
std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) {
std::string filter = initial_filter;
// clang-format off
if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*");
// TODO(b/197141970): Need to revisit OEMCryptoLoadsCert* tests for
// provisioning 4. Disabled here temporarily.
if (!loads_certificate ||
provisioning_method == OEMCrypto_BootCertificateChain)
FilterOut(&filter, "OEMCryptoLoadsCert*");
if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*");
if (!supports_cas) FilterOut(&filter, "*CasOnly*");
if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*");
if (provisioning_method != OEMCrypto_BootCertificateChain)
FilterOut(&filter, "*Prov40*");
if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*");
if (api_version < 17) FilterOut(&filter, "*API17*");
if (api_version < 18) FilterOut(&filter, "*API18*");
// clang-format on
// Some tests may require root access. If user is not root, filter these tests
// out.
if (!wvutil::TestSleep::CanChangeSystemTime()) {
printf("Filtering out TimeRollbackPrevention.\n");
FilterOut(&filter, "*TimeRollbackPrevention*");
} else {
printf("Can change time. I will run TimeRollbackPrevention.\n");
}
// Performance tests take a long time. Filter them out if they are not
// specifically requested.
if (filter.find("Performance") == std::string::npos) {
FilterOut(&filter, "*Performance*");
}
return filter;
}
void DeviceFeatures::PickDerivedKey() {
switch (provisioning_method) {
case OEMCrypto_OEMCertificate:
derive_key_method = TEST_PROVISION_30;
return;
case OEMCrypto_DrmCertificate:
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
derive_key_method = LOAD_TEST_RSA_KEY;
}
return;
case OEMCrypto_Keybox:
if (OEMCrypto_ERROR_NOT_IMPLEMENTED !=
OEMCrypto_LoadTestKeybox(nullptr, 0)) {
derive_key_method = LOAD_TEST_KEYBOX;
}
return;
case OEMCrypto_BootCertificateChain:
derive_key_method = TEST_PROVISION_40;
return;
case OEMCrypto_ProvisioningError:
printf(
"ERROR: OEMCrypto_GetProvisioningMethod() returns "
"OEMCrypto_ProvisioningError\n");
if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) {
derive_key_method = LOAD_TEST_RSA_KEY;
}
return;
}
}
void DeviceFeatures::CheckSecureBuffers() {
output_types_.push_back({false, OEMCrypto_BufferType_Clear});
output_types_.push_back({true, OEMCrypto_BufferType_Clear});
test_secure_buffers = false;
OEMCrypto_SESSION session;
OEMCryptoResult result = OEMCrypto_OpenSession(&session);
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not open session: %d ----\n", result);
return;
}
OEMCrypto_DestBufferDesc output_descriptor;
output_descriptor.type = OEMCrypto_BufferType_Secure;
int secure_fd;
result = OEMCrypto_AllocateSecureBuffer(session, 42, &output_descriptor,
&secure_fd);
if (result == OEMCrypto_ERROR_NOT_IMPLEMENTED) {
printf("Secure buffers will not be tested\n");
return;
}
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not create secure buffer: %d ----\n", result);
return;
}
result = OEMCrypto_FreeSecureBuffer(session, &output_descriptor, secure_fd);
if (result != OEMCrypto_SUCCESS) {
printf("--- ERROR: Could not free secure buffer: %d ----\n", result);
return;
}
printf("Secure buffers will be tested\n");
output_types_.push_back({false, OEMCrypto_BufferType_Secure});
test_secure_buffers = true;
}
void DeviceFeatures::FilterOut(std::string* current_filter,
const std::string& new_filter) {
if (current_filter->find('-') == std::string::npos) {
*current_filter += "-" + new_filter;
} else {
*current_filter += ":" + new_filter;
}
}
// Return the list of output types for the decrypt tests.
const std::vector<OutputType>& DeviceFeatures::GetOutputTypes() {
if (!initialized_) {
Initialize();
}
return output_types_;
}
const char* ProvisioningMethodName(OEMCrypto_ProvisioningMethod method) {
switch (method) {
case OEMCrypto_ProvisioningError:
return "OEMCrypto_ProvisioningError";
case OEMCrypto_DrmCertificate:
return "OEMCrypto_DrmCertificate";
case OEMCrypto_Keybox:
return "OEMCrypto_Keybox";
case OEMCrypto_OEMCertificate:
return "OEMCrypto_OEMCertificate";
case OEMCrypto_BootCertificateChain:
return "OEMCrypto_BootCertificateChain";
}
// Not reachable
return "";
}
} // namespace wvoec