/*
- * Copyright (c) 2000 - 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2000-2020 Samsung Electronics Co., Ltd. All rights reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* @author Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
* @version 1.0
*/
-#include <string>
+#include <unistd.h>
+#include <sys/types.h>
+#include <cstdlib>
+#include <string>
+#include <fstream>
#include <sys/smack.h>
+#include <ckm/ckm-type.h>
#include <ckmc/ckmc-type.h>
#include <ckm-common.h>
#include <tests_common.h>
-#include <access_provider2.h>
#include <ckm/ckm-control.h>
#include <ckm/ckm-manager.h>
#include <ckmc/ckmc-control.h>
#include <ckmc/ckmc-manager.h>
-#include <service_manager.h>
+#include <fcntl.h>
#include <unistd.h>
-
-const char* SERVICE[] = {
- "central-key-manager-listener.service",
- "central-key-manager.service" };
-
-void start_service(ServiceIdx idx)
-{
- ServiceManager sm(SERVICE[idx]);
- sm.startService();
-}
-
-void stop_service(ServiceIdx idx)
-{
- ServiceManager sm(SERVICE[idx]);
- sm.stopService();
-}
-
-
-void switch_to_storage_user(const char* label)
-{
- AccessProvider ap(label);
- ap.allowAPI("key-manager::api-storage", "rw");
- ap.applyAndSwithToUser(APP_UID, APP_GID);
-}
-
-void switch_to_storage_ocsp_user(const char* label)
-{
- AccessProvider ap(label);
- ap.allowAPI("key-manager::api-storage", "rw");
- ap.allowAPI("key-manager::api-ocsp", "rw");
- ap.applyAndSwithToUser(APP_UID, APP_GID);
-}
-
-DBCleanup::~DBCleanup()
-{
- // Let it throw. If db can't be cleared further tests are unreliable
- CKM::ManagerShPtr mgr = CKM::Manager::create();
- for(const auto& it:m_aliases)
- mgr->removeAlias(it);
- m_aliases.clear();
+#include <unordered_map>
+#include <tzplatform_config.h>
+
+const std::string SMACK_USER_APP_PREFIX = "User::Pkg::";
+const char *SYSTEM_LABEL = ckmc_owner_id_system;
+const char *TEST_LABEL = "test_label";
+const char *TEST_LABEL_2 = "test_label_2";
+const char *TEST_LABEL_3 = "test_label_3";
+const char *TEST_LABEL_4 = "test_label_4";
+const char *TEST_LABEL_5 = "test_label_5";
+
+void generate_random(size_t random_bytes, char *output)
+{
+ RUNNER_ASSERT(random_bytes>0 && output);
+
+ std::ifstream is("/dev/urandom", std::ifstream::binary);
+ RUNNER_ASSERT_MSG(is, "Failed to read /dev/urandom");
+ is.read(output, random_bytes);
+ if(static_cast<std::streamsize>(random_bytes) != is.gcount()) {
+ RUNNER_ASSERT_MSG(false,
+ "Not enough bytes read from /dev/urandom: " << random_bytes << "!=" <<
+ is.gcount());
+ }
}
-// returns process label
-CharPtr get_label()
-{
+std::string getLabel() {
int ret;
- char* my_label = NULL;
- RUNNER_ASSERT_MSG(0 <= (ret = smack_new_label_from_self(&my_label)),
+ char* myLabel = NULL;
+ RUNNER_ASSERT_MSG(0 <= (ret = smack_new_label_from_self(&myLabel)),
"Failed to get smack label for self. Error: " << ret);
+ RUNNER_ASSERT_MSG(myLabel, "NULL smack label");
+ std::string result = myLabel;
+ free(myLabel);
+ return result;
+}
- return CharPtr(my_label, free);
+std::string getOwnerIdFromSelf() {
+ const std::string& prefix = SMACK_USER_APP_PREFIX;
+ std::string smack = getLabel();
+ if (0 == smack.compare(0, prefix.size(), prefix))
+ return smack.substr(prefix.size(), std::string::npos);
+ return "/" + smack;
}
std::string aliasWithLabel(const char *label, const char *alias)
return std::string(alias);
}
-// changes process label
-void change_label(const char* label)
-{
- int ret = smack_set_label_for_self(label);
- RUNNER_ASSERT_MSG(0 == ret, "Error in smack_set_label_for_self("<<label<<"). Error: " << ret);
-}
-
-ScopedLabel::ScopedLabel(const char* label) : m_original_label(get_label())
+std::string aliasWithLabelFromSelf(const char *alias)
{
- change_label(label);
-}
+ std::ostringstream oss;
+ oss << getOwnerIdFromSelf() << ckmc_label_name_separator << alias;
-ScopedLabel::~ScopedLabel()
-{
- /*
- * Let it throw. If we can't restore label then remaining tests results will be
- * unreliable anyway.
- */
- change_label(m_original_label.get());
+ return oss.str();
}
-const char * CKMCErrorToString(int error) {
#define ERRORDESCRIBE(name) case name: return #name
+const char * CKMCErrorToString(int error) {
switch(error) {
ERRORDESCRIBE(CKMC_ERROR_NONE);
ERRORDESCRIBE(CKMC_ERROR_INVALID_PARAMETER);
ERRORDESCRIBE(CKMC_ERROR_FILE_ACCESS_DENIED);
ERRORDESCRIBE(CKMC_ERROR_NOT_EXPORTABLE);
ERRORDESCRIBE(CKMC_ERROR_FILE_SYSTEM);
+ ERRORDESCRIBE(CKMC_ERROR_NOT_SUPPORTED);
ERRORDESCRIBE(CKMC_ERROR_UNKNOWN);
default: return "Error not defined";
}
-#undef ERRORDESCRIBE
}
+#undef ERRORDESCRIBE
std::string CKMCReadableError(int error) {
std::string output("Error: ");
return output;
}
-void save_data(const char* alias, const char *data, int expected_err)
-{
- save_data(alias, data, strlen(data), expected_err);
-}
-
-void save_data(const char* alias, const char *data, size_t len, int expected_err = CKMC_ERROR_NONE)
+void save_data(const char* alias, const char *data, size_t len, const char* password,
+ int expected_err, bool exportable)
{
RUNNER_ASSERT(alias);
RUNNER_ASSERT(data);
buffer.data = reinterpret_cast<unsigned char*>(const_cast<char*>(data));
buffer.size = len;
ckmc_policy_s policy;
- policy.password = NULL;
- policy.extractable = true;
-
+ policy.password = const_cast<char*>(password);
+ policy.extractable = exportable;
int ret = ckmc_save_data(alias, buffer, policy);
RUNNER_ASSERT_MSG(expected_err == ret, "Saving data failed. "
- << CKMCErrorToString(ret) << " while expected: "
- << CKMCErrorToString(expected_err));
+ << CKMCErrorToString(ret) << " while expected: "
+ << CKMCErrorToString(expected_err));
+}
+
+void save_data(const char* alias, const char *data, int expected_err, bool exportable)
+{
+ save_data(alias, data, strlen(data), nullptr, expected_err, exportable);
+}
+void save_data(const char* alias, const char *data, size_t len, int expected_err, bool exportable)
+{
+ save_data(alias, data, len, nullptr, expected_err, exportable);
}
ScopedSaveData::ScopedSaveData(const char* alias, const char *data, int expected_err) : m_alias(alias)
check_remove_allowed(m_alias.c_str());
}
-void GarbageCollector::add(const char* alias)
-{
- save_item item;
- item.item_alias = std::string(alias);
- item.owner_label = std::string(get_label().get());
- item.owner_uid = geteuid();
- item.owner_gid = getegid();
- m_garbage.push_back(item);
-}
-
-void GarbageCollector::save(const char* alias, const char *data, int expected_err)
-{
- save(alias, data, strlen(data), expected_err);
-}
-
-void GarbageCollector::save(const char* alias, const char *data, size_t len, int expected_err)
-{
- save_data(alias, data, len, expected_err);
-
- if(CKMC_ERROR_NONE == expected_err)
- add(alias);
-}
-
-GarbageCollector::~GarbageCollector()
-{
- for(auto & item : m_garbage)
- {
- ScopedAccessProvider ap(item.owner_label, item.owner_uid, item.owner_gid);
- check_remove_allowed(item.item_alias.c_str());
- }
-}
-
ScopedDBUnlock::ScopedDBUnlock(uid_t user_id, const char* passwd) : m_uid(user_id)
{
int temp;
int ret;
auto control = CKM::Control::create();
RUNNER_ASSERT_MSG(CKM_API_SUCCESS == (ret = control->unlockUserKey(user_id, passwd)),
- "Error=" << CKM::ErrorToString(ret));
+ "Error=" << CKM::APICodeToString(ret));
}
void remove_user_data(uid_t user_id)
RUNNER_ASSERT_MSG(expected == actual, "Actual list of aliases differ from expected list.");
}
+void check_alias_info_list_helper(const CKM::AliasInfoVector& expected,
+ const CKM::AliasInfoVector& actual,
+ const std::string &userSmackLabel)
+{
+ std::string errorLogMsg;
+ std::unordered_map<std::string, bool> aliasPwdMap;
+
+ RUNNER_ASSERT_MSG(expected.size() == actual.size(), "Aliases item count differs, expected: " <<
+ expected.size() << " actual: " << actual.size());
+
+ for (const auto &it : actual)
+ {
+ aliasPwdMap[std::get<0>(it)] = std::get<1>(it).passwordProtected;
+ }
+
+
+ for (const auto &it : expected)
+ {
+ auto aliasPwd = aliasPwdMap.find(userSmackLabel + std::get<0>(it));
+ if (aliasPwd != aliasPwdMap.end()) {
+ if (aliasPwd->second != std::get<1>(it).passwordProtected) {
+ errorLogMsg += "Alias: " + std::get<0>(it) + " has wrong encryption status: "
+ + std::to_string(std::get<1>(it).passwordProtected) + "\n";
+ }
+ }
+ else {
+ errorLogMsg += "Expected alias: " + std::get<0>(it) + " not found.\n";
+ }
+ }
+
+ if (!errorLogMsg.empty()) {
+ for (const auto &it : actual)
+ {
+ errorLogMsg += "Actual alias: " + std::get<0>(it) + " status: "
+ + std::to_string(std::get<1>(it).passwordProtected) + "\n";
+ }
+ RUNNER_FAIL_MSG("Actual list of aliases differ from expected list.\n" + errorLogMsg);
+ }
+}
+
+std::pair<std::string, CKM::AliasInfo> make_alias_info(const std::string& alias, bool password)
+{
+ return std::make_pair(alias, CKM::AliasInfo({password, CKM::BackendId::SW}));
+}
+
+void check_alias_info_list(const CKM::AliasInfoVector& expected)
+{
+ ckmc_alias_info_list_s *aliasInfoList = NULL;
+ int ret = ckmc_get_data_alias_info_list(&aliasInfoList);
+ RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Failed to get the list of data aliases. " << ret << " / "
+ << CKMCErrorToString(ret));
+
+ CKM::AliasInfoVector actual;
+ ckmc_alias_info_list_s *plist = aliasInfoList;
+ char* alias;
+ bool isPasswordProtected;
+ unsigned int it = 0;
+ while (plist)
+ {
+ ret = ckmc_alias_info_get_alias(plist->info, &alias);
+ RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Failed to get alias. " << ret << " / "
+ << CKMCErrorToString(ret));
+ ret = ckmc_alias_info_is_password_protected(plist->info, &isPasswordProtected);
+ RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Failed to get password protection status" << ret << " / "
+ << CKMCErrorToString(ret));
+ RUNNER_ASSERT_MSG(alias != nullptr, "Got null alias. Iterator: " << it);
+ actual.push_back(make_alias_info(alias, isPasswordProtected));
+ plist = plist->next;
+ it++;
+ }
+ ckmc_alias_info_list_all_free(aliasInfoList);
+ check_alias_info_list_helper(expected, actual);
+}
+
size_t count_aliases(alias_type_ type, size_t minimum_initial_element_count)
{
ckmc_alias_list_s *aliasList = NULL;
std::string sharedDatabase(const CKM::Alias & alias)
{
- return aliasWithLabel(ckmc_label_shared_owner, alias.c_str());
+ return aliasWithLabel(ckmc_owner_id_system, alias.c_str());
+}
+
+ckmc_raw_buffer_s* createRandomBufferCAPI(size_t random_bytes)
+{
+ ckmc_raw_buffer_s* buffer = NULL;
+ char* data = static_cast<char*>(malloc(random_bytes*sizeof(char)));
+ RUNNER_ASSERT(data);
+ generate_random(random_bytes, data);
+ int ret = ckmc_buffer_new(reinterpret_cast<unsigned char*>(data), random_bytes, &buffer);
+ RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Buffer creation failed: " << CKMCErrorToString(ret));
+ return buffer;
+}
+
+CKM::RawBuffer createRandomBuffer(size_t random_bytes)
+{
+ char buffer[random_bytes];
+ generate_random(random_bytes, buffer);
+ return CKM::RawBuffer(buffer, buffer + random_bytes);
+}
+
+ckmc_key_s *generate_AES_key(size_t lengthBits, const char *passwd)
+{
+ ckmc_key_s *retval = reinterpret_cast<ckmc_key_s *>(malloc(sizeof(ckmc_key_s)));
+ RUNNER_ASSERT(retval != NULL);
+
+ RUNNER_ASSERT(lengthBits%8 == 0);
+ char *char_key_AES = reinterpret_cast<char*>(malloc(lengthBits/8));
+ RUNNER_ASSERT(char_key_AES != NULL);
+ generate_random(lengthBits/8, char_key_AES);
+
+ retval->raw_key = reinterpret_cast<unsigned char *>(char_key_AES);
+ retval->key_size = lengthBits/8;
+ retval->key_type = CKMC_KEY_AES;
+ retval->password = passwd?strdup(passwd):NULL;
+
+ return retval;
+}
+
+void validate_AES_key(ckmc_key_s *analyzed)
+{
+ RUNNER_ASSERT_MSG(analyzed, "provided key is NULL");
+ RUNNER_ASSERT_MSG(analyzed->raw_key != NULL, "provided key is empty");
+ RUNNER_ASSERT_MSG(analyzed->key_size==(128/8) ||
+ analyzed->key_size==(192/8) ||
+ analyzed->key_size==(256/8), "provided key length is invalid");
+ RUNNER_ASSERT_MSG(analyzed->key_type = CKMC_KEY_AES, "expected AES key, while got: " << analyzed->key_type);
+}
+
+void compare_AES_keys(ckmc_key_s *first, ckmc_key_s *second)
+{
+ validate_AES_key(first);
+ validate_AES_key(second);
+ RUNNER_ASSERT_MSG(
+ (first->key_size==second->key_size) &&
+ (memcmp(first->raw_key, second->raw_key, first->key_size)==0),
+ "data has been modified in key manager");
+ // bypassing password intentionally
+}
+
+ParamListPtr createParamListPtr()
+{
+ ckmc_param_list_h list = NULL;
+ assert_positive(ckmc_param_list_new, &list);
+ return ParamListPtr(list, ckmc_param_list_free);
+}
+
+void setParam(ParamListPtr& params, ckmc_param_name_e name, ckmc_raw_buffer_s* buffer)
+{
+ int ret = ckmc_param_list_set_buffer(params.get(), name, buffer);
+ RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE,
+ "Failed to set param " << name << " error: " << CKMCErrorToString(ret));
+}
+
+void setParam(ParamListPtr& params, ckmc_param_name_e name, uint64_t integer)
+{
+ int ret = ckmc_param_list_set_integer(params.get(), name, integer);
+ RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE,
+ "Failed to set param " << name << " error: " << CKMCErrorToString(ret));
+}
+
+void assert_buffers_equal(const ckmc_raw_buffer_s* b1, const ckmc_raw_buffer_s* b2, bool equal)
+{
+ if(equal) {
+ RUNNER_ASSERT_MSG(b1->size == b2->size,
+ "Buffer size differs: " << b1->size << "!=" << b2->size);
+ RUNNER_ASSERT_MSG(0 == memcmp(b1->data, b2->data, b1->size), "Buffer contents differ");
+ } else {
+ RUNNER_ASSERT_MSG(b1->size != b2->size || 0 != memcmp(b1->data, b2->data, b1->size),
+ "Buffers should be different");
+ }
+}
+
+RawBufferPtr create_raw_buffer(ckmc_raw_buffer_s* buffer)
+{
+ return RawBufferPtr(buffer, ckmc_buffer_free);
+}
+
+CipherCtxPtr create_cipher_ctx(ckmc_cipher_ctx_h ctx)
+{
+ return CipherCtxPtr(ctx, ckmc_cipher_free);
+}
+
+CKM::Policy generate_ckm_policy(int iterator_nr) {
+ if (iterator_nr % 2) { // policy with password and with / without extractable flag
+ return CKM::Policy(CKM::Password("test_pwd"), iterator_nr % 4);
+ }
+ return CKM::Policy();
+}
+
+void require_default_user(char *argv[])
+{
+ uid_t expected_uid = tzplatform_getuid(TZ_SYS_DEFAULT_USER);
+ if (expected_uid != geteuid()) {
+ std::string userStr("owner");
+ const char* user = tzplatform_getenv(TZ_SYS_DEFAULT_USER);
+ if (user)
+ userStr = user;
+
+ std::cerr << argv[0] << " should be executed as " << userStr << ". Aborting" << std::endl;
+ exit(-1);
+ }
}