Merge branch 'ckm' into tizen 49/294649/1 tizen
authorDariusz Michaluk <d.michaluk@samsung.com>
Thu, 22 Jun 2023 07:28:24 +0000 (09:28 +0200)
committerDariusz Michaluk <d.michaluk@samsung.com>
Thu, 22 Jun 2023 07:28:24 +0000 (09:28 +0200)
Change-Id: Ia4bb16867447fd4d661a8578e21a7131a2cd16ad

packaging/security-tests.spec
src/ckm/ckm-common.cpp
src/ckm/ckm-common.h
src/ckm/privileged/system-db.cpp
src/ckm/unprivileged/encryption-decryption-env.cpp
src/ckm/unprivileged/encryption-decryption-env.h
src/ckm/unprivileged/encryption-decryption.cpp
src/ckm/unprivileged/main.cpp

index cd7b9c0..0b398af 100644 (file)
@@ -12,6 +12,7 @@ BuildRequires: libattr-devel
 BuildRequires: pkgconfig(libcap)
 BuildRequires: pkgconfig(libsmack)
 BuildRequires: pkgconfig(security-manager)
+# TODO update when cipher API is released
 BuildRequires: pkgconfig(key-manager) >= 0.1.49
 BuildRequires: key-manager-initial-values
 BuildRequires: util-linux
index 01c265c..2ceb95b 100644 (file)
@@ -387,55 +387,63 @@ void check_alias_list(const CKM::AliasVector& expected)
     RUNNER_ASSERT_MSG(expected == actual, "Actual list of aliases differ from expected list.");
 }
 
-void check_alias_info_list_helper(const CKM::AliasPwdVector& expected, const CKM::AliasPwdVector& actual,
-        const std::string &userSmackLabel)
+void check_alias_info_list_helper(const InfoVector& expected,
+                                  const InfoMap& actual,
+                                  const std::string &userSmackLabel)
 {
     std::string errorLogMsg;
-    std::unordered_map<std::string, bool> aliasPwdMap;
 
     RUNNER_ASSERT_MSG(expected.size() == actual.size(), "Aliases item count differs, expected: " <<
         expected.size() << " actual: " << actual.size());
 
-    for (const auto &it : actual)
+    for (const auto &expectedIt : expected)
     {
-        aliasPwdMap[std::get<0>(it)] = std::get<1>(it);
-    }
-
-
-    for (const auto &it : expected)
-    {
-        auto aliasPwd = aliasPwdMap.find(userSmackLabel + std::get<0>(it));
-        if (aliasPwd != aliasPwdMap.end()) {
-            if (aliasPwd->second != std::get<1>(it)) {
-                errorLogMsg += "Alias: " + std::get<0>(it) + " has wrong encryption status: "
-                                + std::to_string(std::get<1>(it)) + "\n";
+        auto actualIt = actual.find(userSmackLabel + expectedIt.alias);
+        if (actualIt != actual.end()) {
+            if (actualIt->second.passwordProtected != expectedIt.passwordProtected) {
+                errorLogMsg += "Alias: " + actualIt->second.alias + " has wrong encryption status: "
+                    + std::to_string(actualIt->second.passwordProtected) + "\n";
+            }
+            if (actualIt->second.backend != expectedIt.backend) {
+                errorLogMsg += "Alias: " + actualIt->second.alias + " belongs to wrong backend: "
+                    + std::to_string(static_cast<int>(actualIt->second.backend)) + "\n";
             }
         }
         else {
-            errorLogMsg += "Expected alias: " + std::get<0>(it) + " not found.\n";
+            errorLogMsg += "Expected alias: " + actualIt->second.alias + " not found.\n";
         }
     }
 
     if (!errorLogMsg.empty()) {
-        for (const auto &it : actual)
+        for (const auto& [alias, info] : actual)
         {
-            errorLogMsg += "Actual alias: " + std::get<0>(it) + " status: "
-                + std::to_string(std::get<1>(it)) + "\n";
+            errorLogMsg += "Actual alias: " + alias +
+                " status: " + std::to_string(info.passwordProtected) +
+                " backend: " + std::to_string(static_cast<int>(info.backend)) + "\n";
         }
         RUNNER_FAIL_MSG("Actual list of aliases differ from expected list.\n" + errorLogMsg);
     }
 }
 
-void check_alias_info_list(const CKM::AliasPwdVector& expected)
+CKM::BackendId backend()
+{
+#ifdef TZ_BACKEND
+    return CKM::BackendId::TZ;
+#else
+    return CKM::BackendId::SW;
+#endif
+}
+
+void check_alias_info_list(const InfoVector& expected)
 {
     ckmc_alias_info_list_s *aliasInfoList = NULL;
     int ret = ckmc_get_data_alias_info_list(&aliasInfoList);
     RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Failed to get the list of data aliases. " << ret << " / "
                       << CKMCErrorToString(ret));
 
-    CKM::AliasPwdVector actual;
+    InfoMap actual;
     ckmc_alias_info_list_s *plist = aliasInfoList;
-    char* alias;
+    char* alias = nullptr;
     bool isPasswordProtected;
     unsigned int it = 0;
     while (plist)
@@ -443,11 +451,18 @@ void check_alias_info_list(const CKM::AliasPwdVector& expected)
         ret = ckmc_alias_info_get_alias(plist->info, &alias);
         RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Failed to get alias. " << ret << " / "
                           << CKMCErrorToString(ret));
+        RUNNER_ASSERT_MSG(alias != nullptr, "Got null alias. Iterator: " << it);
+
         ret = ckmc_alias_info_is_password_protected(plist->info, &isPasswordProtected);
         RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Failed to get password protection status" << ret << " / "
                           << CKMCErrorToString(ret));
-        RUNNER_ASSERT_MSG(alias != nullptr, "Got null alias. Iterator: " << it);
-        actual.push_back(std::make_pair(alias, isPasswordProtected));
+
+        ckmc_backend_id_e backend;
+        ret = ckmc_alias_info_get_backend(plist->info, &backend);
+        RUNNER_ASSERT_MSG(ret == CKMC_ERROR_NONE, "Failed to get backend" << ret << " / "
+                          << CKMCErrorToString(ret));
+
+        actual.try_emplace(alias, alias, isPasswordProtected, static_cast<CKM::BackendId>(backend));
         plist = plist->next;
         it++;
     }
