diff options
author | Darren Krahn <dkrahn@google.com> | 2015-11-10 18:57:08 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2015-11-10 18:57:08 +0000 |
commit | 6c4a59b0f8c09db267d71313413ceaa7713924bb (patch) | |
tree | 94ecd16f51b960ff14e1a17aeab757292fff5725 | |
parent | 0768b9943cc0b4f8377eafb9486f4f17177378ed (diff) | |
parent | 296727f895b37f5647618bd1b486de6faa5ed423 (diff) | |
download | security-6c4a59b0f8c09db267d71313413ceaa7713924bb.tar.gz |
Merge "keystore: Add a test suitable for Brillo PTS."
am: 296727f895
* commit '296727f895b37f5647618bd1b486de6faa5ed423':
keystore: Add a test suitable for Brillo PTS.
-rw-r--r-- | keystore/keystore_cli_v2.cpp | 276 |
1 files changed, 270 insertions, 6 deletions
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp index 4f4040d3..3f5feb77 100644 --- a/keystore/keystore_cli_v2.cpp +++ b/keystore/keystore_cli_v2.cpp @@ -29,9 +29,17 @@ using keystore::KeystoreClient; namespace { +struct TestCase { + std::string name; + bool required_for_brillo_pts; + AuthorizationSet parameters; +}; + void PrintUsageAndExit() { printf("Usage: keystore_client_v2 <command> [options]\n"); - printf("Commands: add-entropy --input=<entropy>\n" + printf("Commands: brillo-platform-test [--prefix=<test_name_prefix>]\n" + " list-brillo-tests\n" + " add-entropy --input=<entropy>\n" " generate --name=<key_name>\n" " get-chars --name=<key_name>\n" " export --name=<key_name>\n" @@ -48,6 +56,252 @@ std::unique_ptr<KeystoreClient> CreateKeystoreInstance() { return std::unique_ptr<KeystoreClient>(new keystore::KeystoreClientImpl); } +const char* StringifyTag(keymaster_tag_t tag) { + switch (tag) { + case KM_TAG_INVALID: + return "KM_TAG_INVALID"; + case KM_TAG_PURPOSE: + return "KM_TAG_PURPOSE"; + case KM_TAG_ALGORITHM: + return "KM_TAG_ALGORITHM"; + case KM_TAG_KEY_SIZE: + return "KM_TAG_KEY_SIZE"; + case KM_TAG_BLOCK_MODE: + return "KM_TAG_BLOCK_MODE"; + case KM_TAG_DIGEST: + return "KM_TAG_DIGEST"; + case KM_TAG_PADDING: + return "KM_TAG_PADDING"; + case KM_TAG_CALLER_NONCE: + return "KM_TAG_CALLER_NONCE"; + case KM_TAG_MIN_MAC_LENGTH: + return "KM_TAG_MIN_MAC_LENGTH"; + case KM_TAG_RSA_PUBLIC_EXPONENT: + return "KM_TAG_RSA_PUBLIC_EXPONENT"; + case KM_TAG_BLOB_USAGE_REQUIREMENTS: + return "KM_TAG_BLOB_USAGE_REQUIREMENTS"; + case KM_TAG_BOOTLOADER_ONLY: + return "KM_TAG_BOOTLOADER_ONLY"; + case KM_TAG_ACTIVE_DATETIME: + return "KM_TAG_ACTIVE_DATETIME"; + case KM_TAG_ORIGINATION_EXPIRE_DATETIME: + return "KM_TAG_ORIGINATION_EXPIRE_DATETIME"; + case KM_TAG_USAGE_EXPIRE_DATETIME: + return "KM_TAG_USAGE_EXPIRE_DATETIME"; + case KM_TAG_MIN_SECONDS_BETWEEN_OPS: + return "KM_TAG_MIN_SECONDS_BETWEEN_OPS"; + case KM_TAG_MAX_USES_PER_BOOT: + return "KM_TAG_MAX_USES_PER_BOOT"; + case KM_TAG_ALL_USERS: + return "KM_TAG_ALL_USERS"; + case KM_TAG_USER_ID: + return "KM_TAG_USER_ID"; + case KM_TAG_USER_SECURE_ID: + return "KM_TAG_USER_SECURE_ID"; + case KM_TAG_NO_AUTH_REQUIRED: + return "KM_TAG_NO_AUTH_REQUIRED"; + case KM_TAG_USER_AUTH_TYPE: + return "KM_TAG_USER_AUTH_TYPE"; + case KM_TAG_AUTH_TIMEOUT: + return "KM_TAG_AUTH_TIMEOUT"; + case KM_TAG_ALL_APPLICATIONS: + return "KM_TAG_ALL_APPLICATIONS"; + case KM_TAG_APPLICATION_ID: + return "KM_TAG_APPLICATION_ID"; + case KM_TAG_APPLICATION_DATA: + return "KM_TAG_APPLICATION_DATA"; + case KM_TAG_CREATION_DATETIME: + return "KM_TAG_CREATION_DATETIME"; + case KM_TAG_ORIGIN: + return "KM_TAG_ORIGIN"; + case KM_TAG_ROLLBACK_RESISTANT: + return "KM_TAG_ROLLBACK_RESISTANT"; + case KM_TAG_ROOT_OF_TRUST: + return "KM_TAG_ROOT_OF_TRUST"; + case KM_TAG_ASSOCIATED_DATA: + return "KM_TAG_ASSOCIATED_DATA"; + case KM_TAG_NONCE: + return "KM_TAG_NONCE"; + case KM_TAG_AUTH_TOKEN: + return "KM_TAG_AUTH_TOKEN"; + case KM_TAG_MAC_LENGTH: + return "KM_TAG_MAC_LENGTH"; + } + return "<Unknown>"; +} + +void PrintTags(const AuthorizationSet& parameters) { + const keymaster_key_param_t* iter = nullptr; + for (iter = parameters.begin(); iter != parameters.end(); ++iter) { + printf(" %s\n", StringifyTag(iter->tag)); + } +} + +void PrintKeyCharacteristics(const AuthorizationSet& hardware_enforced_characteristics, + const AuthorizationSet& software_enforced_characteristics) { + printf("Hardware:\n"); + PrintTags(hardware_enforced_characteristics); + printf("Software:\n"); + PrintTags(software_enforced_characteristics); +} + +bool TestKey(const std::string& name, bool required, const AuthorizationSet& parameters) { + std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance(); + AuthorizationSet hardware_enforced_characteristics; + AuthorizationSet software_enforced_characteristics; + int32_t result = keystore->generateKey("tmp", parameters, &hardware_enforced_characteristics, + &software_enforced_characteristics); + if (result != KM_ERROR_OK) { + LOG(ERROR) << "Failed to generate key: " << result; + printf("%s Result: ABORT\n", name.c_str()); + return false; + } + result = keystore->deleteKey("tmp"); + if (result != KM_ERROR_OK) { + LOG(ERROR) << "Failed to delete key: " << result; + printf("%s Result: ABORT\n", name.c_str()); + return false; + } + printf("===============================================================\n"); + printf("%s Key Characteristics:\n", name.c_str()); + PrintKeyCharacteristics(hardware_enforced_characteristics, software_enforced_characteristics); + bool hardware_backed = (hardware_enforced_characteristics.size() > 0); + if (software_enforced_characteristics.GetTagCount(KM_TAG_PURPOSE) > 0 || + software_enforced_characteristics.GetTagCount(KM_TAG_ALGORITHM) > 0 || + software_enforced_characteristics.GetTagCount(KM_TAG_KEY_SIZE) > 0 || + software_enforced_characteristics.GetTagCount(KM_TAG_RSA_PUBLIC_EXPONENT) > 0 || + software_enforced_characteristics.GetTagCount(KM_TAG_DIGEST) > 0 || + software_enforced_characteristics.GetTagCount(KM_TAG_PADDING) > 0 || + software_enforced_characteristics.GetTagCount(KM_TAG_BLOCK_MODE) > 0) { + VLOG(1) << "Hardware-backed key but required characteristics enforced in software."; + hardware_backed = false; + } + const char kBoldRedFail[] = "\033[1;31mFAIL\033[0m"; + const char kBoldGreenPass[] = "\033[1;32mPASS\033[0m"; + const char kBoldYellowWarn[] = "\033[1;33mWARN\033[0m"; + printf("[%s] %s\n", + hardware_backed ? kBoldGreenPass : (required ? kBoldRedFail : kBoldYellowWarn), + name.c_str()); + + return (hardware_backed || !required); +} + +AuthorizationSet GetRSASignParameters(uint32_t key_size, bool sha256_only) { + AuthorizationSetBuilder parameters; + parameters.RsaSigningKey(key_size, 65537) + .Digest(KM_DIGEST_SHA_2_256) + .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN) + .Padding(KM_PAD_RSA_PSS) + .Authorization(keymaster::TAG_NO_AUTH_REQUIRED); + if (!sha256_only) { + parameters.Digest(KM_DIGEST_SHA_2_224) + .Digest(KM_DIGEST_SHA_2_384) + .Digest(KM_DIGEST_SHA_2_512); + } + return parameters.build(); +} + +AuthorizationSet GetRSAEncryptParameters(uint32_t key_size) { + AuthorizationSetBuilder parameters; + parameters.RsaEncryptionKey(key_size, 65537) + .Padding(KM_PAD_RSA_PKCS1_1_5_ENCRYPT) + .Padding(KM_PAD_RSA_OAEP) + .Authorization(keymaster::TAG_NO_AUTH_REQUIRED); + return parameters.build(); +} + +AuthorizationSet GetECDSAParameters(uint32_t key_size, bool sha256_only) { + AuthorizationSetBuilder parameters; + parameters.EcdsaSigningKey(key_size) + .Digest(KM_DIGEST_SHA_2_256) + .Authorization(keymaster::TAG_NO_AUTH_REQUIRED); + if (!sha256_only) { + parameters.Digest(KM_DIGEST_SHA_2_224) + .Digest(KM_DIGEST_SHA_2_384) + .Digest(KM_DIGEST_SHA_2_512); + } + return parameters.build(); +} + +AuthorizationSet GetAESParameters(uint32_t key_size, bool with_gcm_mode) { + AuthorizationSetBuilder parameters; + parameters.AesEncryptionKey(key_size).Authorization(keymaster::TAG_NO_AUTH_REQUIRED); + if (with_gcm_mode) { + parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_GCM) + .Authorization(keymaster::TAG_MIN_MAC_LENGTH, 128); + } else { + parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_ECB); + parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC); + parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CTR); + } + return parameters.build(); +} + +AuthorizationSet GetHMACParameters(uint32_t key_size, keymaster_digest_t digest) { + AuthorizationSetBuilder parameters; + parameters.HmacKey(key_size) + .Digest(digest) + .Authorization(keymaster::TAG_MIN_MAC_LENGTH, 224) + .Authorization(keymaster::TAG_NO_AUTH_REQUIRED); + return parameters.build(); +} + +std::vector<TestCase> GetTestCases() { + TestCase test_cases[] = { + {"RSA-2048 Sign", true, GetRSASignParameters(2048, true)}, + {"RSA-2048 Sign (more digests)", false, GetRSASignParameters(2048, false)}, + {"RSA-3072 Sign", false, GetRSASignParameters(3072, false)}, + {"RSA-4096 Sign", false, GetRSASignParameters(4096, false)}, + {"RSA-2048 Encrypt", true, GetRSAEncryptParameters(2048)}, + {"RSA-3072 Encrypt", false, GetRSAEncryptParameters(3072)}, + {"RSA-4096 Encrypt", false, GetRSAEncryptParameters(4096)}, + {"ECDSA-P256 Sign", true, GetECDSAParameters(256, true)}, + {"ECDSA-P256 Sign (more digests)", false, GetECDSAParameters(256, false)}, + {"ECDSA-P224 Sign", false, GetECDSAParameters(224, false)}, + {"ECDSA-P384 Sign", false, GetECDSAParameters(384, false)}, + {"ECDSA-P521 Sign", false, GetECDSAParameters(521, false)}, + {"AES-128", true, GetAESParameters(128, false)}, + {"AES-256", true, GetAESParameters(256, false)}, + {"AES-128-GCM", false, GetAESParameters(128, true)}, + {"AES-256-GCM", false, GetAESParameters(256, true)}, + {"HMAC-SHA256-16", true, GetHMACParameters(16, KM_DIGEST_SHA_2_256)}, + {"HMAC-SHA256-32", true, GetHMACParameters(32, KM_DIGEST_SHA_2_256)}, + {"HMAC-SHA256-64", false, GetHMACParameters(64, KM_DIGEST_SHA_2_256)}, + {"HMAC-SHA224-32", false, GetHMACParameters(32, KM_DIGEST_SHA_2_224)}, + {"HMAC-SHA384-32", false, GetHMACParameters(32, KM_DIGEST_SHA_2_384)}, + {"HMAC-SHA512-32", false, GetHMACParameters(32, KM_DIGEST_SHA_2_512)}, + }; + return std::vector<TestCase>(&test_cases[0], &test_cases[arraysize(test_cases)]); +} + +int BrilloPlatformTest(const std::string& prefix) { + int test_count = 0; + int fail_count = 0; + std::vector<TestCase> test_cases = GetTestCases(); + for (const auto& test_case : test_cases) { + if (!prefix.empty() && test_case.name.find(prefix) != 0) { + continue; + } + ++test_count; + if (!TestKey(test_case.name, test_case.required_for_brillo_pts, test_case.parameters)) { + VLOG(1) << "Test failed: " << test_case.name; + ++fail_count; + } + } + return fail_count; +} + +int ListTestCases() { + const char kBoldGreenRequired[] = "\033[1;32mREQUIRED\033[0m"; + const char kBoldYellowRecommended[] = "\033[1;33mRECOMMENDED\033[0m"; + std::vector<TestCase> test_cases = GetTestCases(); + for (const auto& test_case : test_cases) { + printf("%s : %s\n", test_case.name.c_str(), + test_case.required_for_brillo_pts ? kBoldGreenRequired : kBoldYellowRecommended); + } + return 0; +} + std::string ReadFile(const std::string& filename) { std::string content; base::FilePath path(filename); @@ -89,8 +343,11 @@ int GenerateKey(const std::string& name) { AuthorizationSet software_enforced_characteristics; int32_t result = keystore->generateKey(name, params.build(), &hardware_enforced_characteristics, &software_enforced_characteristics); - printf("GenerateKey: %d (%zu, %zu)\n", result, hardware_enforced_characteristics.size(), - software_enforced_characteristics.size()); + printf("GenerateKey: %d\n", result); + if (result == KM_ERROR_OK) { + PrintKeyCharacteristics(hardware_enforced_characteristics, + software_enforced_characteristics); + } return result; } @@ -100,8 +357,11 @@ int GetCharacteristics(const std::string& name) { AuthorizationSet software_enforced_characteristics; int32_t result = keystore->getKeyCharacteristics(name, &hardware_enforced_characteristics, &software_enforced_characteristics); - printf("GetCharacteristics: %d (%zu, %zu)\n", result, hardware_enforced_characteristics.size(), - software_enforced_characteristics.size()); + printf("GetCharacteristics: %d\n", result); + if (result == KM_ERROR_OK) { + PrintKeyCharacteristics(hardware_enforced_characteristics, + software_enforced_characteristics); + } return result; } @@ -240,7 +500,11 @@ int main(int argc, char** argv) { if (args.empty()) { PrintUsageAndExit(); } - if (args[0] == "add-entropy") { + if (args[0] == "brillo-platform-test") { + return BrilloPlatformTest(command_line->GetSwitchValueASCII("prefix")); + } else if (args[0] == "list-brillo-tests") { + return ListTestCases(); + } else if (args[0] == "add-entropy") { return AddEntropy(command_line->GetSwitchValueASCII("input")); } else if (args[0] == "generate") { return GenerateKey(command_line->GetSwitchValueASCII("name")); |