1075 lines
43 KiB
C++
1075 lines
43 KiB
C++
/*
|
|
* 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 <string>
|
|
#include <fstream>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <openssl/engine.h>
|
|
|
|
#include <keymaster/google_keymaster_utils.h>
|
|
#include <keymaster/keymaster_tags.h>
|
|
|
|
#include "google_keymaster_test_utils.h"
|
|
#include "google_softkeymaster.h"
|
|
|
|
using std::string;
|
|
using std::ifstream;
|
|
using std::istreambuf_iterator;
|
|
|
|
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() : device(5, new StdoutLogger) { RAND_seed("foobar", 6); }
|
|
~KeymasterTest() {}
|
|
|
|
GoogleSoftKeymaster device;
|
|
};
|
|
|
|
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(3U, response.results_length);
|
|
EXPECT_EQ(KM_ALGORITHM_RSA, response.results[0]);
|
|
EXPECT_EQ(KM_ALGORITHM_DSA, response.results[1]);
|
|
EXPECT_EQ(KM_ALGORITHM_ECDSA, response.results[2]);
|
|
}
|
|
|
|
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_OK, response.error);
|
|
EXPECT_EQ(0U, response.results_length);
|
|
|
|
device.SupportedBlockModes(KM_ALGORITHM_ECDSA, &response);
|
|
EXPECT_EQ(KM_ERROR_OK, response.error);
|
|
EXPECT_EQ(0U, response.results_length);
|
|
|
|
device.SupportedBlockModes(KM_ALGORITHM_AES, &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_OK, response.error);
|
|
EXPECT_EQ(1U, response.results_length);
|
|
EXPECT_EQ(KM_PAD_NONE, response.results[0]);
|
|
|
|
device.SupportedPaddingModes(KM_ALGORITHM_ECDSA, &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_AES, &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_OK, response.error);
|
|
EXPECT_EQ(1U, response.results_length);
|
|
EXPECT_EQ(KM_DIGEST_NONE, response.results[0]);
|
|
|
|
device.SupportedDigests(KM_ALGORITHM_ECDSA, &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_AES, &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_OK, response.error);
|
|
EXPECT_EQ(1U, response.results_length);
|
|
EXPECT_EQ(KM_KEY_FORMAT_PKCS8, response.results[0]);
|
|
|
|
device.SupportedImportFormats(KM_ALGORITHM_ECDSA, &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_AES, &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_OK, response.error);
|
|
EXPECT_EQ(1U, response.results_length);
|
|
EXPECT_EQ(KM_KEY_FORMAT_X509, response.results[0]);
|
|
|
|
device.SupportedExportFormats(KM_ALGORITHM_ECDSA, &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_AES, &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_KEY_SIZE, 256),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_APPLICATION_DATA, "app_data", 8),
|
|
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(12U, rsp.enforced.SerializedSize());
|
|
EXPECT_GT(rsp.unenforced.SerializedSize(), 12U);
|
|
|
|
// 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_KEY_SIZE, 256));
|
|
EXPECT_TRUE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 300));
|
|
|
|
// Verify that App ID, App data and ROT are NOT included.
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_ROOT_OF_TRUST));
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_ID));
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_DATA));
|
|
|
|
// 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));
|
|
}
|
|
|
|
TEST_F(NewKeyGeneration, Dsa) {
|
|
keymaster_key_param_t params[] = {
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
|
|
Authorization(TAG_ALGORITHM, KM_ALGORITHM_DSA),
|
|
Authorization(TAG_KEY_SIZE, 256),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_APPLICATION_DATA, "app_data", 8),
|
|
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(12U, rsp.enforced.SerializedSize());
|
|
EXPECT_GT(rsp.unenforced.SerializedSize(), 12U);
|
|
|
|
// 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_DSA));
|
|
|
|
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_KEY_SIZE, 256));
|
|
EXPECT_TRUE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 300));
|
|
|
|
// Verify that App ID, App data and ROT are NOT included.
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_ROOT_OF_TRUST));
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_ID));
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_DATA));
|
|
|
|
// 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_ORIGIN, KM_ORIGIN_SOFTWARE));
|
|
EXPECT_TRUE(contains(rsp.unenforced, KM_TAG_CREATION_DATETIME));
|
|
|
|
// Generator should have created DSA params.
|
|
keymaster_blob_t g, p, q;
|
|
EXPECT_TRUE(rsp.unenforced.GetTagValue(TAG_DSA_GENERATOR, &g));
|
|
EXPECT_TRUE(rsp.unenforced.GetTagValue(TAG_DSA_P, &p));
|
|
EXPECT_TRUE(rsp.unenforced.GetTagValue(TAG_DSA_Q, &q));
|
|
EXPECT_TRUE(g.data_length >= 63 && g.data_length <= 64);
|
|
EXPECT_EQ(64U, p.data_length);
|
|
EXPECT_EQ(20U, q.data_length);
|
|
}
|
|
|
|
TEST_F(NewKeyGeneration, Ecdsa) {
|
|
keymaster_key_param_t params[] = {
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
|
|
Authorization(TAG_ALGORITHM, KM_ALGORITHM_ECDSA),
|
|
Authorization(TAG_KEY_SIZE, 256),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_APPLICATION_DATA, "app_data", 8),
|
|
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(12U, rsp.enforced.SerializedSize());
|
|
EXPECT_GT(rsp.unenforced.SerializedSize(), 12U);
|
|
|
|
// 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_ECDSA));
|
|
|
|
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_KEY_SIZE, 256));
|
|
EXPECT_TRUE(contains(rsp.unenforced, TAG_AUTH_TIMEOUT, 300));
|
|
|
|
// Verify that App ID, App data and ROT are NOT included.
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_ROOT_OF_TRUST));
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_ID));
|
|
EXPECT_FALSE(contains(rsp.unenforced, TAG_APPLICATION_DATA));
|
|
|
|
// 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_ORIGIN, KM_ORIGIN_SOFTWARE));
|
|
EXPECT_TRUE(contains(rsp.unenforced, KM_TAG_CREATION_DATETIME));
|
|
}
|
|
|
|
typedef KeymasterTest GetKeyCharacteristics;
|
|
TEST_F(GetKeyCharacteristics, SimpleRsa) {
|
|
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_KEY_SIZE, 256),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_AUTH_TIMEOUT, 300),
|
|
};
|
|
|
|
GenerateKeyRequest gen_req;
|
|
gen_req.key_description.Reinitialize(params, array_length(params));
|
|
GenerateKeyResponse gen_rsp;
|
|
|
|
device.GenerateKey(gen_req, &gen_rsp);
|
|
ASSERT_EQ(KM_ERROR_OK, gen_rsp.error);
|
|
|
|
GetKeyCharacteristicsRequest req;
|
|
req.SetKeyMaterial(gen_rsp.key_blob);
|
|
req.additional_params.push_back(TAG_APPLICATION_ID, "app_id", 6);
|
|
|
|
GetKeyCharacteristicsResponse rsp;
|
|
device.GetKeyCharacteristics(req, &rsp);
|
|
ASSERT_EQ(KM_ERROR_OK, rsp.error);
|
|
|
|
EXPECT_EQ(gen_rsp.enforced, rsp.enforced);
|
|
EXPECT_EQ(gen_rsp.unenforced, rsp.unenforced);
|
|
}
|
|
|
|
/**
|
|
* Test class that provides some infrastructure for generating keys and signing messages.
|
|
*/
|
|
class SigningOperationsTest : public KeymasterTest {
|
|
protected:
|
|
void GenerateKey(keymaster_algorithm_t algorithm, keymaster_digest_t digest,
|
|
keymaster_padding_t padding, uint32_t key_size) {
|
|
keymaster_key_param_t params[] = {
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
|
|
Authorization(TAG_ALGORITHM, algorithm),
|
|
Authorization(TAG_KEY_SIZE, key_size),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_AUTH_TIMEOUT, 300),
|
|
};
|
|
GenerateKeyRequest generate_request;
|
|
generate_request.key_description.Reinitialize(params, array_length(params));
|
|
if (static_cast<int>(digest) != -1)
|
|
generate_request.key_description.push_back(TAG_DIGEST, digest);
|
|
if (static_cast<int>(padding) != -1)
|
|
generate_request.key_description.push_back(TAG_PADDING, padding);
|
|
device.GenerateKey(generate_request, &generate_response_);
|
|
EXPECT_EQ(KM_ERROR_OK, generate_response_.error);
|
|
}
|
|
|
|
void SignMessage(const void* message, size_t size) {
|
|
SignMessage(generate_response_.key_blob, message, size);
|
|
}
|
|
|
|
void SignMessage(const keymaster_key_blob_t& key_blob, const void* message, size_t size) {
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob);
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message, size);
|
|
EXPECT_EQ(size, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
device.FinishOperation(finish_request, &finish_response_);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response_.error);
|
|
EXPECT_GT(finish_response_.output.available_read(), 0U);
|
|
}
|
|
|
|
void AddClientParams(AuthorizationSet* set) { set->push_back(TAG_APPLICATION_ID, "app_id", 6); }
|
|
|
|
const keymaster_key_blob_t& key_blob() { return generate_response_.key_blob; }
|
|
|
|
const keymaster_key_blob_t& corrupt_key_blob() {
|
|
uint8_t* tmp = const_cast<uint8_t*>(generate_response_.key_blob.key_material);
|
|
++tmp[generate_response_.key_blob.key_material_size / 2];
|
|
return generate_response_.key_blob;
|
|
}
|
|
|
|
Buffer* signature() {
|
|
if (finish_response_.error == KM_ERROR_OK)
|
|
return &finish_response_.output;
|
|
return NULL;
|
|
}
|
|
|
|
private:
|
|
GenerateKeyResponse generate_response_;
|
|
FinishOperationResponse finish_response_;
|
|
};
|
|
|
|
TEST_F(SigningOperationsTest, RsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
const char message[] = "12345678901234567890123456789012";
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message, array_size(message) - 1);
|
|
EXPECT_EQ(array_size(message) - 1, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_GT(finish_response.output.available_read(), 0U);
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, DsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_DSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize("123456789012345678901234567890123456789012345678", 48);
|
|
EXPECT_EQ(48U, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_GT(finish_response.output.available_read(), 0U);
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, EcdsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_ECDSA, KM_DIGEST_NONE, KM_PAD_NONE, 192 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize("123456789012345678901234567890123456789012345678", 48);
|
|
EXPECT_EQ(48U, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_GT(finish_response.output.available_read(), 0U);
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, RsaAbort) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
EXPECT_EQ(KM_ERROR_OK, device.AbortOperation(begin_response.op_handle));
|
|
|
|
// Another abort should fail
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, RsaUnsupportedDigest) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_SHA_2_256, KM_PAD_NONE, 256 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, begin_response.error);
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, RsaUnsupportedPadding) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_RSA_OAEP, 256 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, begin_response.error);
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, RsaNoDigest) {
|
|
GenerateKey(KM_ALGORITHM_RSA, static_cast<keymaster_digest_t>(-1), KM_PAD_NONE,
|
|
256 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_UNSUPPORTED_DIGEST, begin_response.error);
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, RsaNoPadding) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, static_cast<keymaster_padding_t>(-1),
|
|
256 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_UNSUPPORTED_PADDING_MODE, begin_response.error);
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(SigningOperationsTest, RsaTooShortMessage) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_SIGN;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize("01234567890123456789012345678901", 31);
|
|
EXPECT_EQ(31U, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_UNKNOWN_ERROR, finish_response.error);
|
|
EXPECT_EQ(0U, finish_response.output.available_read());
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
typedef SigningOperationsTest VerificationOperationsTest;
|
|
TEST_F(VerificationOperationsTest, RsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
const char message[] = "12345678901234567890123456789012";
|
|
SignMessage(message, array_size(message) - 1);
|
|
ASSERT_TRUE(signature() != NULL);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_VERIFY;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message, array_size(message) - 1);
|
|
EXPECT_EQ(array_size(message) - 1, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
finish_request.signature.Reinitialize(*signature());
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_EQ(0U, finish_response.output.available_read());
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(VerificationOperationsTest, DsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_DSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
const char message[] = "123456789012345678901234567890123456789012345678";
|
|
SignMessage(message, array_size(message) - 1);
|
|
ASSERT_TRUE(signature() != NULL);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_VERIFY;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message, array_size(message) - 1);
|
|
EXPECT_EQ(array_size(message) - 1, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
finish_request.signature.Reinitialize(*signature());
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_EQ(0U, finish_response.output.available_read());
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(VerificationOperationsTest, EcdsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_ECDSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
const char message[] = "123456789012345678901234567890123456789012345678";
|
|
SignMessage(message, array_size(message) - 1);
|
|
ASSERT_TRUE(signature() != NULL);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(key_blob());
|
|
begin_request.purpose = KM_PURPOSE_VERIFY;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message, array_size(message) - 1);
|
|
EXPECT_EQ(array_size(message) - 1, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
finish_request.signature.Reinitialize(*signature());
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_EQ(0U, finish_response.output.available_read());
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
typedef SigningOperationsTest ExportKeyTest;
|
|
TEST_F(ExportKeyTest, RsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256 /* key size */);
|
|
|
|
ExportKeyRequest request;
|
|
ExportKeyResponse response;
|
|
AddClientParams(&request.additional_params);
|
|
request.key_format = KM_KEY_FORMAT_X509;
|
|
request.SetKeyMaterial(key_blob());
|
|
|
|
device.ExportKey(request, &response);
|
|
ASSERT_EQ(KM_ERROR_OK, response.error);
|
|
EXPECT_TRUE(response.key_data != NULL);
|
|
|
|
// TODO(swillden): Verify that the exported key is actually usable to verify signatures.
|
|
}
|
|
|
|
TEST_F(ExportKeyTest, DsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_DSA, KM_DIGEST_NONE, KM_PAD_NONE, 1024 /* key size */);
|
|
|
|
ExportKeyRequest request;
|
|
ExportKeyResponse response;
|
|
AddClientParams(&request.additional_params);
|
|
request.key_format = KM_KEY_FORMAT_X509;
|
|
request.SetKeyMaterial(key_blob());
|
|
|
|
device.ExportKey(request, &response);
|
|
ASSERT_EQ(KM_ERROR_OK, response.error);
|
|
EXPECT_TRUE(response.key_data != NULL);
|
|
|
|
// TODO(swillden): Verify that the exported key is actually usable to verify signatures.
|
|
}
|
|
|
|
TEST_F(ExportKeyTest, EcdsaSuccess) {
|
|
GenerateKey(KM_ALGORITHM_ECDSA, KM_DIGEST_NONE, KM_PAD_NONE, 192 /* key size */);
|
|
|
|
ExportKeyRequest request;
|
|
ExportKeyResponse response;
|
|
AddClientParams(&request.additional_params);
|
|
request.key_format = KM_KEY_FORMAT_X509;
|
|
request.SetKeyMaterial(key_blob());
|
|
|
|
device.ExportKey(request, &response);
|
|
ASSERT_EQ(KM_ERROR_OK, response.error);
|
|
EXPECT_TRUE(response.key_data != NULL);
|
|
|
|
// TODO(swillden): Verify that the exported key is actually usable to verify signatures.
|
|
}
|
|
|
|
TEST_F(ExportKeyTest, RsaUnsupportedKeyFormat) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256);
|
|
|
|
ExportKeyRequest request;
|
|
ExportKeyResponse response;
|
|
AddClientParams(&request.additional_params);
|
|
|
|
/* We have no other defined export formats defined. */
|
|
request.key_format = KM_KEY_FORMAT_PKCS8;
|
|
request.SetKeyMaterial(key_blob());
|
|
|
|
device.ExportKey(request, &response);
|
|
ASSERT_EQ(KM_ERROR_UNSUPPORTED_KEY_FORMAT, response.error);
|
|
EXPECT_TRUE(response.key_data == NULL);
|
|
}
|
|
|
|
TEST_F(ExportKeyTest, RsaCorruptedKeyBlob) {
|
|
GenerateKey(KM_ALGORITHM_RSA, KM_DIGEST_NONE, KM_PAD_NONE, 256);
|
|
|
|
ExportKeyRequest request;
|
|
ExportKeyResponse response;
|
|
AddClientParams(&request.additional_params);
|
|
request.key_format = KM_KEY_FORMAT_X509;
|
|
request.SetKeyMaterial(corrupt_key_blob());
|
|
|
|
device.ExportKey(request, &response);
|
|
ASSERT_EQ(KM_ERROR_INVALID_KEY_BLOB, response.error);
|
|
ASSERT_TRUE(response.key_data == NULL);
|
|
}
|
|
|
|
static string read_file(const string& file_name) {
|
|
ifstream file_stream(file_name, std::ios::binary);
|
|
istreambuf_iterator<char> file_begin(file_stream);
|
|
istreambuf_iterator<char> file_end;
|
|
return string(file_begin, file_end);
|
|
}
|
|
|
|
typedef SigningOperationsTest ImportKeyTest;
|
|
TEST_F(ImportKeyTest, RsaSuccess) {
|
|
keymaster_key_param_t params[] = {
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
|
|
Authorization(TAG_DIGEST, KM_DIGEST_NONE),
|
|
Authorization(TAG_PADDING, KM_PAD_NONE),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_AUTH_TIMEOUT, 300),
|
|
};
|
|
|
|
string pk8_key = read_file("rsa_privkey_pk8.der");
|
|
ASSERT_EQ(633U, pk8_key.size());
|
|
|
|
ImportKeyRequest import_request;
|
|
import_request.key_description.Reinitialize(params, array_length(params));
|
|
import_request.key_format = KM_KEY_FORMAT_PKCS8;
|
|
import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
|
|
|
|
ImportKeyResponse import_response;
|
|
device.ImportKey(import_request, &import_response);
|
|
ASSERT_EQ(KM_ERROR_OK, import_response.error);
|
|
EXPECT_EQ(0U, import_response.enforced.size());
|
|
EXPECT_GT(import_response.unenforced.size(), 0U);
|
|
|
|
// Check values derived from the key.
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_RSA));
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 1024));
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_RSA_PUBLIC_EXPONENT, 65537U));
|
|
|
|
// And values provided by GoogleKeymaster
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
|
|
EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
|
|
|
|
size_t message_len = 1024 / 8;
|
|
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
|
std::fill(message.get(), message.get() + message_len, 'a');
|
|
SignMessage(import_response.key_blob, message.get(), message_len);
|
|
ASSERT_TRUE(signature() != NULL);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(import_response.key_blob);
|
|
begin_request.purpose = KM_PURPOSE_VERIFY;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message.get(), message_len);
|
|
EXPECT_EQ(message_len, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
finish_request.signature.Reinitialize(*signature());
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_EQ(0U, finish_response.output.available_read());
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(ImportKeyTest, DsaSuccess) {
|
|
keymaster_key_param_t params[] = {
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
|
|
Authorization(TAG_DIGEST, KM_DIGEST_NONE),
|
|
Authorization(TAG_PADDING, KM_PAD_NONE),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_AUTH_TIMEOUT, 300),
|
|
};
|
|
|
|
string pk8_key = read_file("dsa_privkey_pk8.der");
|
|
ASSERT_EQ(335U, pk8_key.size());
|
|
|
|
ImportKeyRequest import_request;
|
|
import_request.key_description.Reinitialize(params, array_length(params));
|
|
import_request.key_format = KM_KEY_FORMAT_PKCS8;
|
|
import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
|
|
|
|
ImportKeyResponse import_response;
|
|
device.ImportKey(import_request, &import_response);
|
|
ASSERT_EQ(KM_ERROR_OK, import_response.error);
|
|
EXPECT_EQ(0U, import_response.enforced.size());
|
|
EXPECT_GT(import_response.unenforced.size(), 0U);
|
|
|
|
// Check values derived from the key.
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_DSA));
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 1024));
|
|
|
|
// And values provided by GoogleKeymaster
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
|
|
EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
|
|
|
|
size_t message_len = 48;
|
|
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
|
std::fill(message.get(), message.get() + message_len, 'a');
|
|
SignMessage(import_response.key_blob, message.get(), message_len);
|
|
ASSERT_TRUE(signature() != NULL);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(import_response.key_blob);
|
|
begin_request.purpose = KM_PURPOSE_VERIFY;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message.get(), message_len);
|
|
EXPECT_EQ(message_len, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
finish_request.signature.Reinitialize(*signature());
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_EQ(0U, finish_response.output.available_read());
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
TEST_F(ImportKeyTest, EcdsaSuccess) {
|
|
keymaster_key_param_t params[] = {
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_SIGN),
|
|
Authorization(TAG_PURPOSE, KM_PURPOSE_VERIFY),
|
|
Authorization(TAG_DIGEST, KM_DIGEST_NONE),
|
|
Authorization(TAG_PADDING, KM_PAD_NONE),
|
|
Authorization(TAG_USER_ID, 7),
|
|
Authorization(TAG_USER_AUTH_ID, 8),
|
|
Authorization(TAG_APPLICATION_ID, "app_id", 6),
|
|
Authorization(TAG_AUTH_TIMEOUT, 300),
|
|
};
|
|
|
|
string pk8_key = read_file("ec_privkey_pk8.der");
|
|
ASSERT_EQ(138U, pk8_key.size());
|
|
|
|
ImportKeyRequest import_request;
|
|
import_request.key_description.Reinitialize(params, array_length(params));
|
|
import_request.key_format = KM_KEY_FORMAT_PKCS8;
|
|
import_request.SetKeyMaterial(pk8_key.data(), pk8_key.size());
|
|
|
|
ImportKeyResponse import_response;
|
|
device.ImportKey(import_request, &import_response);
|
|
ASSERT_EQ(KM_ERROR_OK, import_response.error);
|
|
EXPECT_EQ(0U, import_response.enforced.size());
|
|
EXPECT_GT(import_response.unenforced.size(), 0U);
|
|
|
|
// Check values derived from the key.
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_ALGORITHM, KM_ALGORITHM_ECDSA));
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_KEY_SIZE, 256));
|
|
|
|
// And values provided by GoogleKeymaster
|
|
EXPECT_TRUE(contains(import_response.unenforced, TAG_ORIGIN, KM_ORIGIN_IMPORTED));
|
|
EXPECT_TRUE(contains(import_response.unenforced, KM_TAG_CREATION_DATETIME));
|
|
|
|
size_t message_len = 1024 / 8;
|
|
UniquePtr<uint8_t[]> message(new uint8_t[message_len]);
|
|
std::fill(message.get(), message.get() + message_len, 'a');
|
|
SignMessage(import_response.key_blob, message.get(), message_len);
|
|
ASSERT_TRUE(signature() != NULL);
|
|
|
|
BeginOperationRequest begin_request;
|
|
BeginOperationResponse begin_response;
|
|
begin_request.SetKeyMaterial(import_response.key_blob);
|
|
begin_request.purpose = KM_PURPOSE_VERIFY;
|
|
AddClientParams(&begin_request.additional_params);
|
|
|
|
device.BeginOperation(begin_request, &begin_response);
|
|
ASSERT_EQ(KM_ERROR_OK, begin_response.error);
|
|
|
|
UpdateOperationRequest update_request;
|
|
UpdateOperationResponse update_response;
|
|
update_request.op_handle = begin_response.op_handle;
|
|
update_request.input.Reinitialize(message.get(), message_len);
|
|
EXPECT_EQ(message_len, update_request.input.available_read());
|
|
|
|
device.UpdateOperation(update_request, &update_response);
|
|
ASSERT_EQ(KM_ERROR_OK, update_response.error);
|
|
EXPECT_EQ(0U, update_response.output.available_read());
|
|
|
|
FinishOperationRequest finish_request;
|
|
finish_request.op_handle = begin_response.op_handle;
|
|
finish_request.signature.Reinitialize(*signature());
|
|
FinishOperationResponse finish_response;
|
|
device.FinishOperation(finish_request, &finish_response);
|
|
ASSERT_EQ(KM_ERROR_OK, finish_response.error);
|
|
EXPECT_EQ(0U, finish_response.output.available_read());
|
|
|
|
EXPECT_EQ(KM_ERROR_INVALID_OPERATION_HANDLE, device.AbortOperation(begin_response.op_handle));
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace keymaster
|