@@ -600,6 +615,11 @@ RawBufferPtr create_raw_buffer(ckmc_raw_buffer_s* buffer)
     return RawBufferPtr(buffer, ckmc_buffer_free);
 }
 
+CipherCtxPtr create_cipher_ctx(ckmc_cipher_ctx_h ctx)
+{
+    return CipherCtxPtr(ctx, ckmc_cipher_free);
+}
+
 CKM::Policy generate_ckm_policy(int iterator_nr) {
     if (iterator_nr % 2) { // policy with password and with / without extractable flag
         return CKM::Policy(CKM::Password("test_pwd"), iterator_nr % 4);
index 4d398e5..07cf3cc 100644 (file)
@@ -145,9 +145,28 @@ void reset_user_data(uid_t user_id, const char *passwd);
 
 ckmc_raw_buffer_s prepare_message_buffer(const char * input);
 void check_alias_list(const CKM::AliasVector& expected);
-void check_alias_info_list_helper(const CKM::AliasPwdVector& expected, const CKM::AliasPwdVector& actual,
+
+struct Info {
+    Info(const CKM::Alias &alias,
+         bool passwordProtected,
+         CKM::BackendId backend = CKM::BackendId::SW) :
+        alias(alias),
+        passwordProtected(passwordProtected),
+        backend(backend) {}
+
+    CKM::Alias alias;
+    bool passwordProtected;
+    CKM::BackendId backend;
+};
+typedef std::vector<Info> InfoVector;
+typedef std::unordered_map<std::string, Info> InfoMap;
+
+CKM::BackendId backend();
+
+void check_alias_info_list_helper(const InfoVector& expected,
+                                  const InfoMap& actual,
                                   const std::string &userSmackLabel = {});
-void check_alias_info_list(const CKM::AliasPwdVector& expected);
+void check_alias_info_list(const InfoVector& expected);
 
 typedef enum {
     ALIAS_KEY,
@@ -194,6 +213,7 @@ public:
 
 typedef std::shared_ptr<ckmc_raw_buffer_s> RawBufferPtr;
 typedef std::shared_ptr<struct __ckmc_param_list> ParamListPtr;
+typedef std::shared_ptr<struct __ckmc_cipher_ctx> CipherCtxPtr;
 
 ParamListPtr createParamListPtr();
 void setParam(ParamListPtr& params, ckmc_param_name_e name, ckmc_raw_buffer_s* buffer);
@@ -203,6 +223,8 @@ void assert_buffers_equal(const ckmc_raw_buffer_s* b1, const ckmc_raw_buffer_s*
 
 RawBufferPtr create_raw_buffer(ckmc_raw_buffer_s* buffer);
 
+CipherCtxPtr create_cipher_ctx(ckmc_cipher_ctx_h ctx);
+
 
 template <typename F, typename... Args>
 void test_no_observer(F&& func, Args... args)
index 1a4ee6e..944ada6 100644 (file)
@@ -527,11 +527,11 @@ RUNNER_TEST(T5046_CLIENT_GET_ALIAS_STATUS_NO_PASSWORD, RemoveDataEnv<0>)
     save_data(TEST_SYSTEM_ALIAS_2.c_str(), TEST_DATA);
 
     // [test]
-    CKM::AliasPwdVector aliasPwdVector;
-    aliasPwdVector.push_back(std::make_pair(TEST_SYSTEM_ALIAS.c_str(), false));
-    aliasPwdVector.push_back(std::make_pair(TEST_SYSTEM_ALIAS_2.c_str(), false));
+    InfoVector expected;
+    expected.emplace_back(TEST_SYSTEM_ALIAS, false, backend());
+    expected.emplace_back(TEST_SYSTEM_ALIAS_2, false, backend());
 
-    check_alias_info_list(aliasPwdVector);
+    check_alias_info_list(expected);
 }
 
 RUNNER_TEST(T5047_CLIENT_GET_ALIAS_STATUS_PASSWORD_PROTECTED, RemoveDataEnv<0>)
@@ -551,10 +551,10 @@ RUNNER_TEST(T5047_CLIENT_GET_ALIAS_STATUS_PASSWORD_PROTECTED, RemoveDataEnv<0>)
     save_data((TEST_SYSTEM_ALIAS_2 + "1").c_str(), TEST_DATA, strlen(TEST_DATA), TEST_PASSWORD);
 
     // [test]
-    CKM::AliasPwdVector aliasPwdVector;
-    aliasPwdVector.push_back(std::make_pair(TEST_SYSTEM_ALIAS.c_str(), false));
-    aliasPwdVector.push_back(std::make_pair(TEST_SYSTEM_ALIAS_2.c_str(), true));
-    aliasPwdVector.push_back(std::make_pair((TEST_SYSTEM_ALIAS_2 + "1").c_str(),true));
+    InfoVector expected;
+    expected.emplace_back(TEST_SYSTEM_ALIAS, false, backend());
+    expected.emplace_back(TEST_SYSTEM_ALIAS_2, true, backend());
+    expected.emplace_back(TEST_SYSTEM_ALIAS_2 + "1", true, backend());
 
-    check_alias_info_list(aliasPwdVector);
+    check_alias_info_list(expected);
 }
index 03dc266..7f43bcb 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <encryption-decryption-env.h>
+#include <ckm-common.h>
 
 using namespace CKM;
 
@@ -145,3 +146,196 @@ EncryptionError AsyncApi::ckmError2Result(int error)
     default:                                   return EncryptionError::OTHER;
     }
 }
+
+int CipherApi::crypt(ckmc_cipher_ctx_h ctx,
+                     unsigned char *ptr,
+                     size_t left,
+                     CKM::RawBuffer& output)
+{
+#ifdef TZ_BACKEND
+    ckmc_backend_info_h info;
+    size_t maxSize;
+    // All unexportable keys go to TZ if enabled (and all of them are unexportable)
+    assert_positive(ckmc_get_backend_info, CKMC_BACKEND_TZ, &info);
+    assert_positive(ckmc_backend_get_max_chunk_size, info, &maxSize);
+    const size_t CHUNK_SIZE = 80 < maxSize ? 80 : maxSize;
+#else
+    const size_t CHUNK_SIZE = 80;
+#endif
+    ckmc_raw_buffer_s* out = nullptr;
+    ckmc_raw_buffer_s* in = nullptr;
+    size_t size = CHUNK_SIZE;
+    int ret = CKMC_ERROR_NONE;
+
+    while (left > 0) {
+        if (left < CHUNK_SIZE)
+            size = left;
+
+        ret = ckmc_buffer_new(ptr, size, &in);
+        if (ret != CKMC_ERROR_NONE)
+            goto crypt_fail;
+
+        ret = ckmc_cipher_update(ctx, *in, &out);
+        if (ret != CKMC_ERROR_NONE)
+            goto crypt_fail;
+
+        ckmc_buffer_free(in);
+        in = nullptr;
+        if (out != nullptr)
+            std::copy(out->data, out->data + out->size, std::back_inserter(output));
+
+        ckmc_buffer_free(out);
+        out = nullptr;
+
+        left -= size;
+        ptr += size;
+    }
+
+crypt_fail:
+    ckmc_buffer_free(out);
+    ckmc_buffer_free(in);
+    return ret;
+}
+
+EncryptionError CipherApi::encrypt(ckmc_param_list_h params,
+                                   const char *key_alias,
+                                   const char *password,
+                                   const ckmc_raw_buffer_s& plain,
+                                   ckmc_raw_buffer_s **ppencrypted)
+{
+    ckmc_cipher_ctx_h ctx = nullptr;
+    size_t left = plain.size;
+    unsigned char* ptr = plain.data;
+    CKM::RawBuffer encrypted;
+    ckmc_raw_buffer_s* out = nullptr;
+    ckmc_raw_buffer_s* encrypted_c = nullptr;
+    uint64_t algo;
+
+    int ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ALGO_TYPE, &algo);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    // encrypt
+    ret = ckmc_cipher_initialize(params, key_alias, password, true, &ctx);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    ret = crypt(ctx, ptr, left, encrypted);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    ret = ckmc_cipher_finalize(ctx, nullptr, &out);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    // make sure finalize returns exactly the tag
+    if (algo == CKMC_ALGO_AES_GCM) {
+        uint64_t tagLen = 128;
+        ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ED_TAG_LEN, &tagLen);
+        if (ret != CKMC_ERROR_NONE && ret != CKMC_ERROR_INVALID_PARAMETER)
+            goto encrypt_fail;
+
+        if (tagLen / 8 != out->size) {
+            ret = CKMC_ERROR_SERVER_ERROR;
+            goto encrypt_fail;
+        }
+    }
+
+    if (out != nullptr)
+        std::copy(out->data, out->data + out->size, std::back_inserter(encrypted));
+    out = nullptr;
+
+    ret = ckmc_buffer_new(encrypted.data(), encrypted.size(), &encrypted_c);
+    if (ret != CKMC_ERROR_NONE)
+        goto encrypt_fail;
+
+    *ppencrypted = encrypted_c;
+
+encrypt_fail:
+    ckmc_buffer_free(out);
+    ckmc_cipher_free(ctx);
+
+    return ckmcError2Result(ret);
+}
+
+EncryptionError CipherApi::decrypt(ckmc_param_list_h params,
+                                   const char *key_alias,
+                                   const char *password,
+                                   const ckmc_raw_buffer_s& encrypted,
+                                   ckmc_raw_buffer_s **ppdecrypted)
+{
+    ckmc_cipher_ctx_h ctx = nullptr;
+    size_t left = encrypted.size;
+    unsigned char* ptr = encrypted.data;
+    CKM::RawBuffer decrypted;
+    ckmc_raw_buffer_s* out = nullptr;
+    ckmc_raw_buffer_s* decrypted_c = nullptr;
+    ckmc_raw_buffer_s* tag = nullptr;
+    uint64_t algo;
+
+    int ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ALGO_TYPE, &algo);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    // extract the tag to pass in finalize
+    if (algo == CKMC_ALGO_AES_GCM) {
+        uint64_t tagLen = 128;
+        ret = ckmc_param_list_get_integer(params, CKMC_PARAM_ED_TAG_LEN, &tagLen);
+        if (ret != CKMC_ERROR_NONE && ret != CKMC_ERROR_INVALID_PARAMETER)
+            goto decrypt_fail;
+
+        tagLen /= 8;
+        if (tagLen > left) {
+            ret = CKMC_ERROR_INVALID_PARAMETER;
+            goto decrypt_fail;
+        }
+
+        ret = ckmc_buffer_new(encrypted.data + encrypted.size - tagLen, tagLen, &tag);
+        if (ret != CKMC_ERROR_NONE)
+            goto decrypt_fail;
+
+        left -= tagLen;
+    }
+
+    // decrypt
+    ret = ckmc_cipher_initialize(params, key_alias, password, false, &ctx);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    ret = crypt(ctx, ptr, left, decrypted);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    ret = ckmc_cipher_finalize(ctx, tag, &out);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    if (out != nullptr)
+        std::copy(out->data, out->data + out->size, std::back_inserter(decrypted));
+    out = nullptr;
+
+    ret = ckmc_buffer_new(decrypted.data(), decrypted.size(), &decrypted_c);
+    if (ret != CKMC_ERROR_NONE)
+        goto decrypt_fail;
+
+    *ppdecrypted = decrypted_c;
+
+decrypt_fail:
+    ckmc_cipher_free(ctx);
+    ckmc_buffer_free(out);
+    ckmc_buffer_free(tag);
+
+    return ckmcError2Result(ret);
+}
+
+EncryptionError CipherApi::ckmcError2Result(int error)
+{
+    switch (error) {
+    case CKMC_ERROR_NONE:                   return EncryptionError::SUCCESS;
+    case CKMC_ERROR_INVALID_PARAMETER:      return EncryptionError::INVALID_PARAM;
+    case CKMC_ERROR_SERVER_ERROR:           return EncryptionError::SERVER_ERROR;
+    case CKMC_ERROR_DB_ALIAS_UNKNOWN:       return EncryptionError::ALIAS_UNKNOWN;
+    case CKMC_ERROR_AUTHENTICATION_FAILED:  return EncryptionError::AUTH_FAILED;
+    default:                                return EncryptionError::OTHER;
+    }
+}
index 1af99e5..ac564f3 100644 (file)
@@ -35,7 +35,7 @@ enum EncryptionError{
     SERVER_ERROR,
     ALIAS_UNKNOWN,
     AUTH_FAILED,
-    OTHER,
+    OTHER
 };
 
 struct EncryptionApi
