Add GoogleKeymaster. Very incomplete.
Change-Id: I53542c7132bd1a04afee93f3247b88ed7ed0bedc
diff --git a/google_keymaster_test.cpp b/google_keymaster_test.cpp
new file mode 100644
index 0000000..435257c
--- /dev/null
+++ b/google_keymaster_test.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <openssl/engine.h>
+
+#define KEYMASTER_NAME_TAGS
+#include "keymaster_tags.h"
+#include "google_keymaster_utils.h"
+#include "google_softkeymaster.h"
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int result = RUN_ALL_TESTS();
+ // Clean up stuff OpenSSL leaves around, so Valgrind doesn't complain.
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
+ return result;
+}
+
+namespace keymaster {
+namespace test {
+
+class KeymasterTest : public testing::Test {
+ protected:
+ KeymasterTest() {
+ }
+ ~KeymasterTest() {
+ }
+
+ GoogleSoftKeymaster device;
+};
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM, Tag, KeymasterEnum> tag,
+ KeymasterEnum val) {
+ int pos = set.find(tag);
+ return pos != -1 && set[pos].enumerated == val;
+}
+
+template <keymaster_tag_t Tag, typename KeymasterEnum>
+bool contains(const AuthorizationSet& set, TypedEnumTag<KM_ENUM_REP, Tag, KeymasterEnum> tag,
+ KeymasterEnum val) {
+ int pos = -1;
+ while ((pos = set.find(tag, pos)) != -1)
+ if (set[pos].enumerated == val)
+ return true;
+ return false;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_INT, Tag> tag, uint32_t val) {
+ int pos = set.find(tag);
+ return pos != -1 && set[pos].integer == val;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_INT_REP, Tag> tag, uint32_t val) {
+ int pos = -1;
+ while ((pos = set.find(tag, pos)) != -1)
+ if (set[pos].integer == val)
+ return true;
+ return false;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_LONG, Tag> tag, uint64_t val) {
+ int pos = set.find(tag);
+ return pos != -1 && set[pos].long_integer == val;
+}
+
+template <keymaster_tag_t Tag>
+bool contains(const AuthorizationSet& set, TypedTag<KM_BYTES, Tag> tag, const std::string& val) {
+ int pos = set.find(tag);
+ return pos != -1 &&
+ std::string(reinterpret_cast<const char*>(set[pos].blob.data),
+ set[pos].blob.data_length) == val;
+}
+
+inline bool contains(const AuthorizationSet& set, keymaster_tag_t tag) {
+ return set.find(tag) != -1;
+}
+
+typedef KeymasterTest CheckSupported;
+TEST_F(CheckSupported, SupportedAlgorithms) {
+ // Shouldn't blow up on NULL.
+ device.SupportedAlgorithms(NULL);
+
+ SupportedResponse<keymaster_algorithm_t> response;
+ device.SupportedAlgorithms(&response);
+ EXPECT_EQ(KM_ERROR_OK, response.error);
+ EXPECT_EQ(1U, response.results_length);
+ EXPECT_EQ(KM_ALGORITHM_RSA, response.results[0]);
+}
+
+TEST_F(CheckSupported, SupportedBlockModes) {
+ // Shouldn't blow up on NULL.
+ device.SupportedBlockModes(KM_ALGORITHM_RSA, NULL);
+
+ SupportedResponse<keymaster_block_mode_t> response;
+ device.SupportedBlockModes(KM_ALGORITHM_RSA, &response);
+ EXPECT_EQ(KM_ERROR_OK, response.error);
+ EXPECT_EQ(0U, response.results_length);
+
+ device.SupportedBlockModes(KM_ALGORITHM_DSA, &response);
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
+}
+
+TEST_F(CheckSupported, SupportedPaddingModes) {
+ // Shouldn't blow up on NULL.
+ device.SupportedPaddingModes(KM_ALGORITHM_RSA, NULL);
+
+ SupportedResponse<keymaster_padding_t> response;
+ device.SupportedPaddingModes(KM_ALGORITHM_RSA, &response);
+ EXPECT_EQ(KM_ERROR_OK, response.error);
+ EXPECT_EQ(1U, response.results_length);
+ EXPECT_EQ(KM_PAD_NONE, response.results[0]);
+
+ device.SupportedPaddingModes(KM_ALGORITHM_DSA, &response);
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
+}
+
+TEST_F(CheckSupported, SupportedDigests) {
+ // Shouldn't blow up on NULL.
+ device.SupportedDigests(KM_ALGORITHM_RSA, NULL);
+
+ SupportedResponse<keymaster_digest_t> response;
+ device.SupportedDigests(KM_ALGORITHM_RSA, &response);
+ EXPECT_EQ(KM_ERROR_OK, response.error);
+ EXPECT_EQ(1U, response.results_length);
+ EXPECT_EQ(KM_DIGEST_NONE, response.results[0]);
+
+ device.SupportedDigests(KM_ALGORITHM_DSA, &response);
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
+}
+
+TEST_F(CheckSupported, SupportedImportFormats) {
+ // Shouldn't blow up on NULL.
+ device.SupportedImportFormats(KM_ALGORITHM_RSA, NULL);
+
+ SupportedResponse<keymaster_key_format_t> response;
+ device.SupportedImportFormats(KM_ALGORITHM_RSA, &response);
+ EXPECT_EQ(KM_ERROR_OK, response.error);
+ EXPECT_EQ(1U, response.results_length);
+ EXPECT_EQ(KM_KEY_FORMAT_PKCS8, response.results[0]);
+
+ device.SupportedImportFormats(KM_ALGORITHM_DSA, &response);
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
+}
+
+TEST_F(CheckSupported, SupportedExportFormats) {
+ // Shouldn't blow up on NULL.
+ device.SupportedExportFormats(KM_ALGORITHM_RSA, NULL);
+
+ SupportedResponse<keymaster_key_format_t> response;
+ device.SupportedExportFormats(KM_ALGORITHM_RSA, &response);
+ EXPECT_EQ(KM_ERROR_OK, response.error);
+ EXPECT_EQ(1U, response.results_length);
+ EXPECT_EQ(KM_KEY_FORMAT_X509, response.results[0]);
+
+ device.SupportedExportFormats(KM_ALGORITHM_DSA, &response);
+ EXPECT_EQ(KM_ERROR_UNSUPPORTED_ALGORITHM, response.error);
+}
+
+typedef KeymasterTest NewKeyGeneration;
+TEST_F(NewKeyGeneration, Rsa) {
+ keymaster_key_param_t params[] = {
+ Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
+ Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
+ Authorization(TAG_ALGORITHM, KM_ALGORITHM_RSA),
+ Authorization(TAG_USER_ID, 7),
+ Authorization(TAG_USER_AUTH_ID, 8),
+ Authorization(TAG_APPLICATION_ID, reinterpret_cast<const uint8_t*>("app_id"), 6),
+ Authorization(TAG_AUTH_TIMEOUT, 300),
+ };
+ GenerateKeyRequest req;
+ req.key_description.Reinitialize(params, array_length(params));
+ GenerateKeyResponse rsp;
+
+ device.GenerateKey(req, &rsp);
+
+ ASSERT_EQ(KM_ERROR_OK, rsp.error);
+ EXPECT_EQ(0U, rsp.enforced.size());
+ EXPECT_EQ(8U, rsp.enforced.SerializedSize());
+ EXPECT_GT(rsp.unenforced.SerializedSize(), 8U);
+
+ // Check specified tags are all present in unenforced characteristics
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_SIGN));
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_VERIFY));
+
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
+
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_ID, 7));
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_USER_AUTH_ID, 8));
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_APPLICATION_ID, "app_id"));
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_KEY_SIZE, 2048));
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 300));
+
+ // Just for giggles, check that some unexpected tags/values are NOT present.
+ EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
+ EXPECT_FALSE(contains(rsp.unenforced, TAG_PURPOSE, KM_PURPOSE_DECRYPT));
+ EXPECT_FALSE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 301));
+ EXPECT_FALSE(contains(rsp.unenforced, TAG_RESCOPE_AUTH_TIMEOUT));
+
+ // Now check that unspecified, defaulted tags are correct.
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_RSA_PUBLIC_EXPONENT, 65537));
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_ORIGIN, KM_ORIGIN_SOFTWARE));
+ EXPECT_TRUE(contains(rsp.unenforced, KM_TAG_CREATION_DATETIME));
+ EXPECT_TRUE(contains(rsp.unenforced, TAG_ROOT_OF_TRUST, "SW"));
+}
+
+} // namespace test
+} // namespace keymaster