Merge branch 'ckm' into tizen 99/291199/1 tizen_6.5 tizen_7.0
authorDariusz Michaluk <d.michaluk@samsung.com>
Tue, 11 Apr 2023 12:22:38 +0000 (14:22 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Tue, 11 Apr 2023 12:22:38 +0000 (14:22 +0200)
Change-Id: I568bc8337c9fca77181af04283efd7c28e1ddcdc

18 files changed:
CMakeLists.txt
packaging/security-tests.manifest
packaging/security-tests.spec
src/CMakeLists.txt
src/ckm/CMakeLists.txt
src/ckm/ckm-common.cpp
src/ckm/ckm-common.h
src/ckm/unprivileged/CMakeLists.txt
src/ckm/unprivileged/algo-params.cpp
src/ckm/unprivileged/capi-testcases.cpp
src/ckm/unprivileged/encryption-decryption.cpp
src/ckm/unprivileged/key-derivation.cpp [new file with mode: 0644]
src/ckm/unprivileged/key-wrapping.cpp [new file with mode: 0644]
src/ckm/unprivileged/main.cpp
src/e2ee-adaptation-layer/CMakeLists.txt [new file with mode: 0644]
src/e2ee-adaptation-layer/e2ee-adaptation-layer.cpp [new file with mode: 0644]
src/e2ee-adaptation-layer/e2ee-adaptation-layer.h [new file with mode: 0644]
src/e2ee-adaptation-layer/tests.cpp [new file with mode: 0644]

index e941f15..4fe1851 100644 (file)
@@ -67,6 +67,7 @@ IF(BUILD_ALL_TESTS)
     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
@@ -109,6 +110,7 @@ SET(TARGET_CKM_TESTS "ckm-tests")
 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 ##################################
 
index 0374731..dfda779 100644 (file)
@@ -3,6 +3,7 @@
         <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" />
index 99ac084..0f99419 100644 (file)
@@ -12,7 +12,7 @@ BuildRequires: libattr-devel
 BuildRequires: pkgconfig(libcap)
 BuildRequires: pkgconfig(libsmack)
 BuildRequires: pkgconfig(security-manager)
-BuildRequires: pkgconfig(key-manager)
+BuildRequires: pkgconfig(key-manager) >= 0.1.49
 BuildRequires: key-manager-initial-values
 BuildRequires: util-linux
 BuildRequires: pkgconfig(yaca)
@@ -35,6 +35,7 @@ BuildRequires: pkgconfig(vconf)
 BuildRequires: pkgconfig(libgum) >= 1.0.5
 BuildRequires: pkgconfig(security-privilege-manager)
 BuildRequires: pkgconfig(libsystemd)
+BuildRequires: pkgconfig(device-certificate-manager) >= 2.1
 BuildRequires: openssl1.1
 Requires: gdb
 Requires: diffutils
@@ -115,6 +116,7 @@ echo "security-tests postinst done ..."
 /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/*
index 9a6f938..743513f 100644 (file)
@@ -110,3 +110,7 @@ ENDIF(BUILD_NETHER)
 IF(BUILD_ODE)
     ADD_SUBDIRECTORY(ode)
 ENDIF(BUILD_ODE)
+
+IF(BUILD_E2EE_ADAPTATION_LAYER)
+    ADD_SUBDIRECTORY(e2ee-adaptation-layer)
+ENDIF(BUILD_E2EE_ADAPTATION_LAYER)
index a07a007..0a4c175 100644 (file)
@@ -33,7 +33,7 @@ ADD_DEFINITIONS("-DCKM_RW_DATA_DIR=\"${CKM_RW_DATA_DIR}\"")
 PKG_CHECK_MODULES(CKM_TEST_COMMON_DEP
     REQUIRED
     openssl1.1
-    key-manager
+    key-manager>=0.1.49
     libtzplatform-config
 )
 
index c50f2d6..01c265c 100644 (file)
  * @author     Krzysztof Jackiewicz (k.jackiewicz@samsung.com)
  * @version    1.0
  */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <cstdlib>
 #include <string>
 #include <fstream>
 #include <sys/smack.h>
@@ -32,6 +36,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <unordered_map>
+#include <tzplatform_config.h>
 
 const std::string SMACK_USER_APP_PREFIX = "User::Pkg::";
 const char *SYSTEM_LABEL = ckmc_owner_id_system;
@@ -564,13 +569,28 @@ ParamListPtr createParamListPtr()
     return ParamListPtr(list, ckmc_param_list_free);
 }
 
-void assert_buffers_equal(const ckmc_raw_buffer_s b1, const ckmc_raw_buffer_s b2, bool equal)
+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");
+        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),
+        RUNNER_ASSERT_MSG(b1->size != b2->size || 0 != memcmp(b1->data, b2->data, b1->size),
                           "Buffers should be different");
     }
 }
@@ -586,3 +606,17 @@ CKM::Policy generate_ckm_policy(int iterator_nr) {
     }
     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);
+    }
+}
index a61ffcf..4d398e5 100644 (file)
@@ -28,6 +28,7 @@
 #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>
 
@@ -78,9 +79,6 @@ size_t list_size(const T* list)
     return size;
 }
 
-// scoped free
-typedef std::unique_ptr<char, void (*)(void *)> CharPtr;
-
 std::string getLabel();
 // returns process owner id
 std::string getOwnerIdFromSelf();
@@ -198,8 +196,10 @@ typedef std::shared_ptr<ckmc_raw_buffer_s> RawBufferPtr;
 typedef std::shared_ptr<struct __ckmc_param_list> ParamListPtr;
 
 ParamListPtr createParamListPtr();
+void setParam(ParamListPtr& params, ckmc_param_name_e name, ckmc_raw_buffer_s* buffer);
+void setParam(ParamListPtr& params, ckmc_param_name_e name, uint64_t integer);
 
-void assert_buffers_equal(const ckmc_raw_buffer_s b1, const ckmc_raw_buffer_s b2, bool equal=true);
+void assert_buffers_equal(const ckmc_raw_buffer_s* b1, const ckmc_raw_buffer_s* b2, bool equal=true);
 
 RawBufferPtr create_raw_buffer(ckmc_raw_buffer_s* buffer);
 
@@ -219,3 +219,30 @@ void test_no_observer(F&& func, Args... args)
         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;
+};
+
+void require_default_user(char *argv[]);
index 8b8dfda..03837f8 100644 (file)
@@ -24,6 +24,8 @@ SET(CKM_SOURCES
     encryption-decryption-env.cpp
     encryption-decryption.cpp
     sign-verify.cpp
+    key-wrapping.cpp
+    key-derivation.cpp
     main.cpp
 )
 
index 77919e0..cc4b004 100644 (file)
@@ -71,7 +71,7 @@ void check_buffer_param(ckmc_param_list_h list,
     ckmc_raw_buffer_s* got = NULL;
     int ret = ckmc_param_list_get_buffer(list, name, &got);
     RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "No such buffer param: " << name);
-    assert_buffers_equal(expected, *got);
+    assert_buffers_equal(&expected, got);
 }
 
 void assert_param_count(ckmc_param_list_h list, size_t expected)
index 4491458..d8049f2 100644 (file)
@@ -644,13 +644,13 @@ RUNNER_TEST(T3042_save_get_bin_data_C_API)
                        CKMCReadableError(temp));
 
        RUNNER_ASSERT_MSG(
-                       CKMC_ERROR_INVALID_PARAMETER == (temp = ckmc_save_data("data4", testData3, test_policy3)),
+                       CKMC_ERROR_NONE == (temp = ckmc_save_data("data4", testData3, test_policy3)),
                        CKMCReadableError(temp));
 
        size_t actual_cnt = count_aliases(ALIAS_DATA);
        RUNNER_ASSERT_MSG(
-                       (current_aliases_num+3) == actual_cnt,
-                       "Error: expecting " << (current_aliases_num+3) << " aliases, while found " << actual_cnt);
+                       (current_aliases_num+4) == actual_cnt,
+                       "Error: expecting " << (current_aliases_num+4) << " aliases, while found " << actual_cnt);
 
        ckmc_raw_buffer_s *testData4;
        RUNNER_ASSERT_MSG(
index 9030803..a29c452 100644 (file)
@@ -288,21 +288,6 @@ private:
     PolicyBackend m_backend;
 };
 
-
-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, int 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));
-}
-
 struct EncryptionResult
 {
     RawBufferPtr encrypted;
@@ -491,7 +476,7 @@ void encryptionWithCustomData(const Algo& algo, ckmc_param_name_e name)
     RawBufferPtr tmpDec = create_raw_buffer(decrypted);
 
     // check
-    assert_buffers_equal(*PLAIN_DATA.get(), *tmpDec.get());
+    assert_buffers_equal(PLAIN_DATA.get(), tmpDec.get());
     tmpDec.reset();
     decrypted = nullptr;
 
@@ -547,7 +532,7 @@ void testGcmIvSize(ckmc_raw_buffer_s* iv,
                            &decryptedTmp);
     decrypted = create_raw_buffer(decryptedTmp);
 
-    assert_buffers_equal(*PLAIN_DATA.get(), *decrypted.get());
+    assert_buffers_equal(PLAIN_DATA.get(), decrypted.get());
 }
 
 void testIntegrity(const Algo& algo)
@@ -570,7 +555,7 @@ void testIntegrity(const Algo& algo)
                            &decrypted);
 
     RawBufferPtr tmp = create_raw_buffer(decrypted);
-    assert_buffers_equal(*PLAIN_DATA.get(), *decrypted, false);
+    assert_buffers_equal(PLAIN_DATA.get(), decrypted, false);
 }
 
 void testCtrEncryptionInvalidLength(const Algo& algo)
@@ -599,9 +584,7 @@ void testCtrEncryptionInvalidLength(const Algo& algo)
         encryptedTmp = nullptr;
     };
     // invalid counter size
-    setParam(params, CKMC_PARAM_ED_CTR_LEN, -1);
-    test();
-    setParam(params, CKMC_PARAM_ED_CTR_LEN, 0);
+    setParam(params, CKMC_PARAM_ED_CTR_LEN, 0ULL);
     test();
     setParam(params, CKMC_PARAM_ED_CTR_LEN, CTR_DEFAULT_LEN+1);
     test();
@@ -663,9 +646,7 @@ void testCtrDecryptionInvalidLength(const Algo& algo)
         decrypted = nullptr;
     };
     // invalid counter size
-    setParam(ret.params, CKMC_PARAM_ED_CTR_LEN, -1);
-    test();
-    setParam(ret.params, CKMC_PARAM_ED_CTR_LEN, 0);
+    setParam(ret.params, CKMC_PARAM_ED_CTR_LEN, 0ULL);
     test();
     setParam(ret.params, CKMC_PARAM_ED_CTR_LEN, CTR_DEFAULT_LEN+1);
     test();
@@ -689,7 +670,7 @@ void testCtrDecryptionValidLength(const Algo& algo)
                                &decrypted);
         ckmc_buffer_free(decrypted);
         RawBufferPtr tmp = create_raw_buffer(decrypted);
-        assert_buffers_equal(*PLAIN_DATA.get(), *decrypted);
+        assert_buffers_equal(PLAIN_DATA.get(), decrypted);
     };
     // invalid counter size
     setParam(ret.params, CKMC_PARAM_ED_CTR_LEN, 1);
@@ -856,7 +837,7 @@ void testEncryptDecryptBigData(const Algo& algo)
                     &decrypted);
     RawBufferPtr tmp = create_raw_buffer(decrypted);
 
-    assert_buffers_equal(*BIG_DATA.get(), *decrypted);
+    assert_buffers_equal(BIG_DATA.get(), decrypted);
 }
 
 void testEncryptDecryptDifferentKeys(const Algo& algo, bool success)
@@ -880,7 +861,7 @@ void testEncryptDecryptDifferentKeys(const Algo& algo, bool success)
                                &decrypted);
         RawBufferPtr tmp = create_raw_buffer(decrypted);
 
-        assert_buffers_equal(*PLAIN_DATA.get(), *decrypted, false);
+        assert_buffers_equal(PLAIN_DATA.get(), decrypted, false);
     } else {
         assert_crypto_result(EncryptionError::INVALID_PARAM,
                              apiDecrypt,
@@ -909,7 +890,7 @@ void testRsaLongestData(const Algo& algo, size_t dataSize)
                            &decrypted);
     RawBufferPtr tmp = create_raw_buffer(decrypted);
 
-    assert_buffers_equal(*plain.get(), *decrypted);
+    assert_buffers_equal(plain.get(), decrypted);
 }
 
 void testRsaDataTooLong(const Algo& algo, size_t dataSize)
@@ -1165,7 +1146,7 @@ RUNNER_TEST_MULTIPLE(TED_0300_encrypt_decrypt, SyncEnv, AsyncEnv)
                                &decrypted);
         RawBufferPtr tmp = create_raw_buffer(decrypted);
 
-        assert_buffers_equal(*PLAIN_DATA.get(), *decrypted);
+        assert_buffers_equal(PLAIN_DATA.get(), decrypted);
     });
 }
 
@@ -1196,7 +1177,7 @@ RUNNER_TEST_MULTIPLE(TED_0310_encrypt_decrypt_password, SyncEnv, AsyncEnv)
                                &decrypted);
         RawBufferPtr tmp = create_raw_buffer(decrypted); // guarantees deletion
 
-        assert_buffers_equal(*PLAIN_DATA.get(), *decrypted);
+        assert_buffers_equal(PLAIN_DATA.get(), decrypted);
     });
 }
 