@@ -51,22 +51,26 @@ struct EncryptionApi
                                     const char *password,
                                     const ckmc_raw_buffer_s& encrypted,
                                     ckmc_raw_buffer_s **ppdecrypted) = 0;
+
+    virtual bool symmetricOnly() const { return false; }
+
+    virtual ~EncryptionApi() {}
 };
 
 class SyncApi : public EncryptionApi
 {
 public:
-    virtual EncryptionError encrypt(ckmc_param_list_h params,
-                                    const char *key_alias,
-                                    const char *password,
-                                    const ckmc_raw_buffer_s& decrypted,
-                                    ckmc_raw_buffer_s **ppencrypted);
+    EncryptionError encrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& decrypted,
+                            ckmc_raw_buffer_s **ppencrypted) override;
 
-    virtual EncryptionError decrypt(ckmc_param_list_h params,
-                                    const char *key_alias,
-                                    const char *password,
-                                    const ckmc_raw_buffer_s& encrypted,
-                                    ckmc_raw_buffer_s **ppdecrypted);
+    EncryptionError decrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& encrypted,
+                            ckmc_raw_buffer_s **ppdecrypted) override;
 private:
     static EncryptionError ckmcError2Result(int error);
 };
@@ -95,13 +99,13 @@ public:
                             const char *key_alias,
                             const char *password,
                             const ckmc_raw_buffer_s& decrypted,
