SET(BUILD_YACA ON)
SET(BUILD_NETHER ON)
SET(BUILD_ODE ON)
+ SET(BUILD_E2EE_ADAPTATION_LAYER ON)
ENDIF(BUILD_ALL_TESTS)
# If supported for the target machine, emit position-independent code,suitable
SET(TARGET_CKM_PRIVILEGED_TESTS "ckm-privileged-tests")
SET(TARGET_CKMI_TESTS "ckm-integration-tests")
SET(COMMON_TARGET_TEST "tests-common")
+SET(TARGET_E2EE_TESTS "e2ee-tests")
############################# subdirectories ##################################
<filesystem path="/usr/bin/security-manager-tests" exec_label="System::Privileged" />
<filesystem path="/usr/bin/cynara-tests" exec_label="_" />
<filesystem path="/usr/bin/ckm-tests" exec_label="User" />
+ <filesystem path="/usr/bin/e2ee-tests" exec_label="User" />
<filesystem path="/usr/bin/ckm-privileged-tests" exec_label="System::Privileged" />
<filesystem path="/usr/bin/nether-tests" exec_label="System::Privileged" />
<filesystem path="/usr/bin/libteec-tests" exec_label="System::Privileged" />
BuildRequires: pkgconfig(libcap)
BuildRequires: pkgconfig(libsmack)
BuildRequires: pkgconfig(security-manager)
+ # TODO: BuildRequires: pkgconfig(key-manager) >=0.1.48
BuildRequires: pkgconfig(key-manager)
BuildRequires: key-manager-initial-values
BuildRequires: util-linux
/usr/bin/yaca-test
/usr/bin/nether-tests
/usr/bin/ode-tests
+/usr/bin/e2ee-tests
%{ckm_test_dir}/*
/etc/security-tests
/usr/lib/security-tests/cynara-tests/plugins/single-policy/*
IF(BUILD_ODE)
ADD_SUBDIRECTORY(ode)
ENDIF(BUILD_ODE)
+
+IF(BUILD_E2EE_ADAPTATION_LAYER)
+ ADD_SUBDIRECTORY(e2ee-adaptation-layer)
+ENDIF(BUILD_E2EE_ADAPTATION_LAYER)
#include <ckm/ckm-manager-async.h>
#include <ckmc/ckmc-type.h>
#include <ckmc/ckmc-error.h>
+#include <ckmc/ckmc-manager.h>
#include <tests_common.h>
#include <sys/types.h>
RUNNER_ASSERT_MSG(false, "Unexpected exception");
}
}
+
+class AliasRemover
+{
+public:
+ AliasRemover(const char* alias) : alias(alias) {}
+ ~AliasRemover() {
+ ckmc_remove_alias(alias);
+ }
+
+ AliasRemover(AliasRemover&& other) {
+ alias = other.alias;
+ other.alias = nullptr;
+ }
+
+ AliasRemover& operator=(AliasRemover&& other) {
+ if (&other == this)
+ return *this;
+
+ alias = other.alias;
+ other.alias = nullptr;
+ }
+
+private:
+ const char* alias;
+};
--- /dev/null
+# Copyright (c) 2023 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.
+# 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(FindPkgConfig)
+
+
+# Adaptation layer
+SET(TARGET_E2EE_ADAPTATION_LAYER "e2ee-adaptation-layer")
+
+PKG_CHECK_MODULES(E2EE_ADAPTATION_LAYER_DEP
+ REQUIRED
+ key-manager # >=0.1.48
+)
+
+SET(E2EE_ADAPTATION_LAYER_SOURCES
+ e2ee-adaptation-layer.cpp
+)
+
+ADD_LIBRARY(${TARGET_E2EE_ADAPTATION_LAYER}
+ STATIC ${E2EE_ADAPTATION_LAYER_SOURCES}
+)
+
+TARGET_INCLUDE_DIRECTORIES(${TARGET_E2EE_ADAPTATION_LAYER}
+ SYSTEM PUBLIC ${E2EE_ADAPTATION_LAYER_DEP_INCLUDE_DIRS}
+)
+
+TARGET_LINK_LIBRARIES(${TARGET_E2EE_ADAPTATION_LAYER}
+ ${E2EE_ADAPTATION_LAYER_DEP_LIBRARIES}
+)
+
+
+# Tests
+SET(E2EE_TESTS_SOURCES
+ tests.cpp
+)
+
+ADD_EXECUTABLE(${TARGET_E2EE_TESTS} ${E2EE_TESTS_SOURCES})
+
+TARGET_INCLUDE_DIRECTORIES(${TARGET_E2EE_TESTS}
+ PRIVATE ${PROJECT_SOURCE_DIR}/src/common
+ PRIVATE ${PROJECT_SOURCE_DIR}/src/ckm
+)
+
+TARGET_LINK_LIBRARIES(${TARGET_E2EE_TESTS}
+ ${TARGET_E2EE_ADAPTATION_LAYER}
+ ${TARGET_CKM_TEST_COMMON}
+)
+
+INSTALL(TARGETS ${TARGET_E2EE_TESTS}
+ DESTINATION /usr/bin
+)
#include "e2ee-adaptation-layer.h"
-int ckmew_key_agreement(const char * /*private_key_alias*/,
- const unsigned char * /*raw_public_key*/,
- size_t /*raw_public_key_len*/,
- const char * /*new_key_alias*/)
+#include <cstring>
+#include <memory>
+
+#include <ckmc/ckmc-manager.h>
+
+namespace {
+
+const char* const LABEL = "label";
+const char* const CONTEXT = "context";
+const char* const SECRET_ALIAS = "temporary_shared_e2ee_secret";
+
+typedef std::unique_ptr<struct __ckmc_param_list, decltype(&ckmc_param_list_free)> ParamsPtr;
+
+std::tuple<ParamsPtr, int> makeParams()
{
- // TODO
- return CKMC_ERROR_NONE;
+ ckmc_param_list_h params = nullptr;
+ int ret = ckmc_param_list_new(¶ms);
+ return std::make_tuple(ParamsPtr(params, ckmc_param_list_free), ret);
+}
+
+typedef std::unique_ptr<ckmc_raw_buffer_s, decltype(&ckmc_buffer_free)> BufferPtr;
+
+std::tuple<BufferPtr, int> makeBuffer(const unsigned char* data, size_t size)
+{
+ ckmc_raw_buffer_s* buffer = nullptr;
+ int ret = ckmc_buffer_new(const_cast<unsigned char*>(data), size, &buffer);
+ return std::make_tuple(BufferPtr(buffer, ckmc_buffer_free), ret);
+}
+
+class AliasRemover
+{
+public:
+ AliasRemover(const char *alias) : alias(alias) {}
+ ~AliasRemover() {
+ ckmc_remove_alias(alias);
+ }
+
+private:
+ const char* alias;
+};
+
+} // anonymous namespace
+
+int ckmew_key_agreement(const char *private_key_alias,
+ const unsigned char *raw_public_key,
+ size_t raw_public_key_len,
+ const char *new_key_alias)
+{
+ if (private_key_alias == nullptr || raw_public_key == nullptr || raw_public_key_len == 0 ||
+ new_key_alias == nullptr)
+ return CKMC_ERROR_INVALID_PARAMETER;
+
+ ckmc_policy_s unexportable { nullptr, false };
+
+ auto [ecdh_params, ret] = makeParams();
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ ret = ckmc_param_list_set_integer(ecdh_params.get(), CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_ECDH);
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ auto [peers_public, ret2] = makeBuffer(raw_public_key, raw_public_key_len);
+ if (ret2 != CKMC_ERROR_NONE)
+ return ret2;
+
+ ret = ckmc_param_list_set_buffer(ecdh_params.get(), CKMC_PARAM_ECDH_PUBKEY, peers_public.get());
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ // derive shared secret
+ ret = ckmc_key_derive(ecdh_params.get(),
+ private_key_alias,
+ nullptr,
+ SECRET_ALIAS,
+ unexportable);
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ // delete secret
+ AliasRemover remover(SECRET_ALIAS);
+
+ // set KBKDF params
+ auto [kbkdf_params, ret3] = makeParams();
+ if (ret3 != CKMC_ERROR_NONE)
+ return ret3;
+
+ ret = ckmc_param_list_set_integer(kbkdf_params.get(), CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_KBKDF);
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ ret = ckmc_param_list_set_integer(kbkdf_params.get(),
+ CKMC_PARAM_KDF_PRF,
+ CKMC_KDF_PRF_HMAC_SHA256);
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ ret = ckmc_param_list_set_integer(kbkdf_params.get(),
+ CKMC_PARAM_KBKDF_MODE,
+ CKMC_KBKDF_MODE_COUNTER);
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ ret = ckmc_param_list_set_integer(kbkdf_params.get(),
+ CKMC_PARAM_KBKDF_COUNTER_LOCATION,
+ CKMC_KBKDF_COUNTER_BEFORE_FIXED);
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ auto [label_buf, ret4] = makeBuffer(reinterpret_cast<const unsigned char*>(LABEL),
+ strlen(LABEL));
+ if (ret4 != CKMC_ERROR_NONE)
+ return ret4;
+
+ ret = ckmc_param_list_set_buffer(kbkdf_params.get(), CKMC_PARAM_KBKDF_LABEL, label_buf.get());
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ auto [context_buf, ret5] = makeBuffer(reinterpret_cast<const unsigned char*>(CONTEXT),
+ strlen(CONTEXT));
+ if (ret5 != CKMC_ERROR_NONE)
+ return ret5;
+
+ ret = ckmc_param_list_set_buffer(kbkdf_params.get(),
+ CKMC_PARAM_KBKDF_CONTEXT,
+ context_buf.get());
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ ret = ckmc_param_list_set_integer(kbkdf_params.get(), CKMC_PARAM_KDF_LEN, 32);
+ if (ret != CKMC_ERROR_NONE)
+ return ret;
+
+ // derive symmetric key
+ return ckmc_key_derive(kbkdf_params.get(), SECRET_ALIAS, nullptr, new_key_alias, unexportable);
}
int ckmew_key_derive_pbkdf2(const char * /*password*/,
int ckmew_get_ocf_cert_chain(char ** /*cert_chain*/, size_t * /*cert_chain_len*/)
{
// TODO
- return DCM_ERROR_NONE;
+ return 0;
}
int ckmew_sign_with_ocf(const char * /*public_key_alias*/,
ckmc_raw_buffer_s** /*signature_buf*/)
{
// TODO
- return DCM_ERROR_NONE;
+ return 0;
}
--- /dev/null
+/*
+ * Copyright (c) 2023 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.
+ * 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 "e2ee-adaptation-layer.h"
+
+#include <dpl/test/test_runner.h>
+#include <ckm-common.h>
+#include <ckmc/ckmc-manager.h>
+#include <ckmc/ckmc-control.h>
+
+namespace {
+
+const uid_t UID = 5001;
+
+struct KeyAliasPair
+{
+ std::string prv;
+ std::string pub;
+};
+
+const KeyAliasPair OURS = { "our_ec_private", "our_ec_public" };
+const KeyAliasPair PEERS = { "peer_ec_private", "peer_ec_public" };
+const KeyAliasPair PEERS2 = { "peer2_ec_private", "peer2_ec_public" };
+const KeyAliasPair WRONG = { "wrong_ec_private", "wrong_ec_public" };
+const KeyAliasPair RSA = { "rsa_private", "rsa_public" };
+
+const ckmc_policy_s UNEXPORTABLE { nullptr, false };
+const ckmc_policy_s EXPORTABLE { nullptr, true };
+
+class EALGroupFixture: public DPL::Test::TestGroup
+{
+private:
+ void GenerateEC(ckmc_ec_type_e curve,
+ const KeyAliasPair& pair,
+ const ckmc_policy_s& policy_prv,
+ const ckmc_policy_s& policy_pub)
+ {
+ ckmc_remove_alias(pair.prv.c_str());
+ ckmc_remove_alias(pair.pub.c_str());
+ assert_positive(ckmc_create_key_pair_ecdsa,
+ curve,
+ pair.prv.c_str(),
+ pair.pub.c_str(),
+ policy_prv,
+ policy_pub);
+ }
+
+public:
+ void Init() override
+ {
+ remove_user_data(UID);
+ assert_positive(ckmc_unlock_user_key, UID, "db-pass");
+
+ GenerateEC(CKMC_EC_PRIME256V1, OURS, UNEXPORTABLE, EXPORTABLE);
+ GenerateEC(CKMC_EC_PRIME256V1, PEERS, UNEXPORTABLE, EXPORTABLE);
+ GenerateEC(CKMC_EC_PRIME256V1, PEERS2, EXPORTABLE, EXPORTABLE);
+ GenerateEC(CKMC_EC_PRIME192V1, WRONG, UNEXPORTABLE, EXPORTABLE);
+
+ ckmc_remove_alias(RSA.prv.c_str());
+ ckmc_remove_alias(RSA.pub.c_str());
+ assert_positive(ckmc_create_key_pair_rsa,
+ 1024,
+ RSA.prv.c_str(),
+ RSA.pub.c_str(),
+ UNEXPORTABLE,
+ EXPORTABLE);
+ }
+
+ void Finish() override
+ {
+ int ret = ckmc_lock_user_key(UID);
+ if (ret != CKMC_ERROR_NONE)
+ RUNNER_ERROR_MSG("DB lock failed: " << CKMCErrorToString(ret));
+ remove_user_data(UID);
+ }
+};
+typedef std::unique_ptr<ckmc_key_s, decltype(&ckmc_key_free)> KeyPtr;
+
+KeyPtr getKey(const std::string& alias)
+{
+ ckmc_key_s* key = nullptr;
+ assert_positive(ckmc_get_key, alias.c_str(), "", &key);
+
+ return KeyPtr(key, ckmc_key_free);
+}
+
+AliasRemover keyAgreement(const std::string &prv, const std::string& pub, const char* derived)
+{
+ auto pub_key = getKey(pub);
+ assert_positive(ckmew_key_agreement, prv.c_str(), pub_key->raw_key, pub_key->key_size, derived);
+
+ return AliasRemover(derived);
+}
+
+} // namespace anonymous
+
+RUNNER_TEST_GROUP_INIT_ENV(E2EE_ADAPTATION_LAYER, EALGroupFixture);
+
+RUNNER_TEST(TEAL_0010_key_agreement_positive)
+{
+ const char* const OURS_DERIVED = "ours_derived";
+ const char* const PEERS_DERIVED = "peers_derived";
+ const char* const PEERS2_DERIVED = "peers2_derived";
+
+ auto our_remover = keyAgreement(OURS.prv, PEERS.pub, OURS_DERIVED);
+ auto peer_remover = keyAgreement(PEERS.prv, OURS.pub, PEERS_DERIVED);
+ auto peer2_remover = keyAgreement(PEERS2.prv, OURS.pub, PEERS2_DERIVED);
+
+ auto plain = create_raw_buffer(createRandomBufferCAPI(512));
+ auto iv = create_raw_buffer(createRandomBufferCAPI(16));
+
+ auto params = createParamListPtr();
+ setParam(params, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_AES_CTR);
+ setParam(params, CKMC_PARAM_ED_IV, iv.get());
+
+ ckmc_raw_buffer_s* encrypted = nullptr;
+ assert_positive(ckmc_encrypt_data, params.get(), OURS_DERIVED, "", *plain.get(), &encrypted);
+ auto encryptedPtr = create_raw_buffer(encrypted);
+
+ ckmc_raw_buffer_s* decrypted = nullptr;
+ assert_positive(ckmc_decrypt_data, params.get(), PEERS_DERIVED, "", *encrypted, &decrypted);
+ auto decryptedPtr = create_raw_buffer(decrypted);
+
+ assert_buffers_equal(plain.get(), decrypted);
+
+ decryptedPtr.reset();
+ decrypted = nullptr;
+ assert_positive(ckmc_decrypt_data, params.get(), PEERS2_DERIVED, "", *encrypted, &decrypted);
+ decryptedPtr = create_raw_buffer(decrypted);
+
+ assert_buffers_equal(plain.get(), decrypted, false);
+}
+
+
+RUNNER_TEST(TEAL_0020_key_agreement_wrong_arguments)
+{
+ const char* const DERIVED = "derived";
+
+ auto pub_key = getKey(PEERS.pub);
+
+ auto invalid = [](const char* prv,
+ const unsigned char* pub,
+ size_t pub_size,
+ const char* derived)
+ {
+ assert_invalid_param(ckmew_key_agreement, prv, pub, pub_size, derived);
+ };
+
+ auto garbage = create_raw_buffer(createRandomBufferCAPI(pub_key->key_size));
+
+ invalid(nullptr, pub_key->raw_key, pub_key->key_size, DERIVED);
+ invalid(OURS.pub.c_str(), pub_key->raw_key, pub_key->key_size, DERIVED);
+ invalid(OURS.prv.c_str(), nullptr, pub_key->key_size, DERIVED);
+ invalid(OURS.prv.c_str(), pub_key->raw_key, 6, DERIVED);
+ invalid(OURS.prv.c_str(), garbage->data, garbage->size, DERIVED);
+ invalid(OURS.prv.c_str(), pub_key->raw_key, 0, DERIVED);
+ invalid(OURS.prv.c_str(), pub_key->raw_key, pub_key->key_size, nullptr);
+}
+
+RUNNER_TEST(TEAL_0030_key_agreement_wrong_aliases)
+{
+ const char* const DERIVED = "derived";
+
+ auto pub_key = getKey(PEERS.pub);
+
+ assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+ ckmew_key_agreement,
+ "",
+ pub_key->raw_key,
+ pub_key->key_size,
+ DERIVED);
+
+ assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+ ckmew_key_agreement,
+ "nonexistent-alias",
+ pub_key->raw_key,
+ pub_key->key_size,
+ DERIVED);
+
+ assert_positive(ckmew_key_agreement,
+ OURS.prv.c_str(),
+ pub_key->raw_key,
+ pub_key->key_size,
+ DERIVED);
+
+ AliasRemover remover(DERIVED);
+
+ assert_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+ ckmew_key_agreement,
+ OURS.prv.c_str(),
+ pub_key->raw_key,
+ pub_key->key_size,
+ DERIVED);
+}
+
+int main(int argc, char *argv[])
+{
+ return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);
+}