415 lines
17 KiB
C++

/* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include <my_global.h>
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <sql_plugin_ref.h>
#include "keyring.cc"
#include "keyring_impl.cc"
#include "mock_logger.h"
namespace keyring__api_unittest
{
using ::testing::StrEq;
using namespace keyring;
class Keyring_api_test : public ::testing::Test
{
public:
Keyring_api_test()
{}
~Keyring_api_test()
{
delete[] plugin_name;
delete[] keyring_filename;
}
protected:
virtual void SetUp()
{
plugin_name= new char[strlen("FakeKeyring")+1];
strcpy(plugin_name, "FakeKeyring");
keyring_filename= new char[strlen("./keyring")+1];
strcpy(keyring_filename, "./keyring");
plugin_info.name.str= plugin_name;
plugin_info.name.length= strlen(plugin_name);
keyring_file_data_value= keyring_filename;
remove(keyring_file_data_value);
remove("./keyring.backup");
keyring_init_with_mock_logger();
key_memory_KEYRING= PSI_NOT_INSTRUMENTED;
key_LOCK_keyring= PSI_NOT_INSTRUMENTED;
sample_key_data= "Robi";
}
virtual void TearDown()
{
keyring_deinit_with_mock_logger();
remove(keyring_file_data_value);
remove("./keyring.backup");
}
protected:
void keyring_init_with_mock_logger();
void keyring_deinit_with_mock_logger();
std::string sample_key_data;
char *plugin_name;
char *keyring_filename;
st_plugin_int plugin_info; //for Logger initialization
};
void Keyring_api_test::keyring_init_with_mock_logger()
{
ASSERT_TRUE(keyring_init(&plugin_info) == 0);
//use MockLogger instead of Logger
logger.reset(new Mock_logger());
}
void Keyring_api_test::keyring_deinit_with_mock_logger()
{
keyring_deinit(NULL);
}
TEST_F(Keyring_api_test, StoreFetchRemove)
{
EXPECT_EQ(mysql_key_store("Robert_key", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
char *key_type;
size_t key_len;
void *key;
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, sample_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, sample_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
EXPECT_EQ(mysql_key_remove("Robert_key", "Robert"), 0);
//make sure the key was removed - fetch it
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
ASSERT_TRUE(key == NULL);
}
TEST_F(Keyring_api_test, CheckIfInmemoryKeyIsXORed)
{
EXPECT_EQ(mysql_key_store("Robert_key", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
Key key_id("Robert_key", NULL, "Robert",NULL,0);
IKey* fetched_key= keys->fetch_key(&key_id);
ASSERT_TRUE(fetched_key != NULL);
std::string expected_key_signature= "Robert_keyRobert";
EXPECT_STREQ(fetched_key->get_key_signature()->c_str(), expected_key_signature.c_str());
EXPECT_EQ(fetched_key->get_key_signature()->length(), expected_key_signature.length());
uchar* key_data_fetched= fetched_key->get_key_data();
size_t key_data_fetched_size= fetched_key->get_key_data_size();
EXPECT_STREQ("AES", fetched_key->get_key_type()->c_str());
//make sure that the key was xored before it was put into keys_container, i.e.
//the fetched key data is not equal to the key data that was stored
EXPECT_STRNE(sample_key_data.c_str(), reinterpret_cast<const char*>(key_data_fetched));
ASSERT_TRUE(sample_key_data.length()+1 == key_data_fetched_size);
//now xor to get the data that was stored
fetched_key->xor_data();
EXPECT_STREQ(sample_key_data.c_str(), reinterpret_cast<const char*>(key_data_fetched));
ASSERT_TRUE(sample_key_data.length()+1 == key_data_fetched_size);
my_free(fetched_key->release_key_data());
}
TEST_F(Keyring_api_test, FetchNotExisting)
{
char *key_type= NULL;
void *key= NULL;
size_t key_len= 0;
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
ASSERT_TRUE(key == NULL);
}
TEST_F(Keyring_api_test, RemoveNotExisting)
{
EXPECT_EQ(mysql_key_remove("Robert_key", "Robert"), 1);
}
TEST_F(Keyring_api_test, StoreFetchNotExisting)
{
EXPECT_EQ(mysql_key_store("Robert_key", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
char *key_type;
size_t key_len;
void *key;
EXPECT_EQ(mysql_key_fetch("NotExisting", &key_type, "Robert", &key, &key_len), 0);
ASSERT_TRUE(key == NULL);
}
TEST_F(Keyring_api_test, StoreStoreStoreFetchRemove)
{
std::string key_data1("Robi1");
std::string key_data2("Robi2");
EXPECT_EQ(mysql_key_store("Robert_key", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
EXPECT_EQ(mysql_key_store("Robert_key1", "AES", "Robert", key_data1.c_str(),
key_data1.length() + 1), 0);
EXPECT_EQ(mysql_key_store("Robert_key2", "AES", "Robert", key_data2.c_str(),
key_data2.length() + 1), 0);
char *key_type;
size_t key_len;
void *key;
EXPECT_EQ(mysql_key_fetch("Robert_key1", &key_type, "Robert", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, key_data1.length()+1);
ASSERT_TRUE(memcmp((char *)key, key_data1.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
EXPECT_EQ(mysql_key_remove("Robert_key2", "Robert"), 0);
//make sure the key was removed - fetch it
EXPECT_EQ(mysql_key_fetch("Robert_key2", &key_type, "Robert", &key,
&key_len), 0);
ASSERT_TRUE(key == NULL);
}
TEST_F(Keyring_api_test, StoreValidTypes)
{
EXPECT_EQ(mysql_key_store("Robert_key", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
EXPECT_EQ(mysql_key_store("Robert_key3", "RSA", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
EXPECT_EQ(mysql_key_store("Robert_key4", "DSA", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
}
TEST_F(Keyring_api_test, StoreInvalidType)
{
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while storing key: invalid key_type")));
EXPECT_EQ(mysql_key_store("Robert_key", "YYY", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 1);
char *key_type;
size_t key_len;
void *key;
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
ASSERT_TRUE(key == NULL);
}
TEST_F(Keyring_api_test, StoreTwiceTheSameDifferentTypes)
{
EXPECT_EQ(mysql_key_store("Robert_key", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
EXPECT_EQ(mysql_key_store("Robert_key", "RSA", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 1);
}
TEST_F(Keyring_api_test, KeyGenerate)
{
EXPECT_EQ(mysql_key_generate("Robert_key", "AES", "Robert", 128), 0);
char *key_type;
size_t key_len;
void *key;
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, (size_t)128);
//Try accessing the last byte of key
char ch= ((char*)key)[key_len-1];
//Just to get rid of unused variable compiler error
(void)ch;
my_free(key);
my_free(key_type);
}
TEST_F(Keyring_api_test, KeyringFileChange)
{
EXPECT_EQ(mysql_key_store("Robert_key", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
char *key_type;
size_t key_len;
void *key;
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, sample_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, sample_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
delete[] keyring_filename;
keyring_filename= new char[strlen("./new_keyring")+1];
strcpy(keyring_filename, "./new_keyring");
keyring_file_data_value= keyring_filename;
keyring_deinit_with_mock_logger();
keyring_init_with_mock_logger();
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
ASSERT_TRUE(key == NULL);
EXPECT_EQ(mysql_key_store("Robert_key_new", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
delete[] keyring_filename;
keyring_filename= new char[strlen("./keyring")+1];
strcpy(keyring_filename, "./keyring");
keyring_file_data_value= keyring_filename;
keyring_deinit_with_mock_logger();
keyring_init_with_mock_logger();
EXPECT_EQ(mysql_key_fetch("Robert_key_new", &key_type, "Robert", &key,
&key_len), 0);
ASSERT_TRUE(key == NULL);
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, sample_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, sample_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
delete[] keyring_filename;
keyring_filename= new char[strlen("./new_keyring")+1];
strcpy(keyring_filename, "./new_keyring");
keyring_file_data_value= keyring_filename;
keyring_deinit_with_mock_logger();
keyring_init_with_mock_logger();
EXPECT_EQ(mysql_key_fetch("Robert_key_new", &key_type, "Robert", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, sample_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, sample_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
remove("./new_keyring");
}
TEST_F(Keyring_api_test, NullUser)
{
EXPECT_EQ(mysql_key_store("Robert_key", "AES", NULL, sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
char *key_type;
size_t key_len;
void *key;
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, NULL, &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, sample_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, sample_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
EXPECT_EQ(mysql_key_store("Robert_key", "RSA", NULL, sample_key_data.c_str(),
sample_key_data.length() + 1), 1);
EXPECT_EQ(mysql_key_store("Kamil_key", "AES", NULL, sample_key_data.c_str(),
sample_key_data.length() + 1), 0);
EXPECT_EQ(mysql_key_fetch("Kamil_key", &key_type, NULL, &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, sample_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, sample_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
std::string arturs_key_data= "Artur";
EXPECT_EQ(mysql_key_store("Artur_key", "AES", "Artur", arturs_key_data.c_str(),
arturs_key_data.length() + 1), 0);
EXPECT_EQ(mysql_key_fetch("Artur_key", &key_type, "Artur", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, arturs_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, arturs_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
EXPECT_EQ(mysql_key_remove("Robert_key", NULL) , 0);
EXPECT_EQ(mysql_key_fetch("Robert_key", &key_type, "Robert", &key,
&key_len), 0);
ASSERT_TRUE(key == NULL);
EXPECT_EQ(mysql_key_fetch("Artur_key", &key_type, "Artur", &key,
&key_len), 0);
EXPECT_STREQ("AES", key_type);
EXPECT_EQ(key_len, arturs_key_data.length()+1);
ASSERT_TRUE(memcmp((char *)key, arturs_key_data.c_str(), key_len) == 0);
my_free(key_type);
key_type= NULL;
my_free(key);
key= NULL;
}
TEST_F(Keyring_api_test, NullKeyId)
{
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while storing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_store(NULL, "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while storing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_store(NULL, "AES", NULL, sample_key_data.c_str(),
sample_key_data.length() + 1), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while storing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_store("", "AES", "Robert", sample_key_data.c_str(),
sample_key_data.length() + 1), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while storing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_store("", "AES", NULL, sample_key_data.c_str(),
sample_key_data.length() + 1), 1);
char *key_type;
size_t key_len;
void *key;
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while fetching key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_fetch(NULL, &key_type, "Robert", &key, &key_len), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while fetching key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_fetch(NULL, &key_type, NULL, &key, &key_len), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while fetching key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_fetch("", &key_type, "Robert", &key, &key_len), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while fetching key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_fetch("", &key_type, NULL, &key, &key_len), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while removing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_remove(NULL, "Robert") , 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while removing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_remove(NULL, NULL) , 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while removing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_remove("", "Robert") , 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while removing key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_remove("", NULL) , 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while generating key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_generate(NULL, "AES", "Robert", 128), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while generating key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_generate(NULL, "AES", NULL, 128), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while generating key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_generate("", "AES", "Robert", 128), 1);
EXPECT_CALL(*((Mock_logger *)logger.get()), log(MY_ERROR_LEVEL, StrEq("Error while generating key: key_id cannot be empty")));
EXPECT_EQ(mysql_key_generate("", "AES", NULL, 128), 1);
}
int main(int argc, char **argv) {
if (mysql_rwlock_init(key_LOCK_keyring, &LOCK_keyring))
return TRUE;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
}