-                            ckmc_raw_buffer_s **ppencrypted);
+                            ckmc_raw_buffer_s **ppencrypted) override;
 
     EncryptionError decrypt(ckmc_param_list_h params,
                             const char *key_alias,
                             const char *password,
                             const ckmc_raw_buffer_s& encrypted,
-                            ckmc_raw_buffer_s **ppdecrypted);
+                            ckmc_raw_buffer_s **ppdecrypted) override;
 private:
     typedef void (CKM::ManagerAsync::*cryptoFn)(const CKM::ManagerAsync::ObserverPtr&,
                                                 const CKM::CryptoAlgorithm&,
@@ -119,5 +123,25 @@ private:
     static EncryptionError ckmError2Result(int error);
 };
 
+class CipherApi : public EncryptionApi
+{
+public:
+    EncryptionError encrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& decrypted,
+                            ckmc_raw_buffer_s **ppencrypted) override;
+
+    EncryptionError decrypt(ckmc_param_list_h params,
+                            const char *key_alias,
+                            const char *password,
+                            const ckmc_raw_buffer_s& encrypted,
+                            ckmc_raw_buffer_s **ppdecrypted) override;
+
+    bool symmetricOnly() const override { return true; }
 
+private:
+    int crypt(ckmc_cipher_ctx_h ctx, unsigned char *ptr, size_t left, CKM::RawBuffer& output);
+    EncryptionError ckmcError2Result(int error);
+};
 
index a29c452..d8b98b3 100644 (file)
@@ -46,6 +46,7 @@ const size_t BUF_LEN = 86; // must be less than 1024/8-41 to support RSA OAEP 10
 // Environment
 SyncApi g_syncApi;
 AsyncApi g_asyncApi;
+CipherApi g_cipherApi;
 
 EncryptionApi* g_api = &g_syncApi;
 
@@ -134,6 +135,18 @@ struct AsyncEnv {
     static std::string suffix() { return "_async"; }
 };
 
+struct CipherEnv {
+    void init(const std::string&) {
+        g_api = &g_cipherApi;
+    }
+
+    void finish() {
+        g_api = nullptr;
+    }
+
+    static std::string suffix() { return "_cipher"; }
+};
+
 struct Algo {
     ckmc_algo_type_e type;
     size_t keyLen;
@@ -152,6 +165,7 @@ enum KeyIdx {
 RawBufferPtr PLAIN_DATA;
 RawBufferPtr BIG_DATA;
 ckmc_raw_buffer_s* DEFAULT_IV;
+ckmc_raw_buffer_s* IV1;
 ckmc_raw_buffer_s* IV11;
 ckmc_raw_buffer_s* IV12;
 ckmc_raw_buffer_s* IV15;
@@ -199,11 +213,16 @@ public:
 
         PLAIN_DATA = create_raw_buffer(createRandomBufferCAPI(BUF_LEN));
 #ifdef TZ_BACKEND
-        BIG_DATA = create_raw_buffer(createRandomBufferCAPI(1000));
+        ckmc_backend_info_h info;
+        size_t size;
+        assert_positive(ckmc_get_backend_info, CKMC_BACKEND_TZ, &info);
+        assert_positive(ckmc_backend_get_max_chunk_size, info, &size);
+        BIG_DATA = create_raw_buffer(createRandomBufferCAPI(size));
 #else
-        BIG_DATA = create_raw_buffer(createRandomBufferCAPI(5000000));
+        BIG_DATA = create_raw_buffer(createRandomBufferCAPI(500000));
 #endif
         DEFAULT_IV = createRandomBufferCAPI(DEFAULT_IV_LEN);
+        IV1 = createRandomBufferCAPI(1);
         IV11 = createRandomBufferCAPI(11);
         IV12 = createRandomBufferCAPI(12);
         IV15 = createRandomBufferCAPI(15);
@@ -276,6 +295,7 @@ public:
         ckmc_buffer_free(IV15);
         ckmc_buffer_free(IV12);
         ckmc_buffer_free(IV11);
+        ckmc_buffer_free(IV1);
         ckmc_buffer_free(DEFAULT_IV);
 
         int ret = ckmc_lock_user_key(UID);
@@ -322,8 +342,7 @@ EncryptionResult encrypt(const Algo& algo,
     return ret;
 }
 
-void testAllAlgorithms(
-        const std::function<void(const Algo& algo)>& test)
+void testAllAlgorithms(const std::function<void(const Algo& algo)>& test)
 {
     test( { CKMC_ALGO_AES_CBC, 128 });
     test( { CKMC_ALGO_AES_CBC, 192 });
@@ -337,9 +356,12 @@ void testAllAlgorithms(
     test( { CKMC_ALGO_AES_CFB, 128 });
     test( { CKMC_ALGO_AES_CFB, 192 });
     test( { CKMC_ALGO_AES_CFB, 256 });
-    test( { CKMC_ALGO_RSA_OAEP, 1024 });
-    test( { CKMC_ALGO_RSA_OAEP, 2048 });
-    test( { CKMC_ALGO_RSA_OAEP, 4096 });
+
+    if (!g_api->symmetricOnly()) {
+        test( { CKMC_ALGO_RSA_OAEP, 1024 });
+        test( { CKMC_ALGO_RSA_OAEP, 2048 });
+        test( { CKMC_ALGO_RSA_OAEP, 4096 });
+    }
 }
 
 void testNoIvEnc(const Algo& algo)
@@ -815,7 +837,8 @@ void testGcmDifferentIvSizes(const Algo& algo)
     // add AES GCM key
     KeyAliasPair aliases = getKey(algo, PRIMARY);
 
-    testGcmIvSize(IV11,  aliases, EncryptionError::SERVER_ERROR); // 12B is the smallest
+    testGcmIvSize(IV1,   aliases);
+    testGcmIvSize(IV11,  aliases);
     testGcmIvSize(IV12,  aliases);
     testGcmIvSize(IV17,  aliases);
     testGcmIvSize(IV128, aliases);
@@ -915,6 +938,19 @@ void testRsaDataTooLong(const Algo& algo, size_t dataSize)
                          &encrypted);
 }
 
+std::pair<Alias, ParamListPtr> defaultGcmCipherSetup()
+{
+    Algo algo = {CKMC_ALGO_AES_GCM, 256};
+    KeyAliasPair aliases = getKey(algo, PRIMARY);
+
+    ckmc_param_list_h handle = NULL;
+    assert_positive(ckmc_generate_new_params, algo.type, &handle);
+    auto params = ParamListPtr(handle, ckmc_param_list_free);
+    setParam(params, CKMC_PARAM_ED_IV, IV12);
+
+    return std::make_pair(aliases.prv, params);
+}
+
 } // namespace anonymous
 
 RUNNER_TEST_GROUP_INIT_ENV(CKM_ENCRYPTION_DECRYPTION, EncGroupFixture);
