Files
android/libwvdrmengine/oemcrypto/test/oec_device_features.cpp
Vicky Min b04fda2908 Skip API and time rollback tests with GTEST_SKIP
Bug: 251240681
Change-Id: Ie1cee828f239ddca03ad18aac4139e2e42038df3
2024-02-22 13:54:52 -08:00

257 lines
9.2 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. Devices with a keybox or OEM Certificate are required to support
// loading a DRM certificate. Other devices are either broken, or they have a
// baked in certificate.
loads_certificate = provisioning_method == OEMCrypto_Keybox ||
provisioning_method == OEMCrypto_OEMCertificate ||
provisioning_method == OEMCrypto_BootCertificateChain;
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;
// 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