// Copyright 2016 Google Inc. All Rights Reserved. // // OEMCrypto device features for unit tests // #include "oec_device_features.h" #include #include #include "oec_test_data.h" namespace wvoec { DeviceFeatures global_features; void DeviceFeatures::Initialize(bool is_cast_receiver, bool force_load_test_keybox) { cast_receiver = is_cast_receiver; uses_keybox = false; uses_certificate = false; loads_certificate = false; generic_crypto = false; usage_table = false; supports_rsa_3072 = false; api_version = 0; derive_key_method = NO_METHOD; if (OEMCrypto_SUCCESS != OEMCrypto_Initialize()) { printf("OEMCrypto_Initialize failed. All tests will fail.\n"); return; } uint32_t nonce = 0; uint8_t buffer[1]; 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) { loads_certificate = (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_RewrapDeviceRSAKey(session, buffer, 0, buffer, 0, &nonce, buffer, 0, buffer, buffer, &size)); } else if (provisioning_method == OEMCrypto_OEMCertificate) { // If the device says it uses Provisioning 3.0, then it should be able to // load a DRM certificate. These devices must support RewrapDeviceRSAKey30. 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"); uses_certificate = (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_GenerateRSASignature(session, buffer, 0, buffer, &size, kSign_RSASSA_PSS)); printf("uses_certificate = %s.\n", uses_certificate ? "true" : "false"); generic_crypto = (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_Generic_Encrypt(session, buffer, 0, buffer, OEMCrypto_AES_CBC_128_NO_PADDING, buffer)); printf("generic_crypto = %s.\n", generic_crypto ? "true" : "false"); OEMCrypto_CloseSession(session); api_version = OEMCrypto_APIVersion(); printf("api_version = %d.\n", api_version); // These unit tests only work with new usage tables. We do not test v12 // usage tables. if (api_version > 12) usage_table = OEMCrypto_SupportsUsageTable(); printf("usage_table = %s.\n", usage_table ? "true" : "false"); if (force_load_test_keybox) { derive_key_method = FORCE_TEST_KEYBOX; } else { PickDerivedKey(); } if (api_version >= 13) { 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; } } printf("cast_receiver = %s.\n", cast_receiver ? "true" : "false"); switch (derive_key_method) { case NO_METHOD: printf("NO_METHOD: Cannot derive known session keys.\n"); // Note: cast_receiver left unchanged because set by user on command line. uses_keybox = false; uses_certificate = 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 EXISTING_TEST_KEYBOX: printf("EXISTING_TEST_KEYBOX: Keybox is already the test keybox.\n"); break; case FORCE_TEST_KEYBOX: printf("FORCE_TEST_KEYBOX: User requested calling InstallKeybox.\n"); break; case TEST_PROVISION_30: printf("TEST_PROVISION_30: Device provisioed with OEM Cert.\n"); break; } OEMCrypto_Terminate(); } std::string DeviceFeatures::RestrictFilter(const std::string& initial_filter) { std::string filter = initial_filter; if (!uses_keybox) FilterOut(&filter, "*KeyboxTest*"); if (derive_key_method != FORCE_TEST_KEYBOX) FilterOut(&filter, "*ForceKeybox*"); if (!uses_certificate) FilterOut(&filter, "OEMCrypto*Cert*"); if (!loads_certificate) FilterOut(&filter, "OEMCryptoLoadsCert*"); if (!generic_crypto) FilterOut(&filter, "*GenericCrypto*"); if (!cast_receiver) FilterOut(&filter, "*CastReceiver*"); if (!usage_table) FilterOut(&filter, "*UsageTable*"); if (derive_key_method == NO_METHOD) FilterOut(&filter, "*SessionTest*"); if (provisioning_method != OEMCrypto_OEMCertificate) FilterOut(&filter, "*Prov30*"); if (!supports_rsa_3072) FilterOut(&filter, "*RSAKey3072*"); if (api_version < 9) FilterOut(&filter, "*API09*"); if (api_version < 10) FilterOut(&filter, "*API10*"); if (api_version < 11) FilterOut(&filter, "*API11*"); if (api_version < 12) FilterOut(&filter, "*API12*"); if (api_version < 13) FilterOut(&filter, "*API13*"); // 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() { if (api_version >= 12) { 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: // Fall through to api_version < 12 case. break; case OEMCrypto_ProvisioningError: printf( "ERROR: OEMCrypto_GetProvisioningMethod() returns " "OEMCrypto_ProvisioningError\n"); // Then fall through to api_version < 12 case. break; } } if (uses_keybox) { // If device uses a keybox, try to load the test keybox. if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestKeybox()) { derive_key_method = LOAD_TEST_KEYBOX; } else if (IsTestKeyboxInstalled()) { derive_key_method = EXISTING_TEST_KEYBOX; } } else if (OEMCrypto_ERROR_NOT_IMPLEMENTED != OEMCrypto_LoadTestRSAKey()) { derive_key_method = LOAD_TEST_RSA_KEY; } } bool DeviceFeatures::IsTestKeyboxInstalled() { uint8_t key_data[256]; size_t key_data_len = sizeof(key_data); if (OEMCrypto_GetKeyData(key_data, &key_data_len) != OEMCrypto_SUCCESS) return false; if (key_data_len != sizeof(kTestKeybox.data_)) return false; if (memcmp(key_data, kTestKeybox.data_, key_data_len)) return false; uint8_t dev_id[128] = {0}; size_t dev_id_len = 128; if (OEMCrypto_GetDeviceID(dev_id, &dev_id_len) != OEMCrypto_SUCCESS) return false; // We use strncmp instead of memcmp because we don't really care about the // multiple '\0' characters at the end of the device id. return 0 == strncmp(reinterpret_cast(dev_id), reinterpret_cast(kTestKeybox.device_id_), sizeof(kTestKeybox.device_id_)); } 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; } } 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"; } } } // namespace wvoec