@@ -923,7 +959,7 @@ RUNNER_TEST_GROUP_INIT_ENV(CKM_ENCRYPTION_DECRYPTION, EncGroupFixture);
 // Generic encryption decryption tests
 /////////////////////////////////////////
 
-RUNNER_TEST_MULTIPLE(TED_0010_encrypt_invalid_param_list, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0010_encrypt_invalid_param_list, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -951,7 +987,7 @@ RUNNER_TEST_MULTIPLE(TED_0010_encrypt_invalid_param_list, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0020_encrypt_missing_key, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0020_encrypt_missing_key, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1022,7 +1058,7 @@ RUNNER_TEST_MULTIPLE(TED_0040_encrypt_no_output_buffer, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0110_decrypt_invalid_param_list, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0110_decrypt_invalid_param_list, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1050,7 +1086,7 @@ RUNNER_TEST_MULTIPLE(TED_0110_decrypt_invalid_param_list, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0120_decrypt_missing_key, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0120_decrypt_missing_key, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1113,7 +1149,7 @@ RUNNER_TEST_MULTIPLE(TED_0140_decrypt_no_output_buffer, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0200_encrypt_decrypt_different_keys, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0200_encrypt_decrypt_different_keys, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_GCM, 128}, false);
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_GCM, 192}, false);
@@ -1124,12 +1160,15 @@ RUNNER_TEST_MULTIPLE(TED_0200_encrypt_decrypt_different_keys, SyncEnv, AsyncEnv)
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_CFB, 128}, true);
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_CFB, 192}, true);
     testEncryptDecryptDifferentKeys({CKMC_ALGO_AES_CFB, 256}, true);
-    testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 1024}, false);
-    testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 2048}, false);
-    testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 4096}, false);
+
+    if (!g_api->symmetricOnly()) {
+        testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 1024}, false);
+        testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 2048}, false);
+        testEncryptDecryptDifferentKeys({CKMC_ALGO_RSA_OAEP, 4096}, false);
+    }
 }
 
-RUNNER_TEST_MULTIPLE(TED_0300_encrypt_decrypt, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0300_encrypt_decrypt, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1150,7 +1189,7 @@ RUNNER_TEST_MULTIPLE(TED_0300_encrypt_decrypt, SyncEnv, AsyncEnv)
     });
 }
 
-RUNNER_TEST_MULTIPLE(TED_0310_encrypt_decrypt_password, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0310_encrypt_decrypt_password, SyncEnv, AsyncEnv, CipherEnv)
 {
     testAllAlgorithms([](const Algo& algo){
         // prepare buffers
@@ -1182,62 +1221,62 @@ RUNNER_TEST_MULTIPLE(TED_0310_encrypt_decrypt_password, SyncEnv, AsyncEnv)
 }
 
 // long test split into smaller ones
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CBC, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CBC, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CBC_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CBC, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_GCM, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_GCM, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_GCM_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CTR, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CTR, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CTR_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_128, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_128, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CFB, 128});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_192, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_192, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CFB, 192});
 }
 
-RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_256, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_256, SyncEnv, AsyncEnv, CipherEnv)
 {
     testEncryptDecryptBigData({CKMC_ALGO_AES_CFB, 256});
 }