diff --git a/src/ckm/unprivileged/key-derivation.cpp b/src/ckm/unprivileged/key-derivation.cpp
new file mode 100644 (file)
index 0000000..9955525
--- /dev/null
@@ -0,0 +1,702 @@
+/*
+ *  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 <string>
+#include <vector>
+#include <unordered_map>
+
+#include <dpl/test/test_runner.h>
+#include <ckm-common.h>
+#include <ckmc/ckmc-manager.h>
+#include <ckmc/ckmc-control.h>
+
+namespace {
+
+const char* PASSWORD = "test-password";
+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 std::string DERIVED = "derived";
+const std::string SECRET = "secret";
+
+const ckmc_policy_s UNEXPORTABLE { nullptr, false };
+const ckmc_policy_s EXPORTABLE { nullptr, true };
+const ckmc_policy_s UNEXPORTABLE_PW { const_cast<char*>(PASSWORD), false };
+const ckmc_policy_s EXPORTABLE_PW { const_cast<char*>(PASSWORD), true };
+
+constexpr ckmc_kdf_prf_e HMAC256 = CKMC_KDF_PRF_HMAC_SHA256;
+constexpr ckmc_kdf_prf_e HMAC384 = CKMC_KDF_PRF_HMAC_SHA384;
+constexpr ckmc_kdf_prf_e HMAC512 = CKMC_KDF_PRF_HMAC_SHA512;
+constexpr ckmc_kbkdf_counter_location_e BEFORE = CKMC_KBKDF_COUNTER_BEFORE_FIXED;
+constexpr ckmc_kbkdf_counter_location_e AFTER = CKMC_KBKDF_COUNTER_AFTER_FIXED;
+constexpr ckmc_kbkdf_counter_location_e MIDDLE = CKMC_KBKDF_COUNTER_MIDDLE_FIXED;
+constexpr ckmc_kbkdf_mode_e COUNTER = CKMC_KBKDF_MODE_COUNTER;
+constexpr uint64_t U0 = 0;
+constexpr uint64_t U1 = 1;
+constexpr uint64_t U7 = 7;
+constexpr uint64_t U8 = 8;
+constexpr uint64_t U16 = 16;
+constexpr uint64_t U24 = 24;
+constexpr uint64_t U32 = 32;
+constexpr uint64_t U64 = 64;
+
+const RawBufferPtr LAB = create_raw_buffer(createRandomBufferCAPI(16));
+const RawBufferPtr CTX = create_raw_buffer(createRandomBufferCAPI(12));
+const RawBufferPtr FIX = create_raw_buffer(createRandomBufferCAPI(36));
+const RawBufferPtr ONE = create_raw_buffer(createRandomBufferCAPI(1));
+
+class EcdhGroupFixture: 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)
+    {
+        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_PW, EXPORTABLE);
+        GenerateEC(CKMC_EC_PRIME256V1, PEERS2, EXPORTABLE, EXPORTABLE);
+        GenerateEC(CKMC_EC_PRIME192V1, WRONG, UNEXPORTABLE, EXPORTABLE);
+
+        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);
+    }
+};
+
+struct DerivedFixture
+{
+    void init(const std::string&)
+    {
+    }
+
+    void finish()
+    {
+        ckmc_remove_alias(DERIVED.c_str());
+    }
+};
+
+RawBufferPtr getPublicKey(const std::string& pub_alias)
+{
+    ckmc_key_s *pubKey = nullptr;
+    assert_positive(ckmc_get_key, pub_alias.c_str(), "", &pubKey);
+
+    ckmc_raw_buffer_s* pubBuffer = nullptr;
+    assert_positive(ckmc_buffer_new, pubKey->raw_key, pubKey->key_size, &pubBuffer);
+    ckmc_key_free(pubKey);
+
+    return create_raw_buffer(pubBuffer);
+}
+
+ParamListPtr getDefaultECDHParams(const std::string& pubAlias)
+{
+    auto ecdhParams = createParamListPtr();
+    setParam(ecdhParams, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_ECDH);
+    auto pubKey = getPublicKey(pubAlias);
+    setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, pubKey.get());
+    return ecdhParams;
+}
+
+void deriveEcdh(const std::string& prvAlias,
+                const std::string& prvPass,
+                const std::string& pubAlias,
+                const std::string& derivedAlias,
+                const ckmc_policy_s& derivedPolicy,
+                int expected)
+{
+    auto ecdhParams = getDefaultECDHParams(pubAlias);
+
+    assert_result(expected,
+                  ckmc_key_derive,
+                  ecdhParams.get(),
+                  prvAlias.c_str(),
+                  prvPass.c_str(),
+                  derivedAlias.c_str(),
+                  derivedPolicy);
+}
+
+RawBufferPtr deriveEcdhAndGet(const std::string& prvAlias,
+                              const std::string& prvPass,
+                              const std::string& pubAlias,
+                              const std::string& derivedAlias,
+                              const ckmc_policy_s& derivedPolicy)
+{
+    deriveEcdh(prvAlias, prvPass, pubAlias, derivedAlias, derivedPolicy, CKMC_ERROR_NONE);
+
+    ckmc_raw_buffer_s *derivedBuffer = nullptr;
+    assert_positive(ckmc_get_data, derivedAlias.c_str(), derivedPolicy.password, &derivedBuffer);
+
+    ckmc_remove_alias(derivedAlias.c_str());
+
+    return create_raw_buffer(derivedBuffer);
+}
+
+void invalidDerive(const ParamListPtr& params)
+{
+    assert_invalid_param(ckmc_key_derive,
+                         params.get(),
+                         OURS.prv.c_str(),
+                         "",
+                         DERIVED.c_str(),
+                         EXPORTABLE);
+}
+
+
+class KbkdfParamTester {
+public:
+    void Ok(const uint64_t* len,
+            const ckmc_kdf_prf_e* prf,
+            const ckmc_kbkdf_mode_e* mode,
+            const ckmc_kbkdf_counter_location_e* location,
+            const RawBufferPtr context,
+            const RawBufferPtr label,
+            const RawBufferPtr fixed,
+            const uint64_t* rlen,
+            const uint64_t* llen,
+            bool noSeparator = false)
+    {
+        return Test(true, len, prf, mode, location, context, label, fixed, rlen, llen, noSeparator);
+    }
+
+    void Fail(const uint64_t* len,
+              const ckmc_kdf_prf_e* prf,
+              const ckmc_kbkdf_mode_e* mode,
+              const ckmc_kbkdf_counter_location_e* location,
+              const RawBufferPtr context,
+              const RawBufferPtr label,
+              const RawBufferPtr fixed,
+              const uint64_t* rlen,
+              const uint64_t* llen,
+              bool noSeparator = false)
+    {
+        return Test(
+            false, len, prf, mode, location, context, label, fixed, rlen, llen, noSeparator);
+    }
+private:
+    void Test(bool ok,
+              const uint64_t* len,
+              const ckmc_kdf_prf_e* prf,
+              const ckmc_kbkdf_mode_e* mode,
+              const ckmc_kbkdf_counter_location_e* location,
+              const RawBufferPtr context,
+              const RawBufferPtr label,
+              const RawBufferPtr fixed,
+              const uint64_t* rlen,
+              const uint64_t* llen,
+              bool noSeparator = false)
+    {
+        auto derive = createParamListPtr();
+        setParam(derive, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_KBKDF);
+        if (len)
+            setParam(derive, CKMC_PARAM_KDF_LEN, *len);
+        if (prf)
+            setParam(derive, CKMC_PARAM_KDF_PRF, *prf);
+        if (mode)
+            setParam(derive, CKMC_PARAM_KBKDF_MODE, *mode);
+        if (location)
+            setParam(derive, CKMC_PARAM_KBKDF_COUNTER_LOCATION, *location);
+        if (context)
+            setParam(derive, CKMC_PARAM_KBKDF_CONTEXT, context.get());
+        if (label)
+            setParam(derive, CKMC_PARAM_KBKDF_LABEL, label.get());
+        if (fixed)
+            setParam(derive, CKMC_PARAM_KBKDF_FIXED_INPUT, fixed.get());
+        if (rlen)
+            setParam(derive, CKMC_PARAM_KBKDF_RLEN, *rlen);
+        if (llen)
+            setParam(derive, CKMC_PARAM_KBKDF_LLEN, *llen);
+        if (noSeparator)
+            setParam(derive, CKMC_PARAM_KBKDF_NO_SEPARATOR, 1);
+
+        if (ok) {
+            assert_positive(ckmc_key_derive,
+                            derive.get(),
+                            SECRET.c_str(),
+                            "",
+                            DERIVED.c_str(),
+                            EXPORTABLE);
+
+            ckmc_key_s *derived = nullptr;
+            assert_positive(ckmc_get_key, DERIVED.c_str(), "", &derived);
+            size_t derived_size = derived->key_size;
+            ckmc_key_free(derived);
+
+            RUNNER_ASSERT(derived_size == *len);
+
+            assert_positive(ckmc_remove_alias, DERIVED.c_str());
+        } else {
+            assert_result(CKMC_ERROR_INVALID_PARAMETER,
+                          ckmc_key_derive,
+                          derive.get(),
+                          SECRET.c_str(),
+                          "",
+                          DERIVED.c_str(),
+                          EXPORTABLE);
+        }
+    }
+};
+
+ParamListPtr getDefaultKBKDFParams()
+{
+    auto kbkdfParams = createParamListPtr();
+    setParam(kbkdfParams, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_KBKDF);
+    setParam(kbkdfParams, CKMC_PARAM_KDF_LEN, 32);
+    setParam(kbkdfParams, CKMC_PARAM_KDF_PRF, CKMC_KDF_PRF_HMAC_SHA256);
+    setParam(kbkdfParams, CKMC_PARAM_KBKDF_MODE, CKMC_KBKDF_MODE_COUNTER);
+    setParam(kbkdfParams, CKMC_PARAM_KBKDF_LABEL, LAB.get());
+    setParam(kbkdfParams, CKMC_PARAM_KBKDF_CONTEXT, CTX.get());
+    setParam(kbkdfParams, CKMC_PARAM_KBKDF_COUNTER_LOCATION, CKMC_KBKDF_COUNTER_BEFORE_FIXED);
+    return kbkdfParams;
+}
+
+} // namespace anonymous
+
+RUNNER_TEST_GROUP_INIT_ENV(CKM_DERIVE_ECDH, EcdhGroupFixture);
+
+RUNNER_TEST(TECDH_0010_positive, DerivedFixture)
+{
+    auto ourDerived = deriveEcdhAndGet(OURS.prv, "", PEERS.pub, DERIVED, EXPORTABLE);
+    auto peerDerived = deriveEcdhAndGet(PEERS.prv, PASSWORD, OURS.pub, DERIVED, EXPORTABLE_PW);
+
+    assert_buffers_equal(ourDerived.get(), peerDerived.get());
+
+    auto wrongDerived = deriveEcdhAndGet(OURS.prv, "", PEERS2.pub, DERIVED, EXPORTABLE);
+
+    assert_buffers_equal(ourDerived.get(), wrongDerived.get(), false);
+}
+
+RUNNER_TEST(TECDH_0020_missing_arguments, DerivedFixture)
+{
+    auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+    assert_invalid_param(ckmc_key_derive,
+                         nullptr,
+                         OURS.prv.c_str(),
+                         "",
+                         DERIVED.c_str(),
+                         EXPORTABLE);
+
+    assert_invalid_param(ckmc_key_derive,
+                         ecdhParams.get(),
+                         nullptr,
+                         "",
+                         DERIVED.c_str(),
+                         EXPORTABLE);
+
+    assert_invalid_param(ckmc_key_derive,
+                         ecdhParams.get(),
+                         OURS.prv.c_str(),
+                         "",
+                         nullptr,
+                         EXPORTABLE);
+}
+
+RUNNER_TEST(TECDH_0030_unknown_alias, DerivedFixture)
+{
+    auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+    assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                  ckmc_key_derive,
+                  ecdhParams.get(),
+                  "nonexistent-alias",
+                  "",
+                  DERIVED.c_str(),
+                  EXPORTABLE);
+}
+
+RUNNER_TEST(TECDH_0040_alias_exists, DerivedFixture)
+{
+    auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+    assert_positive(ckmc_key_derive,
+                    ecdhParams.get(),
+                    OURS.prv.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    EXPORTABLE);
+
+    assert_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+                  ckmc_key_derive,
+                  ecdhParams.get(),
+                  OURS.prv.c_str(),
+                  "",
+                  DERIVED.c_str(),
+                  EXPORTABLE);
+}
+
+RUNNER_TEST(TECDH_0050_derived_password, DerivedFixture)
+{
+    auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+    assert_positive(ckmc_key_derive,
+                    ecdhParams.get(),
+                    OURS.prv.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    EXPORTABLE_PW);
+
+    ckmc_raw_buffer_s *derived = nullptr;
+    assert_result(CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), "", &derived);
+    assert_result(CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), "pw", &derived);
+
+    assert_positive(ckmc_remove_alias, DERIVED.c_str());
+
+    assert_positive(ckmc_key_derive,
+                    ecdhParams.get(),
+                    OURS.prv.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    EXPORTABLE);
+
+    assert_result(CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), "pw", &derived);
+    assert_result(
+            CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_data, DERIVED.c_str(), PASSWORD, &derived);
+}
+
+RUNNER_TEST(TECDH_0050_derived_unexportable, DerivedFixture)
+{
+    auto ecdhParams = getDefaultECDHParams(PEERS.pub);
+
+    assert_positive(ckmc_key_derive,
+                    ecdhParams.get(),
+                    OURS.prv.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    UNEXPORTABLE);
+
+    ckmc_raw_buffer_s *derived = nullptr;
+    assert_result(CKMC_ERROR_NOT_EXPORTABLE, ckmc_get_data, DERIVED.c_str(), "", &derived);
+}
+
+RUNNER_TEST(TECDH_0100_wrong_parameters, DerivedFixture)
+{
+    auto ecdhParams = createParamListPtr();
+
+    // no algo
+    invalidDerive(ecdhParams);
+
+    // no pubkey
+    setParam(ecdhParams, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_ECDH);
+    invalidDerive(ecdhParams);
+
+    // garbage pubkey
+    ckmc_raw_buffer_s* garbage = createRandomBufferCAPI(1);
+    auto buffer = create_raw_buffer(garbage);
+    setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, buffer.get());
+    invalidDerive(ecdhParams);
+
+    // private key instead of pubkey
+    buffer = getPublicKey(PEERS2.prv);
+    setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, buffer.get());
+    invalidDerive(ecdhParams);
+
+    // wrong algo
+    buffer = getPublicKey(OURS.pub);
+    setParam(ecdhParams, CKMC_PARAM_ECDH_PUBKEY, buffer.get());
+    setParam(ecdhParams, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_KBKDF);
+    invalidDerive(ecdhParams);
+}
+
+RUNNER_TEST(TECDH_0200_wrong_password, DerivedFixture)
+{
+    deriveEcdh(PEERS.prv, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_AUTHENTICATION_FAILED);
+    deriveEcdh(OURS.prv,
+               UNEXPORTABLE_PW.password,
+               PEERS.pub,
+               DERIVED,
+               UNEXPORTABLE,
+               CKMC_ERROR_AUTHENTICATION_FAILED);
+}
+
+RUNNER_TEST(TECDH_0210_different_curves, DerivedFixture)
+{
+    deriveEcdh(OURS.prv, "", WRONG.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+    deriveEcdh(WRONG.prv, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}
+
+RUNNER_TEST(TECDH_0220_different_key_types, DerivedFixture)
+{
+    deriveEcdh(OURS.prv, "", RSA.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+    deriveEcdh(RSA.prv, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}
+
+RUNNER_TEST(TECDH_0230_public_instead_of_private, DerivedFixture)
+{
+    deriveEcdh(OURS.pub, "", OURS.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}
+
+RUNNER_TEST(TECDH_0230_wrong_key_types, DerivedFixture)
+{
+    deriveEcdh(RSA.prv, "", RSA.pub, DERIVED, UNEXPORTABLE, CKMC_ERROR_INVALID_PARAMETER);
+}
+
+
+class KbkdfGroupFixture: public DPL::Test::TestGroup
+{
+public:
+    void Init() override
+    {
+        remove_user_data(UID);
+        assert_positive(ckmc_unlock_user_key, UID, "db-pass");
+
+        ckmc_raw_buffer_s* secret = createRandomBufferCAPI(12);
+
+        assert_positive(ckmc_save_data, SECRET.c_str(), *secret, UNEXPORTABLE);
+    }
+
+    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);
+    }
+};
+
+RUNNER_TEST_GROUP_INIT_ENV(CKM_DERIVE_KBKDF, KbkdfGroupFixture);
+
+RUNNER_TEST(TKBKDF_0010_positive, DerivedFixture)
+{
+    KbkdfParamTester test;
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+
+    test.Ok(&U16, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Ok(&U24, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+
+    test.Ok(&U32, &HMAC384, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Ok(&U32, &HMAC512, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &AFTER,  CTX, LAB, nullptr, nullptr, nullptr);
+    test.Ok(&U32, &HMAC256, &COUNTER, &MIDDLE, CTX, LAB, nullptr, nullptr, nullptr);
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, ONE, LAB, nullptr, nullptr, nullptr);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, ONE, nullptr, nullptr, nullptr);
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, nullptr, nullptr, FIX, nullptr, nullptr);
+    test.Ok(&U32, &HMAC256, &COUNTER, &AFTER,  nullptr, nullptr, FIX, nullptr, nullptr);
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, nullptr, nullptr, ONE, nullptr, nullptr);
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U32, nullptr);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U24, nullptr);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U16, nullptr);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U8,  nullptr);
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U32);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U24);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U16);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U8);
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U0);
+
+    test.Ok(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr, true);
+    test.Ok(&U32, &HMAC256, &COUNTER, &MIDDLE, CTX, LAB, nullptr, nullptr, nullptr, true);
+}
+
+RUNNER_TEST(TKBKDF_0020_derive_from_derived, DerivedFixture)
+{
+    auto kbkdfParams = getDefaultKBKDFParams();
+    assert_positive(ckmc_key_derive,
+                    kbkdfParams.get(),
+                    SECRET.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    UNEXPORTABLE);
+
+    assert_positive(ckmc_key_derive,
+                    kbkdfParams.get(),
+                    DERIVED.c_str(),
+                    "",
+                    "derived2",
+                    EXPORTABLE);
+
+    ckmc_key_s *derived2 = nullptr;
+    assert_positive(ckmc_get_key, "derived2", "", &derived2);
+    ckmc_key_free(derived2);
+}
+
+RUNNER_TEST(TKBKDF_0030_unknown_alias, DerivedFixture)
+{
+    auto kbkdfParams = getDefaultKBKDFParams();
+    assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                  ckmc_key_derive,
+                  kbkdfParams.get(),
+                  "nonexistent-alias",
+                  "",
+                  DERIVED.c_str(),
+                  EXPORTABLE);
+}
+
+RUNNER_TEST(TKBKDF_0040_wrong_password, DerivedFixture)
+{
+    auto kbkdfParams = getDefaultKBKDFParams();
+    assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                  ckmc_key_derive,
+                  kbkdfParams.get(),
+                  SECRET.c_str(),
+                  "wrong-password",
+                  DERIVED.c_str(),
+                  EXPORTABLE);
+}
+
+RUNNER_TEST(TKBKDF_0050_alias_exists, DerivedFixture)
+{
+    auto kbkdfParams = getDefaultKBKDFParams();
+    assert_positive(ckmc_key_derive,
+                    kbkdfParams.get(),
+                    SECRET.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    EXPORTABLE);
+
+    assert_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+                  ckmc_key_derive,
+                  kbkdfParams.get(),
+                  SECRET.c_str(),
+                  "",
+                  DERIVED.c_str(),
+                  EXPORTABLE);
+}
+
+RUNNER_TEST(TKBKDF_0060_derived_password, DerivedFixture)
+{
+    auto kbkdfParams = getDefaultKBKDFParams();
+    assert_positive(ckmc_key_derive,
+                    kbkdfParams.get(),
+                    SECRET.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    EXPORTABLE);
+
+    ckmc_key_s *derived = nullptr;
+    assert_result(
+            CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_key, DERIVED.c_str(), PASSWORD, &derived);
+
+    assert_positive(ckmc_remove_alias, DERIVED.c_str());
+
+    assert_positive(ckmc_key_derive,
+                    kbkdfParams.get(),
+                    SECRET.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    EXPORTABLE_PW);
+
+    assert_result(
+            CKMC_ERROR_AUTHENTICATION_FAILED, ckmc_get_key, DERIVED.c_str(), "", &derived);
+    assert_positive(ckmc_get_key, DERIVED.c_str(), PASSWORD, &derived);
+    ckmc_key_free(derived);
+}
+
+RUNNER_TEST(TKBKDF_0070_unexportable, DerivedFixture)
+{
+    auto kbkdfParams = getDefaultKBKDFParams();
+    assert_positive(ckmc_key_derive,
+                    kbkdfParams.get(),
+                    SECRET.c_str(),
+                    "",
+                    DERIVED.c_str(),
+                    UNEXPORTABLE);
+
+    ckmc_key_s *derived = nullptr;
+    assert_result(CKMC_ERROR_NOT_EXPORTABLE, ckmc_get_key, DERIVED.c_str(), "", &derived);
+}
+
+RUNNER_TEST(TKBKDF_0100_wrong_params, DerivedFixture)
+{
+    KbkdfParamTester test;
+
+    // missing parameters
+    test.Fail(nullptr, &HMAC256, &COUNTER, &BEFORE, CTX,     LAB,     nullptr, nullptr, nullptr);
+    test.Fail(&U32,    nullptr,  &COUNTER, &BEFORE, CTX,     LAB,     nullptr, nullptr, nullptr);
+    test.Fail(&U32,    &HMAC256, nullptr,  &BEFORE, CTX,     LAB,     nullptr, nullptr, nullptr);
+    test.Fail(&U32,    &HMAC256, &COUNTER, nullptr, CTX,     LAB,     nullptr, nullptr, nullptr);
+    test.Fail(&U32,    &HMAC256, &COUNTER, &BEFORE, nullptr, LAB,     nullptr, nullptr, nullptr);
+    test.Fail(&U32,    &HMAC256, &COUNTER, &BEFORE, CTX,     nullptr, nullptr, nullptr, nullptr);
+
+    // conflicting parameters
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX,     LAB,     FIX, nullptr, nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, nullptr, LAB,     FIX, nullptr, nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX,     nullptr, FIX, nullptr, nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &MIDDLE, nullptr, nullptr, FIX, nullptr, nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &MIDDLE, nullptr, nullptr, FIX, nullptr, &U32);
+    test.Fail(&U32, &HMAC256, &COUNTER, &MIDDLE, nullptr, nullptr, FIX, nullptr, &U0);
+    test.Fail(&U32, &HMAC256, &COUNTER, &MIDDLE, nullptr, nullptr, FIX, nullptr, nullptr, true);
+
+    // invalid values
+    test.Fail(&U0,  &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Fail(&U1,  &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Fail(&U8,  &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Fail(&U64, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+
+    auto wrongPrf1 = static_cast<ckmc_kdf_prf_e>(0);
+    auto wrongPrf2 = static_cast<ckmc_kdf_prf_e>(4);
+    test.Fail(&U32, &wrongPrf1, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Fail(&U32, &wrongPrf2, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+
+    auto wrongMode1 = static_cast<ckmc_kbkdf_mode_e>(0);
+    auto wrongMode2 = static_cast<ckmc_kbkdf_mode_e>(2);
+    test.Fail(&U32, &HMAC256, &wrongMode1, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Fail(&U32, &HMAC256, &wrongMode2, &BEFORE, CTX, LAB, nullptr, nullptr, nullptr);
+
+    auto wrongLocation1 = static_cast<ckmc_kbkdf_counter_location_e>(0);
+    auto wrongLocation2 = static_cast<ckmc_kbkdf_counter_location_e>(4);
+    test.Fail(&U32, &HMAC256, &COUNTER, &wrongLocation1, CTX, LAB, nullptr, nullptr, nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &wrongLocation2, CTX, LAB, nullptr, nullptr, nullptr);
+
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U0,  nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U1,  nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U7,  nullptr);
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, &U64, nullptr);
+
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U1);
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U7);
+    test.Fail(&U32, &HMAC256, &COUNTER, &BEFORE, CTX, LAB, nullptr, nullptr, &U64);
+}
diff --git a/src/ckm/unprivileged/key-wrapping.cpp b/src/ckm/unprivileged/key-wrapping.cpp
new file mode 100644 (file)
index 0000000..cfb88a0
--- /dev/null
@@ -0,0 +1,1138 @@
+/*
+ *  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 <string>
+
+#include <dpl/test/test_runner.h>
+#include <ckm-common.h>
+#include <ckmc/ckmc-manager.h>
+#include <ckmc/ckmc-control.h>
+
+using namespace CKM;
+namespace {
+
+const uid_t UID = 5001;
+ckmc_raw_buffer_s* DEFAULT_IV = nullptr;
+
+const Alias AES_KEY_128_ALIAS = "AES-gen-test-128";
+const Alias AES_KEY_192_ALIAS = "AES-gen-test-192";
+const Alias AES_KEY_256_ALIAS = "AES-gen-test-256";
+const Alias AES_KEY_128_PASS_ALIAS = "AES-gen-test-128-pass";
+const Alias AES_KEY_UNEXP_PASS_ALIAS = "AES-gen-test-128-unexp-pass";
+const Alias AES_KEY_UNEXP_ALIAS = "AES-gen-test-128-unexp";
+const Alias RSA_KEY_1024_PRV_ALIAS = "RSA-gen-test-1024-prv";
+const Alias RSA_KEY_1024_PUB_ALIAS = "RSA-gen-test-1024-pub";
+const Alias RSA_KEY_2048_PRV_ALIAS = "RSA-gen-test-2048-prv";
+const Alias RSA_KEY_2048_PUB_ALIAS = "RSA-gen-test-2048-pub";
+const Alias RSA_KEY_4096_PRV_ALIAS = "RSA-gen-test-4096-prv";
+const Alias RSA_KEY_4096_PUB_ALIAS = "RSA-gen-test-4096-pub";
+
+const Alias IMP_AES_CTR = "imp-AES-CTR";
+const Alias IMP_AES_CTR_PASS = "imp-AES-CTR-p";
+const Alias IMPORTED_ALIAS = "imported-key-1";
+
+const char* KEY_PASSWORD = "test-pass-1";
+const ckmc_policy_s EXPORTABLE = {nullptr, 1};
+const ckmc_policy_s EXPORTABLE_PASS = {const_cast<char*>(KEY_PASSWORD), 1};
+const ckmc_policy_s UNEXPORTABLE = {nullptr, 0};
+const ckmc_policy_s UNEXPORTABLE_PASS = {const_cast<char*>(KEY_PASSWORD), 0};
+
+struct Algo {
+       ckmc_algo_type_e type;
+       size_t initVector;
+};
+const Algo AES_CTR_ALGO = {CKMC_ALGO_AES_CTR, 16};
+const Algo AES_CBC_ALGO = {CKMC_ALGO_AES_CBC, 16};
+const Algo AES_GCM_ALGO = {CKMC_ALGO_AES_GCM, 16};
+const Algo AES_CFB_ALGO = {CKMC_ALGO_AES_CFB, 16};
+const Algo RSA_OAEP_ALGO = {CKMC_ALGO_RSA_OAEP, 0};
+
+void importKey(const Algo &algo,
+               int buffLen,
+               const Alias &wrappingKeyAlias,
+               const char* wrappingKeyPass,
+               const Alias &importedKeyAlias,
+               const ckmc_policy_s &importedKeyPolicy);
+
+class GroupFixture: public DPL::Test::TestGroup{
+public:
+       void Init() override {
+               remove_user_data(UID);
+               int ret = ckmc_unlock_user_key(UID,"db-pass");
+               if (ret != CKMC_ERROR_NONE)
+                       RUNNER_ERROR_MSG("DB unlock failed: " <<CKMCErrorToString(ret));
+
+               assert_positive(ckmc_create_key_pair_rsa,
+                               1024,
+                               RSA_KEY_1024_PRV_ALIAS.c_str(),
+                               RSA_KEY_1024_PUB_ALIAS.c_str(),
+                               EXPORTABLE,
+                               EXPORTABLE);
+
+               assert_positive(ckmc_create_key_pair_rsa,
+                               2048,
+                               RSA_KEY_2048_PRV_ALIAS.c_str(),
+                               RSA_KEY_2048_PUB_ALIAS.c_str(),
+                               EXPORTABLE,
+                               EXPORTABLE);
+
+               assert_positive(ckmc_create_key_pair_rsa,
+                               4096,
+                               RSA_KEY_4096_PRV_ALIAS.c_str(),
+                               RSA_KEY_4096_PUB_ALIAS.c_str(),
+                               EXPORTABLE,
+                               EXPORTABLE);
+
+               assert_positive(ckmc_create_key_aes, 128, AES_KEY_128_ALIAS.c_str(), EXPORTABLE);
+               assert_positive(ckmc_create_key_aes, 192, AES_KEY_192_ALIAS.c_str(), EXPORTABLE);
+               assert_positive(ckmc_create_key_aes, 256, AES_KEY_256_ALIAS.c_str(), EXPORTABLE);
+               assert_positive(ckmc_create_key_aes, 128, AES_KEY_128_PASS_ALIAS.c_str(), EXPORTABLE_PASS);
+               assert_positive(ckmc_create_key_aes, 128, AES_KEY_UNEXP_ALIAS.c_str(), UNEXPORTABLE);
+               assert_positive(ckmc_create_key_aes, 128, AES_KEY_UNEXP_PASS_ALIAS.c_str(), UNEXPORTABLE_PASS);
+
+               importKey(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, IMP_AES_CTR, EXPORTABLE);
+               importKey(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, IMP_AES_CTR_PASS, EXPORTABLE_PASS);
+       }
+       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);
+               ckmc_buffer_free(DEFAULT_IV);
+
+               ckmc_remove_key(RSA_KEY_1024_PRV_ALIAS.c_str());
+               ckmc_remove_key(RSA_KEY_1024_PUB_ALIAS.c_str());
+               ckmc_remove_key(RSA_KEY_2048_PRV_ALIAS.c_str());
+               ckmc_remove_key(RSA_KEY_2048_PUB_ALIAS.c_str());
+               ckmc_remove_key(RSA_KEY_4096_PRV_ALIAS.c_str());
+               ckmc_remove_key(RSA_KEY_4096_PUB_ALIAS.c_str());
+               ckmc_remove_key(AES_KEY_128_ALIAS.c_str());
+               ckmc_remove_key(AES_KEY_192_ALIAS.c_str());
+               ckmc_remove_key(AES_KEY_256_ALIAS.c_str());
+               ckmc_remove_key(AES_KEY_128_PASS_ALIAS.c_str());
+               ckmc_remove_key(AES_KEY_UNEXP_ALIAS.c_str());
+               ckmc_remove_key(AES_KEY_UNEXP_PASS_ALIAS.c_str());
+
+               ckmc_remove_key(IMP_AES_CTR.c_str());
+               ckmc_remove_key(IMP_AES_CTR_PASS.c_str());
+       }
+};
+
+ParamListPtr getDefaultParams(const Algo &algo){
+       ckmc_param_list_h handle = nullptr;
+
+       assert_positive(ckmc_generate_new_params, algo.type, &handle);
+       ParamListPtr params = ParamListPtr(handle, ckmc_param_list_free);
+       if(algo.type == CKMC_ALGO_RSA_OAEP)
+               return params;
+
+       DEFAULT_IV = createRandomBufferCAPI(algo.initVector);
+       setParam(params, CKMC_PARAM_ED_IV, DEFAULT_IV);
+       return params;
+}
+
+RawBufferPtr encryptAndImport(const ParamListPtr &params,
+                       int buffLen,
+                       const Alias &wrappingKeyAlias,
+                       const char* wrappingKeyPass,
+                       const Alias &importedKeyAlias,
+                       const ckmc_policy_s &importedKeyPolicy){
+       RawBufferPtr plainData = create_raw_buffer(createRandomBufferCAPI(buffLen));
+
+       ckmc_raw_buffer_s *encrypted = nullptr;
+       ckmc_key_s *aesKey = nullptr;
+
+       assert_positive(ckmc_encrypt_data,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               wrappingKeyPass,
+                               *plainData.get(),
+                               &encrypted);
+
+       assert_positive(ckmc_key_new,
+                               encrypted->data,
+                               encrypted->size,
+                               CKMC_KEY_AES,
+                               nullptr,
+                               &aesKey);
+
+       assert_positive(ckmc_import_wrapped_key,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               wrappingKeyPass,
+                               importedKeyAlias.c_str(),
+                               aesKey,
+                               importedKeyPolicy);
+
+       ckmc_buffer_free(encrypted);
+       ckmc_key_free(aesKey);
+       return plainData;
+}
+void testInvalidAlgoParameters(const ParamListPtr &invalidParams, const Algo &algo){
+       ParamListPtr params = getDefaultParams(algo);
+       RawBufferPtr plainData = create_raw_buffer(createRandomBufferCAPI(32));
+
+       ckmc_raw_buffer_s *encrypted = nullptr;
+       ckmc_key_s *aesKey = nullptr;
+
+       assert_positive(ckmc_encrypt_data,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               *plainData.get(),
+                               &encrypted);
+
+       assert_positive(ckmc_key_new,
+                               encrypted->data,
+                               encrypted->size,
+                               CKMC_KEY_AES,
+                               nullptr,
+                               &aesKey);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               invalidParams.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               EXPORTABLE);
+
+       ckmc_buffer_free(encrypted);
+       ckmc_key_free(aesKey);
+}
+void testImportInvalidBuffLen(const Algo &algo,
+                       int buffLen,
+                       const Alias &wrappingKeyAlias){
+       RawBufferPtr plainData = create_raw_buffer(createRandomBufferCAPI(buffLen));
+
+       ckmc_raw_buffer_s *encrypted = nullptr;
+       ckmc_key_s *aesKey = nullptr;
+
+       ParamListPtr params = getDefaultParams(algo);
+
+       assert_positive(ckmc_encrypt_data,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               nullptr,
+                               *plainData.get(),
+                               &encrypted);
+
+       assert_positive(ckmc_key_new,
+                               encrypted->data,
+                               encrypted->size,
+                               CKMC_KEY_AES,
+                               nullptr,
+                               &aesKey);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               EXPORTABLE);
+       ckmc_buffer_free(encrypted);
+       ckmc_key_free(aesKey);
+}
+
+void testImportValidArgs(const Algo &algo, int buffLen, const Alias &wrappingKeyAlias){
+       ckmc_key_s *ppkey = nullptr;
+       ckmc_raw_buffer_s *finalData = nullptr;
+
+       ParamListPtr params = getDefaultParams(algo);
+
+       RawBufferPtr plainData = encryptAndImport(params,
+                               buffLen,
+                               wrappingKeyAlias,
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               EXPORTABLE);
+
+       assert_positive(ckmc_get_key, IMPORTED_ALIAS.c_str(), nullptr, &ppkey);
+       assert_positive(ckmc_buffer_new, ppkey->raw_key, ppkey->key_size, &finalData);
+       assert_buffers_equal(plainData.get(), finalData);
+
+       ckmc_buffer_free(finalData);
+       ckmc_key_free(ppkey);
+       ckmc_remove_key(IMPORTED_ALIAS.c_str());
+}
+
+void testBadWrappedKey(const Algo &algo){
+       ParamListPtr params = getDefaultParams(algo);
+       ckmc_key_s *wrongKey = generate_AES_key(128, nullptr);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               wrongKey,
+                               EXPORTABLE);
+
+       ckmc_key_free(wrongKey);
+}
+
+void testExportableImported(const Algo &algo,
+                       int buffLen,
+                       const Alias &wrappingKeyAlias,
+                       const char* wrappingKeyPass,
+                       const ckmc_policy_s &importedKeyPolicy,
+                       const char* importedKeyPass){
+       ckmc_key_s *ppkey = nullptr;
+       ckmc_raw_buffer_s* finalData = nullptr;
+
+       ParamListPtr params = getDefaultParams(algo);
+
+       RawBufferPtr plainData = encryptAndImport(params,
+                               buffLen,
+                               wrappingKeyAlias,
+                               wrappingKeyPass,
+                               IMPORTED_ALIAS.c_str(),
+                               importedKeyPolicy);
+
+       assert_positive(ckmc_get_key,
+                               IMPORTED_ALIAS.c_str(),
+                               importedKeyPass,
+                               &ppkey);
+
+       assert_positive(ckmc_buffer_new,
+                               ppkey->raw_key,
+                               ppkey->key_size,
+                               &finalData);
+
+       assert_buffers_equal(plainData.get(), finalData);
+
+       ckmc_buffer_free(finalData);
+       ckmc_key_free(ppkey);
+       ckmc_remove_key(IMPORTED_ALIAS.c_str());
+}
+
+void testUnEXPORTABLEImported(const Algo &algo,
+                       int buffLen,
+                       const Alias &wrappingKeyAlias,
+                       const char* wrappingKeyPass,
+                       const ckmc_policy_s &importedKeyPolicy,
+                       const char* importedKeyPass){
+       ckmc_key_s *ppkey = nullptr;
+       ParamListPtr params = getDefaultParams(algo);
+
+       RawBufferPtr plainData = encryptAndImport(params,
+                               buffLen,
+                               wrappingKeyAlias,
+                               wrappingKeyPass,
+                               IMPORTED_ALIAS.c_str(),
+                               importedKeyPolicy);
+
+       assert_result(CKMC_ERROR_NOT_EXPORTABLE,
+                               ckmc_get_key,
+                               IMPORTED_ALIAS.c_str(),
+                               importedKeyPass,
+                               &ppkey);
+       ckmc_key_free(ppkey);
+       ckmc_remove_key(IMPORTED_ALIAS.c_str());
+}
+
+void importKey(const Algo &algo,
+                       int buffLen,
+                       const Alias &wrappingKeyAlias,
+                       const char* wrappingKeyPass,
+                       const Alias &importedKeyAlias,
+                       const ckmc_policy_s &importedKeyPolicy){
+       RawBufferPtr plainData = create_raw_buffer(createRandomBufferCAPI(buffLen));
+
+       ckmc_key_s *aesKey = nullptr;
+       ckmc_raw_buffer_s* encrypted = nullptr;
+
+       ParamListPtr params = getDefaultParams(algo);
+
+       assert_positive(ckmc_encrypt_data,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               wrappingKeyPass,
+                               *plainData.get(),
+                               &encrypted);
+
+       assert_positive(ckmc_key_new,
+                               encrypted->data,
+                               encrypted->size,
+                               CKMC_KEY_AES,
+                               nullptr,
+                               &aesKey);
+
+       assert_positive(ckmc_import_wrapped_key,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               wrappingKeyPass,
+                               importedKeyAlias.c_str(),
+                               aesKey,
+                               importedKeyPolicy);
+
+       ckmc_buffer_free(encrypted);
+       ckmc_key_free(aesKey);
+}
+
+void testImportExportValidArgs(const Algo &algo,
+                       int buffLen,
+                       const Alias &wrappingKeyAlias,
+                       const char* wrappingKeyPass,
+                       const ckmc_policy_s &importedKeyPolicy,
+                       const char* importedKeyPass){
+       ckmc_key_s *ppkey = nullptr;
+       ckmc_raw_buffer_s* finalData = nullptr;
+       ckmc_raw_buffer_s* decrypted = nullptr;
+
+       ParamListPtr params = getDefaultParams(algo);
+
+       RawBufferPtr plainData = encryptAndImport(params,
+                               buffLen,
+                               wrappingKeyAlias.c_str(),
+                               wrappingKeyPass,
+                               IMPORTED_ALIAS,
+                               importedKeyPolicy);
+
+       assert_positive(ckmc_export_wrapped_key,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               wrappingKeyPass,
+                               IMPORTED_ALIAS.c_str(),
+                               importedKeyPass,
+                               &ppkey);
+
+       assert_positive(ckmc_buffer_new,
+                               ppkey->raw_key,
+                               ppkey->key_size,
+                               &finalData);
+
+       assert_positive(ckmc_decrypt_data,
+                               params.get(),
+                               wrappingKeyAlias.c_str(),
+                               wrappingKeyPass,
+                               *finalData,
+                               &decrypted);
+
+       assert_buffers_equal(plainData.get(), decrypted);
+
+       ckmc_buffer_free(finalData);
+       ckmc_buffer_free(decrypted);
+       ckmc_key_free(ppkey);
+       ckmc_remove_key(IMPORTED_ALIAS.c_str());
+}
+
+}      //END OF THE NAMESPACE
+
+RUNNER_TEST_GROUP_INIT_ENV(CKM_KEY_WRAPPING, GroupFixture);
+
+RUNNER_TEST(TKW_NO_ADDED_ALGO){
+       RawBufferPtr plainData = create_raw_buffer(createRandomBufferCAPI(32));
+
+       ckmc_key_s *aesKey = nullptr;
+       ckmc_raw_buffer_s* encrypted = nullptr;
+
+       ParamListPtr params = getDefaultParams(AES_CBC_ALGO);
+
+       ckmc_param_list_h handle = nullptr;
+
+       assert_positive(ckmc_encrypt_data,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               *plainData.get(),
+                               &encrypted);
+
+       assert_positive(ckmc_key_new,
+                               encrypted->data,
+                               encrypted->size,
+                               CKMC_KEY_AES,
+                               nullptr,
+                               &aesKey);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               handle,
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               EXPORTABLE);
+       ckmc_buffer_free(encrypted);
+       ckmc_key_free(aesKey);
+}
+
+RUNNER_TEST(TKW_WRONG_ALGO_PARAMS){
+       ckmc_param_list_h handle = nullptr;
+       assert_positive(ckmc_generate_new_params, AES_CTR_ALGO.type, &handle);
+       ParamListPtr invalidParams = ParamListPtr(handle, ckmc_param_list_free);
+       ckmc_raw_buffer_s *initVec = createRandomBufferCAPI(8);
+       setParam(invalidParams, CKMC_PARAM_ED_IV, initVec);
+
+       testInvalidAlgoParameters(invalidParams, AES_CTR_ALGO);
+
+       ckmc_buffer_free(initVec);
+       invalidParams.reset();
+       assert_positive(ckmc_generate_new_params, AES_GCM_ALGO.type, &handle);
+       invalidParams = ParamListPtr(handle, ckmc_param_list_free);
+       initVec = createRandomBufferCAPI(16);
+       setParam(invalidParams, CKMC_PARAM_ED_IV, initVec);
+       setParam(invalidParams, CKMC_PARAM_ED_TAG_LEN, 130);
+
+       testInvalidAlgoParameters(invalidParams, AES_GCM_ALGO);
+
+       ckmc_buffer_free(initVec);
+}
+
+RUNNER_TEST(TKW_WRONG_PASS_WRAPPING_KEY){
+       int buffLen = 32;
+       RawBufferPtr plainData = create_raw_buffer(createRandomBufferCAPI(buffLen));
+
+       ckmc_key_s *aesKey = nullptr;
+       ckmc_raw_buffer_s* encrypted = nullptr;
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+
+       assert_positive(ckmc_encrypt_data,
+                               params.get(),
+                               AES_KEY_128_PASS_ALIAS.c_str(),
+                               KEY_PASSWORD,
+                               *plainData.get(),
+                               &encrypted);
+
+       assert_positive(ckmc_key_new,
+                               encrypted->data,
+                               encrypted->size,
+                               CKMC_KEY_AES,
+                               nullptr,
+                               &aesKey);
+
+       assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                               ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_PASS_ALIAS.c_str(),
+                               "wrong_password",
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               UNEXPORTABLE);
+
+       assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                               ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_PASS_ALIAS.c_str(),
+                               "",
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               UNEXPORTABLE);
+
+       assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                               ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               "non_empty_password",
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               UNEXPORTABLE);
+
+       ckmc_buffer_free(encrypted);
+       ckmc_key_free(aesKey);
+}
+
+RUNNER_TEST(TKW_UNKNOWN_ALIAS_WRAPPING_KEY){
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+       ckmc_key_s *key = generate_AES_key(128, nullptr);
+
+       assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                               ckmc_import_wrapped_key,
+                               params.get(),
+                               "unknown_alias",
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               key,
+                               EXPORTABLE);
+
+       ckmc_key_free(key);
+}
+
+RUNNER_TEST(TKW_EXISTING_ALIAS_WRAPPING_KEY){
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+       ckmc_key_s *key = generate_AES_key(128, nullptr);
+
+       assert_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+                               ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMP_AES_CTR.c_str(),
+                               key,
+                               EXPORTABLE);
+
+       ckmc_key_free(key);
+}
+
+RUNNER_TEST(TKW_INVALID_ALIAS_IMPORT){
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+       ckmc_key_s *key = generate_AES_key(128, nullptr);
+       Alias invalidAlias = "invalid alias";
+
+       assert_result(CKMC_ERROR_PERMISSION_DENIED,
+                               ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               invalidAlias.c_str(),
+                               key,
+                               EXPORTABLE);
+
+       ckmc_key_free(key);
+}
+
+RUNNER_TEST(TKW_BAD_WRAPPED_KEY){
+       testBadWrappedKey(AES_CBC_ALGO);
+       testBadWrappedKey(AES_GCM_ALGO);
+       testBadWrappedKey(RSA_OAEP_ALGO);
+}
+
+RUNNER_TEST(TKW_NULL_PARAMETER){
+       RawBufferPtr plainData = create_raw_buffer(createRandomBufferCAPI(16));
+
+       ckmc_key_s *aesKey = nullptr;
+       ckmc_raw_buffer_s* encrypted = nullptr;
+
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+
+       assert_positive(ckmc_encrypt_data,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               *plainData.get(),
+                               &encrypted);
+
+       assert_positive(ckmc_key_new,
+                               encrypted->data,
+                               encrypted->size,
+                               CKMC_KEY_AES,
+                               nullptr,
+                               &aesKey);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               nullptr,
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               EXPORTABLE);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               params.get(),
+                               nullptr,
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               aesKey,
+                               EXPORTABLE);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               nullptr,
+                               aesKey,
+                               EXPORTABLE);
+
+       assert_invalid_param(ckmc_import_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMPORTED_ALIAS.c_str(),
+                               nullptr,
+                               EXPORTABLE);
+       ckmc_buffer_free(encrypted);
+       ckmc_key_free(aesKey);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CTR_128){
+       testImportValidArgs(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_CTR_ALGO, 24, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_CTR_ALGO, 32, AES_KEY_128_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CBC_128){
+       testImportValidArgs(AES_CBC_ALGO, 16, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_CBC_ALGO, 24, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_CBC_ALGO, 32, AES_KEY_128_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_GCM_128){
+       testImportValidArgs(AES_GCM_ALGO, 16, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_GCM_ALGO, 24, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_GCM_ALGO, 32, AES_KEY_128_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CFB_128){
+       testImportValidArgs(AES_CFB_ALGO, 16, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_CFB_ALGO, 24, AES_KEY_128_ALIAS);
+       testImportValidArgs(AES_CFB_ALGO, 32, AES_KEY_128_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CTR_192){
+       testImportValidArgs(AES_CTR_ALGO, 16, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_CTR_ALGO, 24, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_CTR_ALGO, 32, AES_KEY_192_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CBC_192){
+       testImportValidArgs(AES_CBC_ALGO, 16, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_CBC_ALGO, 24, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_CBC_ALGO, 32, AES_KEY_192_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_GCM_192){
+       testImportValidArgs(AES_GCM_ALGO, 16, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_GCM_ALGO, 24, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_GCM_ALGO, 32, AES_KEY_192_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CFB_192){
+       testImportValidArgs(AES_CFB_ALGO, 16, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_CFB_ALGO, 24, AES_KEY_192_ALIAS);
+       testImportValidArgs(AES_CFB_ALGO, 32, AES_KEY_192_ALIAS);
+}
+RUNNER_TEST(TKW_VALID_ARGS_AES_CTR_256){
+       testImportValidArgs(AES_CTR_ALGO, 16, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_CTR_ALGO, 24, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_CTR_ALGO, 32, AES_KEY_256_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CBC_256){
+       testImportValidArgs(AES_CBC_ALGO, 16, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_CBC_ALGO, 24, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_CBC_ALGO, 32, AES_KEY_256_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_GCM_256){
+       testImportValidArgs(AES_GCM_ALGO, 16, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_GCM_ALGO, 24, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_GCM_ALGO, 32, AES_KEY_256_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_AES_CFB_256){
+       testImportValidArgs(AES_CFB_ALGO, 16, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_CFB_ALGO, 24, AES_KEY_256_ALIAS);
+       testImportValidArgs(AES_CFB_ALGO, 32, AES_KEY_256_ALIAS);
+}
+
+RUNNER_TEST(TKW_AES_CTR_INVALID_BUFF_LENGTH){
+       testImportInvalidBuffLen(AES_CTR_ALGO, 8, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 12, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 128, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 8, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 12, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 128, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 8, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 12, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_CTR_ALGO, 128, AES_KEY_256_ALIAS);
+}
+
+RUNNER_TEST(TKW_AES_CBC_INVALID_BUFF_LENGTH){
+       testImportInvalidBuffLen(AES_CBC_ALGO, 8, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 12, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 128, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 8, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 12, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 128, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 8, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 12, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_CBC_ALGO, 128, AES_KEY_256_ALIAS);
+}
+RUNNER_TEST(TKW_AES_GCM_INVALID_BUFF_LENGTH){
+       testImportInvalidBuffLen(AES_GCM_ALGO, 8, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 12, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 128, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 8, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 12, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 128, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 8, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 12, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_GCM_ALGO, 128, AES_KEY_256_ALIAS);
+}
+
+RUNNER_TEST(TKW_AES_CFB_INVALID_BUFF_LENGTH){
+       testImportInvalidBuffLen(AES_CFB_ALGO, 8, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 12, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 128, AES_KEY_128_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 8, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 12, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 128, AES_KEY_192_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 8, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 12, AES_KEY_256_ALIAS);
+       testImportInvalidBuffLen(AES_CFB_ALGO, 128, AES_KEY_256_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_RSA_OAEP_1024){
+       testImportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_1024_PRV_ALIAS);
+       testImportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_1024_PRV_ALIAS);
+       testImportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_1024_PRV_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_RSA_OAEP_2048){
+       testImportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_2048_PRV_ALIAS);
+       testImportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_2048_PRV_ALIAS);
+       testImportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_2048_PRV_ALIAS);
+}
+
+RUNNER_TEST(TKW_VALID_ARGS_RSA_OAEP_4096){
+       testImportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_4096_PRV_ALIAS);
+       testImportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_4096_PRV_ALIAS);
+       testImportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_4096_PRV_ALIAS);
+}
+
+RUNNER_TEST(TKW_RSAOAEP_INVALID_BUFF_LENGTH){
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 8, RSA_KEY_1024_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 12, RSA_KEY_1024_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 82, RSA_KEY_1024_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 8, RSA_KEY_2048_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 12, RSA_KEY_2048_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 82, RSA_KEY_2048_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 8, RSA_KEY_4096_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 12, RSA_KEY_4096_PRV_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 82, RSA_KEY_4096_PRV_ALIAS);
+}
+
+RUNNER_TEST(TKW_WRONG_TYPE_WRAPPING_KEY){
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 16, RSA_KEY_1024_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 24, RSA_KEY_1024_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 32, RSA_KEY_1024_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 16, RSA_KEY_2048_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 24, RSA_KEY_2048_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 32, RSA_KEY_2048_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 16, RSA_KEY_4096_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 24, RSA_KEY_4096_PUB_ALIAS);
+       testImportInvalidBuffLen(RSA_OAEP_ALGO, 32, RSA_KEY_4096_PUB_ALIAS);
+}
+
+RUNNER_TEST(TKW_DIF_POLICIES_EXPORTABLE_IMPORTED){
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testExportableImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_DIF_POLICIES_UNEXPORTABLE_IMPORTED){
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, UNEXPORTABLE, nullptr);
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, UNEXPORTABLE, nullptr);
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_ALIAS, nullptr, UNEXPORTABLE, nullptr);
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_PASS_ALIAS, KEY_PASSWORD, UNEXPORTABLE, nullptr);
+
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, UNEXPORTABLE_PASS, KEY_PASSWORD);
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, UNEXPORTABLE_PASS, KEY_PASSWORD);
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_ALIAS, nullptr, UNEXPORTABLE_PASS, KEY_PASSWORD);
+       testUnEXPORTABLEImported(AES_CTR_ALGO, 16, AES_KEY_UNEXP_PASS_ALIAS, KEY_PASSWORD, UNEXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_EXPORT_IMPORTED_KEY){
+       ckmc_key_s *ppkey = nullptr;
+
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+       assert_positive(ckmc_export_wrapped_key,
+                       params.get(),
+                       AES_KEY_128_ALIAS.c_str(),
+                       nullptr,
+                       IMP_AES_CTR.c_str(),
+                       nullptr,
+                       &ppkey);
+
+       ckmc_key_free(ppkey);
+}
+
+RUNNER_TEST(TKW_NO_ADDED_ALGO_EXPORT){
+       ckmc_key_s *ppkey = nullptr;
+       ckmc_param_list_h handle = nullptr;
+
+       assert_invalid_param(ckmc_export_wrapped_key,
+                               handle,
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMP_AES_CTR.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       ckmc_key_free(ppkey);
+}
+
+RUNNER_TEST(TKW_EXPORT_UNKNOWN_WRAPPING_KEY_ALIAS){
+       ckmc_key_s *ppkey = nullptr;
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+
+       assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                               ckmc_export_wrapped_key,
+                               params.get(),
+                               "unknown_alias",
+                               nullptr,
+                               IMP_AES_CTR.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       ckmc_key_free(ppkey);
+}
+
+RUNNER_TEST(TKW_EXPORT_UNKNOWN_IMPORTED_KEY_ALIAS){
+       ckmc_key_s *ppkey = nullptr;
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+       Alias alias = "non_existing_alias";
+
+       assert_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                               ckmc_export_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               alias.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       ckmc_key_free(ppkey);
+}
+
+RUNNER_TEST(TKW_EXPORT_AUTHENTICATION_FAILED){
+       ckmc_key_s *ppkey = nullptr;
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+
+       assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                               ckmc_export_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_PASS_ALIAS.c_str(),
+                               nullptr,
+                               IMP_AES_CTR.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                               ckmc_export_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_PASS_ALIAS.c_str(),
+                               "wrong_password",
+                               IMP_AES_CTR.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                               ckmc_export_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMP_AES_CTR_PASS.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       assert_result(CKMC_ERROR_AUTHENTICATION_FAILED,
+                               ckmc_export_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMP_AES_CTR_PASS.c_str(),
+                               "wrong_password",
+                               &ppkey);
+
+       ckmc_key_free(ppkey);
+}
+
+RUNNER_TEST(TKW_EXPORT_NULL_PARAMETER){
+       ckmc_key_s *ppkey = nullptr;
+       ParamListPtr params = getDefaultParams(AES_CTR_ALGO);
+
+       assert_invalid_param(ckmc_export_wrapped_key,
+                               nullptr,
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMP_AES_CTR.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       assert_invalid_param(ckmc_export_wrapped_key,
+                               params.get(),
+                               nullptr,
+                               nullptr,
+                               IMP_AES_CTR.c_str(),
+                               nullptr,
+                               &ppkey);
+
+       assert_invalid_param(ckmc_export_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               nullptr,
+                               nullptr,
+                               &ppkey);
+
+       assert_invalid_param(ckmc_export_wrapped_key,
+                               params.get(),
+                               AES_KEY_128_ALIAS.c_str(),
+                               nullptr,
+                               IMP_AES_CTR.c_str(),
+                               nullptr,
+                               nullptr);
+
+       ckmc_key_free(ppkey);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_CTR){
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_CTR_PASS){
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_CTR_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CTR_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_CBC){
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_CBC_PASS){
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_CBC_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CBC_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_GCM){
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_GCM_PASS){
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_GCM_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_GCM_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_CFB){
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_128_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_192_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_256_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_AES_CFB_PASS){
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(AES_CFB_ALGO, 16, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 24, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(AES_CFB_ALGO, 32, AES_KEY_128_PASS_ALIAS, KEY_PASSWORD, EXPORTABLE_PASS, KEY_PASSWORD);
+}
+
+RUNNER_TEST(TKW_IMPORT_EXPORT_RSA_OAEP){
+       testImportExportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_1024_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_1024_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_1024_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_2048_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_2048_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_2048_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_4096_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_4096_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_4096_PRV_ALIAS, nullptr, EXPORTABLE, nullptr);
+
+       testImportExportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_1024_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_1024_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_1024_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_2048_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_2048_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_2048_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 16, RSA_KEY_4096_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 24, RSA_KEY_4096_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+       testImportExportValidArgs(RSA_OAEP_ALGO, 32, RSA_KEY_4096_PRV_ALIAS, nullptr, EXPORTABLE_PASS, KEY_PASSWORD);
+}
index 5d939ee..93ccd11 100644 (file)
@@ -13,8 +13,6 @@
  *  See the License for the specific language governing permissions and
  *  limitations under the License
  */