@@ -1246,7 +1285,7 @@ RUNNER_TEST_MULTIPLE(TED_0400_encrypt_decrypt_big_data_AES_CFB_256, SyncEnv, Asy
 // Algorithm specific tests
 /////////////////////////////////////////
 
-RUNNER_TEST_MULTIPLE(TED_1005_no_iv_enc, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1005_no_iv_enc, SyncEnv, AsyncEnv, CipherEnv)
 {
     testNoIvEnc({CKMC_ALGO_AES_CTR, 128});
     testNoIvEnc({CKMC_ALGO_AES_CTR, 192});
@@ -1262,7 +1301,7 @@ RUNNER_TEST_MULTIPLE(TED_1005_no_iv_enc, SyncEnv, AsyncEnv)
     testNoIvEnc({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1010_invalid_iv_enc, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1010_invalid_iv_enc, SyncEnv, AsyncEnv, CipherEnv)
 {
     testInvalidIvEnc({CKMC_ALGO_AES_CTR, 128});
     testInvalidIvEnc({CKMC_ALGO_AES_CTR, 192});
@@ -1275,7 +1314,7 @@ RUNNER_TEST_MULTIPLE(TED_1010_invalid_iv_enc, SyncEnv, AsyncEnv)
     testInvalidIvEnc({CKMC_ALGO_AES_CFB, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1015_no_iv_dec, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1015_no_iv_dec, SyncEnv, AsyncEnv, CipherEnv)
 {
     testNoIvDec({CKMC_ALGO_AES_CTR, 128});
     testNoIvDec({CKMC_ALGO_AES_CTR, 192});
@@ -1291,7 +1330,7 @@ RUNNER_TEST_MULTIPLE(TED_1015_no_iv_dec, SyncEnv, AsyncEnv)
     testNoIvDec({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1020_invalid_iv_dec, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1020_invalid_iv_dec, SyncEnv, AsyncEnv, CipherEnv)
 {
     testInvalidIvDec({CKMC_ALGO_AES_CTR, 128});
     testInvalidIvDec({CKMC_ALGO_AES_CTR, 192});
@@ -1304,7 +1343,7 @@ RUNNER_TEST_MULTIPLE(TED_1020_invalid_iv_dec, SyncEnv, AsyncEnv)
     testInvalidIvDec({CKMC_ALGO_AES_CFB, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1050_data_integrity, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1050_data_integrity, SyncEnv, AsyncEnv, CipherEnv)
 {
     testIntegrity({CKMC_ALGO_AES_CTR, 128});
     testIntegrity({CKMC_ALGO_AES_CTR, 192});
@@ -1317,14 +1356,14 @@ RUNNER_TEST_MULTIPLE(TED_1050_data_integrity, SyncEnv, AsyncEnv)
     testIntegrity({CKMC_ALGO_AES_CFB, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1100_ctr_encryption_invalid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1100_ctr_encryption_invalid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     testCtrEncryptionInvalidLength({CKMC_ALGO_AES_CTR, 128});
     testCtrEncryptionInvalidLength({CKMC_ALGO_AES_CTR, 192});
     testCtrEncryptionInvalidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1105_ctr_encryption_valid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1105_ctr_encryption_valid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     RUNNER_IGNORED_MSG("Openssl supports only 128-bit AES CTR length");
     testCtrEncryptionValidLength({CKMC_ALGO_AES_CTR, 128});
@@ -1332,14 +1371,14 @@ RUNNER_TEST_MULTIPLE(TED_1105_ctr_encryption_valid_length, SyncEnv, AsyncEnv)
     testCtrEncryptionValidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1110_ctr_decryption_invalid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1110_ctr_decryption_invalid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     testCtrDecryptionInvalidLength({CKMC_ALGO_AES_CTR, 128});
     testCtrDecryptionInvalidLength({CKMC_ALGO_AES_CTR, 192});
     testCtrDecryptionInvalidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1115_ctr_decryption_valid_length, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1115_ctr_decryption_valid_length, SyncEnv, AsyncEnv, CipherEnv)
 {
     RUNNER_IGNORED_MSG("Openssl supports only 128-bit AES CTR length");
     testCtrDecryptionValidLength({CKMC_ALGO_AES_CTR, 128});
@@ -1347,35 +1386,35 @@ RUNNER_TEST_MULTIPLE(TED_1115_ctr_decryption_valid_length, SyncEnv, AsyncEnv)
     testCtrDecryptionValidLength({CKMC_ALGO_AES_CTR, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1200_gcm_encryption_tag_len, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1200_gcm_encryption_tag_len, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmEncryptionTagLen({CKMC_ALGO_AES_GCM, 128});
     testGcmEncryptionTagLen({CKMC_ALGO_AES_GCM, 192});
     testGcmEncryptionTagLen({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1210_gcm_decryption_tag_len, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1210_gcm_decryption_tag_len, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmDecryptionTagLen({CKMC_ALGO_AES_GCM, 128});
     testGcmDecryptionTagLen({CKMC_ALGO_AES_GCM, 192});
     testGcmDecryptionTagLen({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1230_gcm_wrong_tag, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1230_gcm_wrong_tag, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmWrongTag({CKMC_ALGO_AES_GCM, 128});
     testGcmWrongTag({CKMC_ALGO_AES_GCM, 192});
     testGcmWrongTag({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1240_gcm_different_iv_sizes, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1240_gcm_different_iv_sizes, SyncEnv, AsyncEnv, CipherEnv)
 {
     testGcmDifferentIvSizes({CKMC_ALGO_AES_GCM, 128});
     testGcmDifferentIvSizes({CKMC_ALGO_AES_GCM, 192});
     testGcmDifferentIvSizes({CKMC_ALGO_AES_GCM, 256});
 }
 
-RUNNER_TEST_MULTIPLE(TED_1250_gcm_aad, SyncEnv, AsyncEnv)
+RUNNER_TEST_MULTIPLE(TED_1250_gcm_aad, SyncEnv, AsyncEnv, CipherEnv)
 {
     encryptionWithCustomData({CKMC_ALGO_AES_GCM, 128}, CKMC_PARAM_ED_AAD);
     encryptionWithCustomData({CKMC_ALGO_AES_GCM, 192}, CKMC_PARAM_ED_AAD);
@@ -1450,7 +1489,7 @@ RUNNER_TEST(TED_2010_dec_no_observer_async, AsyncEnv)
 /////////////////////////////////////////
 // Mulithreaded test for synchronous API
 /////////////////////////////////////////
-RUNNER_TEST(TED_3000_muliple_threads, SyncEnv)
+RUNNER_TEST_MULTIPLE(TED_3000_multiple_threads, SyncEnv, CipherEnv)
 {
     std::vector<std::thread> threads;
     threads.reserve(10);
@@ -1459,3 +1498,154 @@ RUNNER_TEST(TED_3000_muliple_threads, SyncEnv)
     for (auto& thread : threads)
         thread.join();
 }
+
+/////////////////////////////////////////
+// Cipher API only
+/////////////////////////////////////////
+RUNNER_TEST(TED_4000_cipher_missing_arguments)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // no AAD
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+
+    // missing arguments
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, nullptr);
+    assert_invalid_param(ckmc_cipher_update, nullptr, *PLAIN_DATA.get(), &encrypted);
+    assert_invalid_param(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), nullptr);
+    assert_invalid_param(ckmc_cipher_finalize, nullptr, nullptr, &encrypted);
+    assert_invalid_param(ckmc_cipher_finalize, nullptr, nullptr, nullptr);
+}
+
+RUNNER_TEST(TED_4010_cipher_reinitialize_without_aad)
+{
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // no AAD
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+}
+
+RUNNER_TEST(TED_4020_cipher_tag_during_encryption)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // tag input during encryption
+    assert_invalid_param(ckmc_cipher_finalize, ctx, PLAIN_DATA.get(), &encrypted);
+}
+
+RUNNER_TEST(TED_4030_cipher_wrong_order)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), &encrypted);
+    ckmc_buffer_free(encrypted);
+
+    // initialize after update
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, nullptr);
+
+    assert_positive(ckmc_cipher_finalize, ctx, nullptr, &encrypted);
+    ckmc_buffer_free(encrypted);
+
+    // initialize after finalize
+    assert_invalid_param(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, nullptr);
+
+    // update after finalize
+    assert_invalid_param(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), &encrypted);
+}
+
+RUNNER_TEST(TED_4040_cipher_gcm_aad_and_tag)
+{
+    ckmc_raw_buffer_s* encrypted = nullptr;
+
+    auto [alias, params] = defaultGcmCipherSetup();
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+
+    ckmc_cipher_ctx_h ctx = nullptr;
+
+    // encrypt
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    auto ctxPtr = create_cipher_ctx(ctx);
+
+    // 2 more AAD chunks
+    setParam(params, CKMC_PARAM_ED_AAD, AAD64);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, true, &ctx);
+
+    ckmc_raw_buffer_s* tag = nullptr;
+
+    assert_positive(ckmc_cipher_update, ctx, *PLAIN_DATA.get(), &encrypted);
+    auto encryptedPtr = create_raw_buffer(encrypted);
+    assert_positive(ckmc_cipher_finalize, ctx, nullptr, &tag);
+
+    ctxPtr.reset();
+    ctx = nullptr;
+
+    ckmc_raw_buffer_s* decrypted = nullptr;
+    ckmc_raw_buffer_s* empty = nullptr;
+
+    // decrypt with invalid AAD
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    ctxPtr = create_cipher_ctx(ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *encrypted, &decrypted);
+    ckmc_buffer_free(decrypted);
+    assert_invalid_param(ckmc_cipher_finalize, ctx, tag, &empty);
+
+    ctxPtr.reset();
+    ctx = nullptr;
+
+    // decrypt without TAG
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    ctxPtr = create_cipher_ctx(ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD64);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *encrypted, &decrypted);
+    ckmc_buffer_free(decrypted);
+    assert_invalid_param(ckmc_cipher_finalize, ctx, nullptr, &empty);
+
+    ctxPtr.reset();
+    ctx = nullptr;
+
+    // correct decrypt
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    ctxPtr = create_cipher_ctx(ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD64);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+    setParam(params, CKMC_PARAM_ED_AAD, AAD32);
+    assert_positive(ckmc_cipher_initialize, params.get(), alias.c_str(), nullptr, false, &ctx);
+
+    assert_positive(ckmc_cipher_update, ctx, *encrypted, &decrypted);
+    auto decryptedPtr = create_raw_buffer(decrypted);
+    assert_positive(ckmc_cipher_finalize, ctx, tag, &empty);
+
+    RUNNER_ASSERT(empty == nullptr);
+
+    assert_buffers_equal(PLAIN_DATA.get(), decrypted);
+}
index 93ccd11..8f02903 100644 (file)
@@ -280,7 +280,13 @@ RUNNER_TEST(T1014_save_with_label)
 RUNNER_TEST(T1020_save_big_data)
 {
 #ifdef TZ_BACKEND
-    const size_t BIG_SIZE = 100000;
+    ckmc_backend_info_h info;
+    size_t size;
+    // all data goes to TZ when enabled
+    assert_positive(ckmc_get_backend_info, CKMC_BACKEND_TZ, &info);
+    assert_positive(ckmc_backend_get_max_chunk_size, info, &size);
+    const size_t BIG_SIZE = size;
+
     CKM::PolicyBackend backend = CKM::PolicyBackend::FORCE_HARDWARE;
 #else
     const size_t BIG_SIZE = 5000000;
@@ -442,7 +448,7 @@ RUNNER_TEST(T1024_app_user_save_keys_get_alias_pwd)
     const int aliasNameCount = 10;
     auto manager = CKM::Manager::create();
 
-    CKM::AliasPwdVector expected;
+    InfoVector expected;
     CKM::RawBuffer buffer(KEY_PEM.begin(), KEY_PEM.end());
     auto key = CKM::Key::create(buffer, CKM::Password());
     std::string currentAlias;
@@ -453,21 +459,31 @@ RUNNER_TEST(T1024_app_user_save_keys_get_alias_pwd)
     {
         CKM::Policy policy = generate_ckm_policy(it);
         currentAlias = "T1024_appkey" + std::to_string(it);
-        expected.push_back(std::make_pair(currentAlias, !policy.password.empty()));
+        expected.emplace_back(currentAlias, !policy.password.empty(), backend());
         RUNNER_ASSERT_MSG(
             CKM_API_SUCCESS == (exitCode = manager->saveKey(currentAlias, key, policy)),
             "Error=" << CKM::APICodeToString(exitCode));
     }
 
-    CKM::AliasPwdVector actual;
+    CKM::AliasInfoVector aliasInfoVector;
+    InfoMap actual;
 
     RUNNER_ASSERT_MSG(
-        CKM_API_SUCCESS == (exitCode = manager->getKeyAliasPwdVector(actual)),
+        CKM_API_SUCCESS == (exitCode = manager->getKeyAliasInfoVector(aliasInfoVector)),
         "Error=" << CKM::APICodeToString(exitCode));
     RUNNER_ASSERT_MSG(
-        actual.size() == (beforeSaveAliasCount + aliasNameCount),
-        "Wrong aliases count: " << actual.size() << " Expected: "
+            aliasInfoVector.size() == (beforeSaveAliasCount + aliasNameCount),
+        "Wrong aliases count: " << aliasInfoVector.size() << " Expected: "
         << (beforeSaveAliasCount + aliasNameCount));
+
+    bool status;
+    for (const auto &info : aliasInfoVector) {
+        exitCode = manager->getKeyEncryptionStatus(info.alias, status);
+        RUNNER_ASSERT_MSG(CKM_API_SUCCESS == exitCode, "Error=" << CKM::APICodeToString(exitCode));
+
+        actual.try_emplace(info.alias, info.alias, status, info.backend);
+    }
+
     check_alias_info_list_helper(expected, actual, "/User ");
 
     remove_user_data(USER_APP);
@@ -481,7 +497,7 @@ RUNNER_TEST(T1025_app_user_save_certificates_get_alias_pwd)
     const int aliasNameCount = 10;
     auto manager = CKM::Manager::create();
 
-    CKM::AliasPwdVector expected;
+    InfoVector expected;
     auto cert = TestData::getTestCertificate(TestData::TEST_LEAF);
     std::string currentAlias;
 
@@ -490,20 +506,31 @@ RUNNER_TEST(T1025_app_user_save_certificates_get_alias_pwd)
     {
         CKM::Policy policy = generate_ckm_policy(it);
         currentAlias = "T1025_appcert" + std::to_string(it);
-        expected.push_back(std::make_pair(currentAlias, !policy.password.empty()));
+        expected.emplace_back(currentAlias, !policy.password.empty(), CKM::BackendId::SW);
         RUNNER_ASSERT_MSG(
                 CKM_API_SUCCESS == (exitCode = manager->saveCertificate(currentAlias, cert, policy)),
                     "Error=" << CKM::APICodeToString(exitCode));
     }
 
-    CKM::AliasPwdVector actual;
+    CKM::AliasInfoVector aliasInfoVector;
+    InfoMap actual;
+
     RUNNER_ASSERT_MSG(
-        CKM_API_SUCCESS == (exitCode = manager->getCertificateAliasPwdVector(actual)),
+        CKM_API_SUCCESS == (exitCode = manager->getCertificateAliasInfoVector(aliasInfoVector)),
         "Error=" << CKM::APICodeToString(exitCode));
     RUNNER_ASSERT_MSG(
-        actual.size() == (beforeSaveAliasCount + aliasNameCount),
-        "Wrong aliases count: " << actual.size() << " Expected: "
+            aliasInfoVector.size() == (beforeSaveAliasCount + aliasNameCount),
+        "Wrong aliases count: " << aliasInfoVector.size() << " Expected: "
         << (beforeSaveAliasCount + aliasNameCount));
+
+    bool status;
+    for (const auto &info : aliasInfoVector) {
+        exitCode = manager->getCertificateEncryptionStatus(info.alias, status);
+        RUNNER_ASSERT_MSG(CKM_API_SUCCESS == exitCode, "Error=" << CKM::APICodeToString(exitCode));
+
+        actual.try_emplace(info.alias, info.alias, status, info.backend);
+    }
+
     check_alias_info_list_helper(expected, actual, "/User ");
 
     remove_user_data(USER_APP);
@@ -517,7 +544,7 @@ RUNNER_TEST(T1026_app_user_save_data_get_alias_pwd)
     const int aliasNameCount = 10;
     auto manager = CKM::Manager::create();
 
-    CKM::AliasPwdVector expected;
+    InfoVector expected;
     std::string binData = "My bin data";
     CKM::RawBuffer buffer(binData.begin(), binData.end());
     std::string currentAlias;
@@ -527,25 +554,63 @@ RUNNER_TEST(T1026_app_user_save_data_get_alias_pwd)
     {
         CKM::Policy policy = generate_ckm_policy(it);
         currentAlias = "T1026_appdata" + std::to_string(it);
-        expected.push_back(std::make_pair(currentAlias, !policy.password.empty()));
+        expected.emplace_back(currentAlias, !policy.password.empty(), backend());
         RUNNER_ASSERT_MSG(
             CKM_API_SUCCESS == (exitCode = manager->saveData(currentAlias, buffer, policy)),
                 "Error=" << CKM::APICodeToString(exitCode));
     }
 
-    CKM::AliasPwdVector actual;
+    CKM::AliasInfoVector aliasInfoVector;
+    InfoMap actual;
+
     RUNNER_ASSERT_MSG(
-        CKM_API_SUCCESS == (exitCode = manager->getDataAliasPwdVector(actual)),
+        CKM_API_SUCCESS == (exitCode = manager->getDataAliasInfoVector(aliasInfoVector)),
         "Error=" << CKM::APICodeToString(exitCode));
     RUNNER_ASSERT_MSG(
-        actual.size() == (beforeSaveAliasCount + aliasNameCount),
-        "Wrong aliases count: " << actual.size() << " Expected: "
+        aliasInfoVector.size() == (beforeSaveAliasCount + aliasNameCount),
+        "Wrong aliases count: " << aliasInfoVector.size() << " Expected: "
         << (beforeSaveAliasCount + aliasNameCount));
+
+    bool status;
+    for (const auto &info : aliasInfoVector) {
+        exitCode = manager->getDataEncryptionStatus(info.alias, status);
+        RUNNER_ASSERT_MSG(CKM_API_SUCCESS == exitCode, "Error=" << CKM::APICodeToString(exitCode));
+
+        actual.try_emplace(info.alias, info.alias, status, info.backend);
+    }
+
     check_alias_info_list_helper(expected, actual, "/User ");
 
     remove_user_data(USER_APP);
 }
 
+RUNNER_TEST(T1027_backend_info)
+{
+    //int ckmc_get_backend_info(ckmc_backend_id_e backend, ckmc_backend_info_h* ppinfo)
+    ckmc_backend_info_h info;
+    size_t size;
+    assert_invalid_param(ckmc_get_backend_info, static_cast<ckmc_backend_id_e>(-1), &info);
+    assert_invalid_param(ckmc_get_backend_info, static_cast<ckmc_backend_id_e>(2), &info);
+    assert_invalid_param(ckmc_get_backend_info, CKMC_BACKEND_SW, nullptr);
+
+#ifdef TZ_BACKEND
+    assert_positive(ckmc_get_backend_info, CKMC_BACKEND_TZ, &info);
+    RUNNER_ASSERT_MSG(info != nullptr, "Backend info is null");
+
+    assert_positive(ckmc_backend_get_max_chunk_size, info, &size);
+    RUNNER_ASSERT_MSG(size != 0, "Unexpected max chunk size");
+#else
+    assert_invalid_param(ckmc_get_backend_info, CKMC_BACKEND_TZ, &info);
+#endif
+
+    assert_positive(ckmc_get_backend_info, CKMC_BACKEND_SW, &info);
+    RUNNER_ASSERT_MSG(info != nullptr, "Backend info is null");
+
+    assert_positive(ckmc_backend_get_max_chunk_size, info, &size);
+    RUNNER_ASSERT_MSG(size == 0, "Unexpected max chunk size");
+}
+
+
 RUNNER_TEST(T1029_deinit)
 {
     remove_user_data(USER_APP);