-#include <unistd.h>
-#include <sys/types.h>
 
 #include <fstream>
 #include <iostream>
@@ -38,8 +36,6 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 
-#include <tzplatform_config.h>
-
 namespace {
 const int USER_APP = 5001;
 
@@ -434,7 +430,7 @@ RUNNER_TEST(T1023_app_user_save_keys_exportable_flag)
         CKM_API_ERROR_NOT_EXPORTABLE == (temp = manager->getKey("appkey4", CKM::Password(), key)),
         "Error=" << CKM::APICodeToString(temp));
     RUNNER_ASSERT_MSG(
-        CKM_API_ERROR_INPUT_PARAM == (temp = manager->saveData("data3", buffer, notExportable)),
+        CKM_API_SUCCESS == (temp = manager->saveData("data3", buffer, notExportable)),
         "Error=" << CKM::APICodeToString(temp));
 }
 
@@ -2927,16 +2923,7 @@ RUNNER_TEST(T1905_deinit)
 
 int main(int argc, 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;
-        return -1;
-    }
+    require_default_user(argv);
 
     int exitCode = DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);
 
diff --git a/src/e2ee-adaptation-layer/CMakeLists.txt b/src/e2ee-adaptation-layer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b55fb9c
--- /dev/null
@@ -0,0 +1,64 @@
+# 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.49
+    device-certificate-manager>=2.1
+    openssl1.1
+)
+
+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
+)
diff --git a/src/e2ee-adaptation-layer/e2ee-adaptation-layer.cpp b/src/e2ee-adaptation-layer/e2ee-adaptation-layer.cpp
new file mode 100644 (file)
index 0000000..3e86ae0
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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 <cstring>
+#include <cstdlib>
+
+#include <memory>
+
+#include <openssl/evp.h>
+
+#include <ckmc/ckmc-manager.h>
+#include <device_certificate_manager.h>
+
+namespace {
+
+const char* const LABEL = "label";
+const char* const CONTEXT = "context";
+const char* const SECRET_ALIAS = "temporary_shared_e2ee_secret";
+constexpr size_t ITERATIONS = 1000;
+
+typedef std::unique_ptr<struct __ckmc_param_list, decltype(&ckmc_param_list_free)> ParamsPtr;
+typedef std::unique_ptr<void, decltype(&dcm_free_key_context)> DcmCtxPtr;
+typedef std::unique_ptr<ckmc_raw_buffer_s, decltype(&ckmc_buffer_free)> BufferPtr;
+typedef std::unique_ptr<ckmc_key_s, decltype(&ckmc_key_free)> KeyPtr;
+typedef std::unique_ptr<dcm_e2ee_bundle_s, decltype(&dcm_e2ee_free_bundle)> BundlePtr;
+
+std::tuple<ParamsPtr, int> makeParams()
+{
+    ckmc_param_list_h params = nullptr;
+    int ret = ckmc_param_list_new(&params);
+    return std::make_tuple(ParamsPtr(params, ckmc_param_list_free), ret);
+}
+
+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;
+};
+
+std::tuple<DcmCtxPtr, int> getOcfContext()
+{
+    void* ocf_ctx = nullptr;
+    int ret = dcm_create_key_context(nullptr, nullptr, "ECDSA", &ocf_ctx);
+    return std::make_tuple(DcmCtxPtr(ocf_ctx, dcm_free_key_context), ret);
+}
+
+} // 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,
+                            const unsigned char *salt,
+                            size_t salt_len,
+                            size_t new_key_len,
+                            const char *new_key_alias)
+{
+    if (password == nullptr || salt == nullptr || new_key_alias == nullptr || new_key_len == 0)
+        return CKMC_ERROR_INVALID_PARAMETER;
+
+    unsigned char derived[new_key_len];
+
+    if (1 != PKCS5_PBKDF2_HMAC_SHA1(password,
+                                    strlen(password),
+                                    salt,
+                                    salt_len,
+                                    ITERATIONS,
+                                    new_key_len,
+                                    derived))
+        return CKMC_ERROR_SERVER_ERROR;
+
+    ckmc_key_s* key = nullptr;
+    int ret = ckmc_key_new(derived, new_key_len, CKMC_KEY_AES, nullptr, &key);
+    if (ret != CKMC_ERROR_NONE)
+        return ret;
+
+    ckmc_policy_s unexportable { nullptr, false };
+    ret = ckmc_save_key(new_key_alias, *key, unexportable);
+    ckmc_key_free(key);
+
+    return ret;
+}
+
+int ckmew_get_ocf_cert_chain(char **cert_chain, size_t *cert_chain_len)
+{
+    auto [ocf, ret] = getOcfContext();
+    if (ret != DCM_ERROR_NONE)
+        return ret;
+
+    return dcm_get_certificate_chain(ocf.get(), cert_chain, cert_chain_len);
+}
+
+int ckmew_sign_with_ocf(const char *public_key_alias,
+                        ckmc_raw_buffer_s **message_buf,
+                        ckmc_raw_buffer_s **signature_buf)
+{
+    if (public_key_alias == nullptr || message_buf == nullptr || signature_buf == nullptr)
+        return DCM_ERROR_INVALID_PARAMETER;
+
+    // get ocf context
+    auto [ocf, ret] = getOcfContext();
+    if (ret != DCM_ERROR_NONE)
+        return ret;
+
+    // get device public key
+    ckmc_key_s* device_pub_key = nullptr;
+    ret = ckmc_get_key(public_key_alias, nullptr, &device_pub_key);
+    if (ret != CKMC_ERROR_NONE)
+        return ret; // This is a CKM error!
+
+    KeyPtr device_pub_key_ptr(device_pub_key, ckmc_key_free);
+
+    // pack & sign device public key
+    dcm_e2ee_bundle_h bundle = nullptr;
+    unsigned char* signature = nullptr;
+    size_t signature_len = 0;
+    ret = dcm_e2ee_create_signed_bundle(ocf.get(),
+                                        DCM_DIGEST_SHA256,
+                                        device_pub_key->raw_key,
+                                        device_pub_key->key_size,
+                                        &bundle,
+                                        reinterpret_cast<char**>(&signature),
+                                        &signature_len);
+    if (ret != DCM_ERROR_NONE)
+        return ret;
+
+    BundlePtr bundle_ptr(bundle, dcm_e2ee_free_bundle);
+    auto [signature_ptr, ret2] = makeBuffer(signature, signature_len);
+    if (ret2 != CKMC_ERROR_NONE)
+        return ret2; // This is a CKM error!
+
+    const unsigned char* message = nullptr;
+    size_t message_len = 0;
+    ret = dcm_e2ee_get_bundle_message(bundle, &message, &message_len);
+    if (ret != DCM_ERROR_NONE)
+        return ret;
+
+    ret = ckmc_buffer_new(const_cast<unsigned char*>(message), message_len, message_buf);
+    if (ret != CKMC_ERROR_NONE)
+        return ret; // This is a CKM error!
+
+    *signature_buf = signature_ptr.release();
+
+    return DCM_ERROR_NONE;
+}
diff --git a/src/e2ee-adaptation-layer/e2ee-adaptation-layer.h b/src/e2ee-adaptation-layer/e2ee-adaptation-layer.h
new file mode 100644 (file)
index 0000000..f020951
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <ckmc/ckmc-type.h>
+
+/**
+ * @brief Derives a common symmetric key using ECDH and KBKDF.
+ *
+ * @since_tizen 7.5
+ *
+ * @remarks The derived key will be a symmetric one. It will be stored as a #CKMC_KEY_AES.
+ * @remarks The function first generates a shared secret using ECDH and temporarily stores it in
+ *          key-manager. Then it derives a symmetric key from it, stores it in key-manager too and
+ *          removes the shared secret.
+ * @remarks Shared secret length and KBKDF algorithm parameters are fixed in the code.
+ * @remarks To simplify the API, it is assumed that the private key alias does not use a custom
+ *          password.
+ *
+ * @param[in] private_key_alias Alias of the private key to be used in ECDH
+ * @param[in] raw_public_key Peer's public key in DER format to be used in ECDH
+ * @param[in] raw_public_key_len Length of the @a raw_public_key
+ * @param[in] new_key_alias The name under which the new key will be known in key-manager
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ *
+ * @retval #CKMC_ERROR_NONE Successful
+ * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid (@a private_key_alias = NULL,
+ *                                       @a raw_public_key = NULL, @a new_key_alias = NULL)
+ * @retval #CKMC_ERROR_DB_LOCKED A user is not logged in to key-manager
+ * @retval #CKMC_ERROR_DB_ALIAS_UNKNOWN @a private_key_alias does not exist
+ * @retval #CKMC_ERROR_DB_ALIAS_EXISTS @a new_key_alias already exists
+ * @retval #CKMC_ERROR_INVALID_FORMAT The format of @a raw_public_key is not valid
+ * @retval #CKMC_ERROR_DB_ERROR Failed due to a database error
+ * @retval #CKMC_ERROR_PERMISSION_DENIED Failed to access key manager
+ * @retval #CKMC_ERROR_AUTHENTICATION_FAILED Secret decryption failed because @a private_key_alias
+ *                                           needed a password and none was given
+ * @retval #CKMC_ERROR_SERVER_ERROR Unknown error
+ *
+ * @pre User is already logged in to key-manager.
+ *
+ * @see ckmc_key_derive()
+ */
+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);
+
+/**
+ * @brief Derives a symmetric key from a password using PBKFD2 and stores it in key-manager
+ *
+ * @since_tizen 7.5
+ *
+ * @remarks The password is temporarily stored in key-manager. It is deleted after key derivation
+ *          is performed.
+ * @remarks The key-manager's policy for storing the derived key is fixed in the code.
+ * @remarks The number of PBKDF2 iteration is fixed in the code.
+ *
+ * @param[in] password The password to derive the key from
+ * @param[in] salt The salt used for PBKDF2
+ * @param[in] salt_len Length of the @a salt
+ * @param[in] new_key_len The desired length of the derived key
+ * @param[in] new_key_alias The name under which the new key will be known in key-manager
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ *
+ * @retval #CKMC_ERROR_NONE Successful
+ * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid (@a password = NULL or
+ *                                       @a salt = NULL)
+ * @retval #CKMC_ERROR_NOT_SUPPORTED Unsupported key length
+ * @retval #CKMC_ERROR_DB_LOCKED A user is not logged in to key-manager
+ * @retval #CKMC_ERROR_DB_ALIAS_EXISTS @a new_key_alias already exists
+ * @retval #CKMC_ERROR_DB_ERROR Failed due to a database error
+ * @retval #CKMC_ERROR_PERMISSION_DENIED Failed to access key manager
+ * @retval #CKMC_ERROR_SERVER_ERROR Unknown error
+ *
+ * @pre User is already logged in to key-manager.
+ *
+ * @see ckmc_key_derive()
+ */
+int ckmew_key_derive_pbkdf2(const char *password,
+                            const unsigned char *salt,
+                            size_t salt_len,
+                            size_t new_key_len,
+                            const char *new_key_alias);
+
+/**
+ * @platform
+ *
+ * @since_tizen 7.5
+ *
+ * @brief Constructs OCF certificate chain and returns it
+ *
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @remarks The @a cert_chain should be freed using free().
+ *
+ * @param[out] cert_chain Certificate chain in binary, will be allocated by the library
+ * @param[out] cert_chain_len The total length of certificate chain
+ *
+ * @return #DCM_ERROR_NONE on success, otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_NO_DATA No certificate chain available
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ */
+int ckmew_get_ocf_cert_chain(char **cert_chain, size_t *cert_chain_len);
+
+/**
+ * @platform
+ *
+ * @since_tizen 7.5
+ *
+ * @brief Signs given public key with OCF using E2EE signing scheme.
+ *
+ * @privlevel platform
+ * @privilege %http://tizen.org/privilege/devicecertificate
+ *
+ * @remarks The public key will be retrieved from key-manager.
+ * @remarks It is assumed that the public key is not encrypted with a custom password in
+ *          key-manager and thus there's no need to pass additional argument.
+ *
+ * @param[in] public_key_alias Alias of the public key to be signed
+ * @param[out] message The E2EE message composed from public key and E2EE prefixes. It has to be
+ *             freed using ckmc_buffer_free()
+ * @param[out] signature The OCF signature calculated for @a message. It has to be
+ *             freed using ckmc_buffer_free()
+ *
+ * @return #DCM_ERROR_NONE on success, otherwise a negative error value
+ *
+ * @retval #DCM_ERROR_NONE Successful
+ * @retval #DCM_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #DCM_ERROR_OUT_OF_MEMORY Out of memory during processing
+ * @retval #DCM_ERROR_PERMISSION_DENIED Failed to access device certificate manager
+ * @retval #DCM_ERROR_NOT_SUPPORTED Feature needed to run API is not supported
+ * @retval #DCM_ERROR_SOCKET Socket error between client and server
+ * @retval #DCM_ERROR_NO_DATA If OCF or public key are not available
+ * @retval #DCM_ERROR_UNKNOWN Unknown error
+ * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid
+ * @retval #CKMC_ERROR_OUT_OF_MEMORY Not enough memory
+ * @retval #CKMC_ERROR_DB_LOCKED A user key is not loaded in memory (a user is not logged in)
+ * @retval #CKMC_ERROR_DB_ERROR Failed due to a database error
+ * @retval #CKMC_ERROR_DB_ALIAS_UNKNOWN Alias does not exist
+ * @retval #CKMC_ERROR_PERMISSION_DENIED Failed to access key manager
+ * @retval #CKMC_ERROR_AUTHENTICATION_FAILED Decryption failed because password is incorrect
+ */
+int ckmew_sign_with_ocf(const char *public_key_alias,
+                        ckmc_raw_buffer_s **message,
+                        ckmc_raw_buffer_s **signature);
diff --git a/src/e2ee-adaptation-layer/tests.cpp b/src/e2ee-adaptation-layer/tests.cpp
new file mode 100644 (file)
index 0000000..2cd6a70
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ *  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 <sstream>
+
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/crypto.h>
+
+#include <dpl/test/test_runner.h>
+#include <ckm-common.h>
+#include <ckmc/ckmc-manager.h>
+#include <ckmc/ckmc-control.h>
+#include <device_certificate_manager.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_KEYS = { "rsa_private", "rsa_public" };
+
+const char* const DERIVED = "derived";
+
+constexpr size_t SALT_LEN = 16;
+const unsigned char SALT[SALT_LEN] = {};
+
+const ckmc_policy_s UNEXPORTABLE { nullptr, false };
+const ckmc_policy_s EXPORTABLE { nullptr, true };
+
+#define ERRORDESCRIBE(name) case name: return #name
+const char * E2EEErrorToString(int error) {
+    switch(error) {
+        ERRORDESCRIBE(DCM_ERROR_INVALID_PARAMETER);
+        ERRORDESCRIBE(DCM_ERROR_OUT_OF_MEMORY);
+        ERRORDESCRIBE(DCM_ERROR_PERMISSION_DENIED);
+        ERRORDESCRIBE(DCM_ERROR_NOT_SUPPORTED);
+        ERRORDESCRIBE(DCM_ERROR_NO_DATA);
+        ERRORDESCRIBE(DCM_ERROR_UNKNOWN);
+        ERRORDESCRIBE(DCM_ERROR_SOCKET);
+        default: return CKMCErrorToString(error);
+    }
+}
+#undef ERRORDESCRIBE
+
+// RUNNER_ASSERT wrappers
+template <typename F, typename... Args>
+void e2ee_result(int expected, F&& func, Args... args)
+{
+    int ret = func(args...);
+    RUNNER_ASSERT_MSG(ret == expected,
+                      "Expected: " << E2EEErrorToString(expected) << "(" << expected << ")"
+                      " got: " << E2EEErrorToString(ret) << "(" << ret << ")");
+}
+
+template <typename F, typename... Args>
+void e2ee_positive(F&& func, Args... args)
+{
+    e2ee_result(DCM_ERROR_NONE, std::move(func), args...);
+}
+
+template <typename F, typename... Args>
+void e2ee_invalid_param(F&& func, Args... args)
+{
+    e2ee_result(DCM_ERROR_INVALID_PARAMETER, std::move(func), args...);
+}
+
+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());
+        e2ee_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);
+        e2ee_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_KEYS.prv.c_str());
+        ckmc_remove_alias(RSA_KEYS.pub.c_str());
+        e2ee_positive(ckmc_create_key_pair_rsa,
+                      1024,
+                      RSA_KEYS.prv.c_str(),
+                      RSA_KEYS.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;
+    e2ee_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);
+    e2ee_positive(ckmew_key_agreement, prv.c_str(), pub_key->raw_key, pub_key->key_size, derived);
+
+    return AliasRemover(derived);
+}
+
+template <typename T, void (*Fn)(T*)>
+struct Free {
+    explicit Free(T* ptr) : ptr(ptr) {}
+    ~Free() {
+        Fn(ptr);
+    }
+    Free(const Free&) = delete;
+    Free& operator=(const Free&) = delete;
+    T* operator*() { return ptr; }
+private:
+    T* ptr;
+};
+
+void OPENSSL_free_wrapper(unsigned char* ptr)
+{
+    OPENSSL_free(static_cast<void*>(ptr));
+}
+
+typedef Free<dcm_e2ee_bundle_s, dcm_e2ee_free_bundle> FreeBundle;
+typedef Free<void, free> FreeVoid;
+typedef Free<BIO, BIO_free_all> FreeBio;
+typedef Free<unsigned char, OPENSSL_free_wrapper> FreeOpenssl;
+typedef Free<X509, X509_free> FreeX509;
+typedef Free<EVP_MD_CTX, EVP_MD_CTX_free> FreeMdCtx;
+typedef Free<X509_STORE_CTX, X509_STORE_CTX_free> FreeX509StoreCtx;
+
+typedef STACK_OF(X509) X509_STACK;
+typedef std::unique_ptr<X509_STACK, decltype(&sk_X509_free)> X509StackPtr;
+
+X509StackPtr getOcfChain()
+{
+    // extract OCFs root certificate
+    char* ocfChain = nullptr;
+    size_t ocfChainLen = 0;
+
+    // OCF cert + common OCFs root cert
+    e2ee_positive(ckmew_get_ocf_cert_chain, &ocfChain, &ocfChainLen);
+
+    RUNNER_ASSERT_MSG(ocfChain != nullptr, "OCF cert chain is empty");
+
+    FreeVoid ocfChainFree(static_cast<void*>(ocfChain));
+
+    RUNNER_ASSERT_MSG(ocfChainLen > 0, "OCF cert chain has 0 length");
+
+    auto bio = (BIO_new(BIO_s_mem()));
+    RUNNER_ASSERT_MSG(bio != nullptr, "BIO_new failed");
+    FreeBio bioFree(bio);
+
+    auto written = BIO_write(bio, ocfChain, ocfChainLen);
+    RUNNER_ASSERT_MSG(written >= 0, "BIO_write failed");
+    RUNNER_ASSERT_MSG(static_cast<size_t>(written) == ocfChainLen, "OCF chain write is incomplete");
+
+    // build a X509 chain
+    X509StackPtr chainPtr(sk_X509_new_null(), sk_X509_free);
+    RUNNER_ASSERT_MSG(chainPtr, "sk_X509_new_null failed");
+
+    X509* cert = nullptr;
+    while((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) != nullptr)
+        RUNNER_ASSERT_MSG(sk_X509_push(chainPtr.get(), cert) > 0, "Nothing was pushed to stack");
+
+    RUNNER_ASSERT_MSG(sk_X509_num(chainPtr.get()) >= 1, "No certificates in the chain");
+
+    // TODO this requires 2-element OCF cert chain
+    if (sk_X509_num(chainPtr.get()) < 2)
+        RUNNER_ERROR_MSG("Insufficient number of certificates in the chain");
+
+    return chainPtr;
+}
+
+struct ustreambuf: public std::basic_streambuf<unsigned char> {
+    ustreambuf(unsigned char* buf, size_t size) : std::basic_streambuf<unsigned char>()
+    {
+        pubsetbuf(buf, size);
+    }
+};
+
+class Peer
+{
+public:
+    Peer(const KeyAliasPair& keys, const char* derived) : ours(keys), derived(derived) {}
+    ~Peer() {
+        ckmc_remove_alias(derived);
+    }
+
+    std::string send()
+    {
+        ckmc_raw_buffer_s* message = nullptr;
+        ckmc_raw_buffer_s* signature = nullptr;
+        e2ee_positive(ckmew_sign_with_ocf, ours.pub.c_str(), &message, &signature);
+
+        auto messagePtr = create_raw_buffer(message);
+        auto signaturePtr = create_raw_buffer(signature);
+
+        RUNNER_ASSERT_MSG(messagePtr->size > 0, "Message buffer has 0 length");
+        RUNNER_ASSERT_MSG(messagePtr->data != nullptr, "Message buffer has no data");
+
+        RUNNER_ASSERT_MSG(signaturePtr->size > 0, "Signature buffer has 0 length");
+        RUNNER_ASSERT_MSG(signaturePtr->data != nullptr, "Signature buffer has no data");
+
+        // extract OCF key certificate
+        auto chainPtr = getOcfChain();
+        auto ocfCertX509 = sk_X509_value(chainPtr.get(), 0);
+
+        RUNNER_ASSERT_MSG(ocfCertX509 != nullptr, "OCF certificate extraction failed");
+
+        // convert it to DER
+        unsigned char *ocfCert = nullptr;
+        size_t ocfCertLen = i2d_X509(ocfCertX509, &ocfCert);
+
+        RUNNER_ASSERT_MSG(ocfCertLen > 0, "OCF certificate has 0 length");
+        RUNNER_ASSERT_MSG(ocfCert != nullptr, "OCF certificate is empty");
+        FreeOpenssl certFree(ocfCert);
+
+        // serialize
+        std::ostringstream os;
+        auto serialize = [&](const unsigned char* data, size_t size){
+            os.write(reinterpret_cast<const char*>(&size), sizeof(size));
+            os.write(reinterpret_cast<const char*>(data), size);
+        };
+
+        serialize(message->data, message->size);
+        serialize(signature->data, signature->size);
+        serialize(ocfCert, ocfCertLen);
+
+        return os.str();
+    }
+
+    void receive(std::string&& buffer)
+    {
+        // deserialize
+        std::istringstream is(buffer);
+        auto deserialize = [&]()
+        {
+            size_t size;
+            is.read(reinterpret_cast<char*>(&size), sizeof(size));
+            RUNNER_ASSERT_MSG(size > 0, "Deserialized 0 length vector");
+            std::vector<unsigned char> data(size);
+            is.read(reinterpret_cast<char*>(data.data()), size);
+
+            return data;
+        };
+
+        auto message = deserialize();
+        auto signature = deserialize();
+        auto ocfCert = deserialize();
+
+        // decompose message
+        unsigned char* messageDup = static_cast<unsigned char*>(malloc(message.size()));
+        RUNNER_ASSERT_MSG(messageDup != nullptr, "Memory allocation failed");
+        memcpy(messageDup, message.data(), message.size());
+
+        dcm_e2ee_bundle_h bundle = nullptr;
+        e2ee_positive(dcm_e2ee_create_bundle, messageDup, message.size(), &bundle);
+        RUNNER_ASSERT_MSG(bundle != nullptr, "Bundle creation failed");
+        FreeBundle freeBundle(bundle);
+
+        const char* platform = nullptr;
+        e2ee_positive(dcm_e2ee_get_bundle_platform, bundle, &platform);
+        RUNNER_ASSERT_MSG(strcmp(platform, "Tizen") == 0, "Unexpected platform:" << platform);
+
+        char* label = NULL;
+        ssize_t size = smack_new_label_from_self(&label);
+        RUNNER_ASSERT_MSG(size > 0 &&  label != nullptr, "Smack label acquisition failed");
+        FreeVoid freeLabel(static_cast<void*>(label));
+
+        const char* pkgId = nullptr;
+        e2ee_positive(dcm_e2ee_get_bundle_pkg_id, bundle, &pkgId);
+        RUNNER_ASSERT_MSG(strcmp(pkgId, label) == 0, "Unexpected pkg id:" << pkgId);
+
+        const unsigned char* peerPubDevKey = nullptr;
+        size_t peerPubDevKeyLen = 0;
+        e2ee_positive(dcm_e2ee_get_bundle_payload, bundle, &peerPubDevKey, &peerPubDevKeyLen);
+        RUNNER_ASSERT_MSG(peerPubDevKey != nullptr, "Empty public key");
+        RUNNER_ASSERT_MSG(peerPubDevKeyLen > 0, "Public key has zero length");
+
+        // parse OCF certificate
+        const unsigned char* ocfCertPtr = ocfCert.data();
+        auto ocfCertX509 = d2i_X509(nullptr, &ocfCertPtr, ocfCert.size());
+        RUNNER_ASSERT_MSG(ocfCertX509 != nullptr, "OCF certificate parsing failed");
+        FreeX509 freeCert(ocfCertX509);
+
+        // extract OCF public key from OCF certificate
+        EVP_PKEY *ocfPubKey = X509_get0_pubkey(ocfCertX509);
+        RUNNER_ASSERT_MSG(ocfPubKey != nullptr, "Can't get public key from OCF certificate");
+
+        // verify OCF signature
+        EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
+        RUNNER_ASSERT_MSG(mdctx != nullptr, "EVP_MD_CTX_new failed");
+        FreeMdCtx freeMd(mdctx);
+
+        int ret = EVP_DigestVerifyInit(mdctx, nullptr, EVP_sha256(), nullptr, ocfPubKey);
+        RUNNER_ASSERT_MSG(ret == 1, "EVP_DigestVerifyInit failed");
+
+        ret = EVP_DigestVerifyUpdate(mdctx, message.data(), message.size());
+        RUNNER_ASSERT_MSG(ret == 1, "EVP_DigestVerifyUpdate failed");
+
+        ret = EVP_DigestVerifyFinal(mdctx, signature.data(), signature.size());
+        RUNNER_ASSERT_MSG(ret == 1, "OCF signature verification failed");
+
+        // verify received cert with local certchain
+        auto chainPtr = getOcfChain();
+
+        // pop the first certificate
+        sk_X509_shift(chainPtr.get());
+
+        X509_STORE* store = X509_STORE_new();
+        FreeX509StoreCtx storeCtx(X509_STORE_CTX_new());
+        // store becomes a member of storeCtx
+        ret = X509_STORE_CTX_init(*storeCtx, store, ocfCertX509, chainPtr.get());
+        RUNNER_ASSERT_MSG(ret == 1, "X509_STORE_CTX_init failed");
+        ret = X509_verify_cert(*storeCtx);
+        // TODO this requires 2-element OCF cert chain
+        if (ret != 1)
+            RUNNER_ERROR_MSG("OCF certificate verification failed");
+
+        // derive shared key
+        e2ee_positive(ckmew_key_agreement,
+                      ours.prv.c_str(),
+                      peerPubDevKey,
+                      peerPubDevKeyLen,
+                      derived);
+    }
+
+    RawBufferPtr encrypt(const ParamListPtr& params, const RawBufferPtr& plain)
+    {
+        ckmc_raw_buffer_s* encrypted = nullptr;
+        e2ee_positive(ckmc_encrypt_data, params.get(), derived, "", *plain.get(), &encrypted);
+        return create_raw_buffer(encrypted);
+    }
+
+    RawBufferPtr decrypt(const ParamListPtr& params, const RawBufferPtr& encrypted)
+    {
+        ckmc_raw_buffer_s* decrypted = nullptr;
+        e2ee_positive(ckmc_decrypt_data, params.get(), derived, "", *encrypted.get(), &decrypted);
+        return create_raw_buffer(decrypted);
+    }
+
+private:
+    const KeyAliasPair& ours;
+    const char* 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;
+    e2ee_positive(ckmc_encrypt_data, params.get(), OURS_DERIVED, "", *plain.get(), &encrypted);
+    auto encryptedPtr = create_raw_buffer(encrypted);
+
+    ckmc_raw_buffer_s* decrypted = nullptr;
+    e2ee_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;
+    e2ee_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)
+{
+    auto pub_key = getKey(PEERS.pub);
+
+    auto invalid = [](const char* prv,
+                      const unsigned char* pub,
+                      size_t pub_size,
+                      const char* derived)
+    {
+        e2ee_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);
+
+    e2ee_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                ckmew_key_agreement,
+                "",
+                pub_key->raw_key,
+                pub_key->key_size,
+                DERIVED);
+
+    e2ee_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                ckmew_key_agreement,
+                "nonexistent-alias",
+                pub_key->raw_key,
+                pub_key->key_size,
+                DERIVED);
+
+    e2ee_positive(ckmew_key_agreement,
+                  OURS.prv.c_str(),
+                  pub_key->raw_key,
+                  pub_key->key_size,
+                  DERIVED);
+
+    AliasRemover remover(DERIVED);
+
+    e2ee_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+                ckmew_key_agreement,
+                OURS.prv.c_str(),
+                pub_key->raw_key,
+                pub_key->key_size,
+                DERIVED);
+}
+
+RUNNER_TEST(TEAL_1000_pbkdf_positive)
+{
+    constexpr size_t KEY_LEN = 32;
+
+    auto plain = create_raw_buffer(createRandomBufferCAPI(512));
+    auto iv = create_raw_buffer(createRandomBufferCAPI(16));
+    auto salt = create_raw_buffer(createRandomBufferCAPI(SALT_LEN));
+
+    auto params = createParamListPtr();
+    setParam(params, CKMC_PARAM_ALGO_TYPE, CKMC_ALGO_AES_CTR);
+    setParam(params, CKMC_PARAM_ED_IV, iv.get());
+
+    e2ee_positive(ckmew_key_derive_pbkdf2, "password", salt->data, salt->size, KEY_LEN, DERIVED);
+    auto remover1 = AliasRemover(DERIVED);
+
+    ckmc_raw_buffer_s* encrypted = nullptr;
+    e2ee_positive(ckmc_encrypt_data, params.get(), DERIVED, "", *plain.get(), &encrypted);
+    auto encryptedPtr = create_raw_buffer(encrypted);
+
+    auto deriveAndDecrypt = [&encryptedPtr, &params](const char* password,
+                                                     const unsigned char* salt,
+                                                     size_t salt_len,
+                                                     size_t key_len)
+    {
+        const char* const DERIVED2 = "derived2";
+        e2ee_positive(ckmew_key_derive_pbkdf2, password, salt, salt_len, key_len, DERIVED2);
+        auto remover = AliasRemover(DERIVED2);
+
+        ckmc_raw_buffer_s* decrypted = nullptr;
+        e2ee_positive(ckmc_decrypt_data,
+                      params.get(),
+                      DERIVED2,
+                      "",
+                      *encryptedPtr.get(),
+                      &decrypted);
+
+        return create_raw_buffer(decrypted);
+    };
+
+    RawBufferPtr decrypted;
+    decrypted = deriveAndDecrypt("password", salt->data, salt->size, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get());
+
+    decrypted = deriveAndDecrypt("wrong", salt->data, salt->size, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+
+    decrypted = deriveAndDecrypt("password", salt->data, salt->size, KEY_LEN - 8);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+
+    decrypted = deriveAndDecrypt("password", salt->data, salt->size - 1, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+
+    decrypted = deriveAndDecrypt("password", plain->data, salt->size, KEY_LEN);
+    assert_buffers_equal(plain.get(), decrypted.get(), false);
+}
+
+RUNNER_TEST(TEAL_1010_pbkdf_invalid_arguments)
+{
+    e2ee_invalid_param(ckmew_key_derive_pbkdf2, nullptr,    SALT,    SALT_LEN, 32, DERIVED);
+    e2ee_invalid_param(ckmew_key_derive_pbkdf2, "password", nullptr, SALT_LEN, 32, DERIVED);
+    e2ee_invalid_param(ckmew_key_derive_pbkdf2, "password", SALT,    SALT_LEN, 32, nullptr);
+    e2ee_invalid_param(ckmew_key_derive_pbkdf2, "password", SALT,    SALT_LEN, 0,  DERIVED);
+
+    auto invalidFormat = [&](size_t key_len) {
+        e2ee_result(CKMC_ERROR_INVALID_FORMAT,
+                    ckmew_key_derive_pbkdf2,
+                    "password",
+                    SALT,
+                    SALT_LEN,
+                    key_len,
+                    DERIVED);
+    };
+    invalidFormat(64);
+    invalidFormat(31);
+    invalidFormat(8);
+    invalidFormat(1);
+}
+
+RUNNER_TEST(TEAL_1020_pbkdf_wrong_alias)
+{
+    e2ee_positive(ckmew_key_derive_pbkdf2, "password", SALT, SALT_LEN, 32, DERIVED);
+
+    auto remover = AliasRemover(DERIVED);
+
+    e2ee_result(CKMC_ERROR_DB_ALIAS_EXISTS,
+                ckmew_key_derive_pbkdf2,
+                "password",
+                SALT,
+                SALT_LEN,
+                32,
+                DERIVED);
+}
+
+RUNNER_TEST(TEAL_2000_ocf_positive)
+{
+    ckmc_raw_buffer_s* message = nullptr;
+    ckmc_raw_buffer_s* signature = nullptr;
+    e2ee_positive(ckmew_sign_with_ocf, OURS.pub.c_str(), &message, &signature);
+
+    auto messagePtr = create_raw_buffer(message);
+    auto signaturePtr = create_raw_buffer(signature);
+
+    RUNNER_ASSERT_MSG(messagePtr->size > 0, "Message buffer size is 0");
+    RUNNER_ASSERT_MSG(messagePtr->data != nullptr, "Message buffer is empty");
+
+    RUNNER_ASSERT_MSG(signaturePtr->size > 0, "Signature buffer size is 0");
+    RUNNER_ASSERT_MSG(signaturePtr->data != nullptr, "Singature buffer is empty");
+}
+
+RUNNER_TEST(TEAL_2010_ocf_invalid_param)
+{
+    ckmc_raw_buffer_s* message = nullptr;
+    ckmc_raw_buffer_s* signature = nullptr;
+
+    auto invalid = [](const char* pub_alias,
+                      ckmc_raw_buffer_s** message,
+                      ckmc_raw_buffer_s** signature)
+    {
+        e2ee_result(DCM_ERROR_INVALID_PARAMETER,
+                    ckmew_sign_with_ocf,
+                    pub_alias,
+                    message,
+                    signature);
+    };
+
+    invalid(nullptr, &message, &signature);
+    invalid(OURS.pub.c_str(), nullptr, &signature);
+    invalid(OURS.pub.c_str(), &message, nullptr);
+}
+
+RUNNER_TEST(TEAL_2020_ocf_wrong_public_key)
+{
+    ckmc_raw_buffer_s* message = nullptr;
+    ckmc_raw_buffer_s* signature = nullptr;
+
+    e2ee_result(CKMC_ERROR_DB_ALIAS_UNKNOWN,
+                ckmew_sign_with_ocf,
+                "nonexistent-alias",
+                &message,
+                &signature);
+
+    e2ee_result(CKMC_ERROR_NOT_EXPORTABLE,
+                ckmew_sign_with_ocf,
+                OURS.prv.c_str(),
+                &message,
+                &signature);
+}
+
+RUNNER_TEST(TEAL_3000_link_key_agreement_scenario)
+{
+    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());
+
+    Peer p1(OURS, "our_link_key");
+    Peer p2(PEERS, "peers_link_key");
+
+    p2.receive(p1.send());
+    p1.receive(p2.send());
+
+    auto encrypted = p1.encrypt(params, plain);
+    auto decrypted = p2.decrypt(params, encrypted);
+
+    assert_buffers_equal(plain.get(), decrypted.get());
+}
+
+int main(int argc, char *argv[])
+{
+    require_default_user(argv);
+
+    return DPL::Test::TestRunnerSingleton::Instance().ExecTestRunner(argc, argv);
+}