From 733f084dca9bafa67af48aa9e287e1f8d600bb2c Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 26 Apr 2023 12:17:14 +0200 Subject: [PATCH 01/16] Multi-stage encryption API Change-Id: If56a367a40f1ca3a6d4dcebfbb38543c7ec44fd5 --- src/include/ckmc/ckmc-manager.h | 114 +++++++++++++++++++++++++++++++++++++++- src/include/ckmc/ckmc-type.h | 10 ++++ 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/src/include/ckmc/ckmc-manager.h b/src/include/ckmc/ckmc-manager.h index 686d939..07d5305 100644 --- a/src/include/ckmc/ckmc-manager.h +++ b/src/include/ckmc/ckmc-manager.h @@ -1244,7 +1244,7 @@ int ckmc_export_wrapped_key(const ckmc_param_list_h params, * @retval #CKMC_ERROR_DB_ALIAS_UNKNOWN @a secret_alias does not exist * @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_AUTHENTICATION_FAILED Secret decryption failed because @a secret_password is + * @retval #CKMC_ERROR_AUTHENTICATION_FAILED Secret decryption failed because @a secret_password is * incorrect * @retval #CKMC_ERROR_SERVER_ERROR Unknown error * @@ -1262,6 +1262,118 @@ int ckmc_key_derive(const ckmc_param_list_h params, const char *new_key_alias, ckmc_policy_s new_key_policy); +/** + * @brief Sets up a symmetric encryption or decryption context with given key and parameters. + * + * @since_tizen 6.5 + * + * @remarks The newly created @a context must be destroyed using ckmc_cipher_free() when it's no + * longer needed. + * @remarks To perform the encryption/decryption, one or more calls to ckmc_cipher_update() must be + * folowed by one call to ckmc_cipher_finalize(). + * + * @param[in] params Algorithm parameter list handle. See #ckmc_param_list_h and #ckmc_algo_type_e + * for details. Supported algorithms: + * - #CKMC_ALGO_AES_GCM, + * @param[in] key_alias Alias of the key to be used for encryption/decryption + * @param[in] key_password Optional password of the key used for encryption/decryption + * @param[in] encrypt Encryption/decryption switch (true=encryption, false=decryption) + * @param[out] context Encryption/decryption context + * + * @return @c 0 on success, otherwise a negative error value + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_PERMISSION_DENIED Insufficient permissions to access key manager or the key + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid (missing or invalid mandatory + * algorithm parameter, @a key_alias = NULL, + * @a context = NULL) + * @retval #CKMC_ERROR_DB_LOCKED A user key is not loaded in memory (a user is not logged in) + * @retval #CKMC_ERROR_DB_ALIAS_UNKNOWN @a key_alias does not exist + * @retval #CKMC_ERROR_DB_ERROR Failed due to a database error + * @retval #CKMC_ERROR_AUTHENTICATION_FAILED Key decryption failed because @a key_password is + * incorrect + * @retval #CKMC_ERROR_SERVER_ERROR Unknown error + * + * @pre User is already logged in and the user key is already loaded into memory in plain text form. + * + * @see #ckmc_cipher_ctx_h + * @see ckmc_cipher_update() + * @see ckmc_cipher_finalize() + * @see ckmc_cipher_free() + */ +int ckmc_cipher_initialize(ckmc_param_list_h params, + const char *key_alias, + const char *key_password, + bool encrypt, + ckmc_cipher_ctx_h *context); + +/** + * @brief Performs symmetric encryption or decryption of the input and places the result in the + * output. + * + * @since_tizen 6.5 + * + * @remarks The function may be called multiple times to encrypt succcessive blocks of data. + * @remarks The newly created @a ppout must be destroyed using ckmc_buffer_free() when it's no + * longer needed. + * + * @param[in] context Encryption/decryption context created with ckmc_cipher_initialize() + * @param[in] in Encryption/decryption input + * @param[out] ppout Encryption/decryption output + * + * @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 context = NULL, + * @a ppout = NULL) + * @retval #CKMC_ERROR_SERVER_ERROR Unknown error + * + * @see #ckmc_cipher_ctx_h + * @see ckmc_cipher_initialize() + * @see ckmc_cipher_finalize() + * @see ckmc_cipher_free() + */ +int ckmc_cipher_update(ckmc_cipher_ctx_h context, + const ckmc_raw_buffer_s in, + ckmc_raw_buffer_s **ppout); + +/** + * @brief Finalizes symmetric encryption or decryption and returns remaining output if any. + * + * @since_tizen 6.5 + * + * @remarks After the call to this function the ckmc_cipher_update() can be called no more. + * @remarks The newly created @a ppout must be destroyed using ckmc_buffer_free() when it's no + * longer needed. + * + * @param[in] context Encryption/decryption context created with ckmc_cipher_initialize() + * @param[out] ppout Encryption/decryption output + * + * @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 context = NULL, + * @a ppout = NULL) + * @retval #CKMC_ERROR_SERVER_ERROR Unknown error + * + * @see #ckmc_cipher_ctx_h + * @see ckmc_cipher_initialize() + * @see ckmc_cipher_update() + * @see ckmc_cipher_free() + */ +int ckmc_cipher_finalize(ckmc_cipher_ctx_h context, ckmc_raw_buffer_s **ppout); + +/** + * @brief Destroys the encryption/decryption context and releases all its resources. + * + * @since_tizen 6.5 + * + * @param[in] context Encryption/decryption context created with ckmc_cipher_initialize() + * + * @see #ckmc_cipher_ctx_h + * @see ckmc_cipher_initialize() + * @see ckmc_cipher_update() + * @see ckmc_cipher_finalize() + */ +void ckmc_cipher_free(ckmc_cipher_ctx_h context); + #ifdef __cplusplus } #endif diff --git a/src/include/ckmc/ckmc-type.h b/src/include/ckmc/ckmc-type.h index e568655..8897712 100644 --- a/src/include/ckmc/ckmc-type.h +++ b/src/include/ckmc/ckmc-type.h @@ -462,6 +462,16 @@ typedef enum __ckmc_algo_type { } ckmc_algo_type_e; /** + * @brief Encryption/decryption context handle. + * @since_tizen 6.5 + * @see ckmc_cipher_initialize() + * @see ckmc_cipher_update() + * @see ckmc_cipher_finalize() + * @see ckmc_cipher_free() + */ +typedef struct __ckmc_cipher_ctx *ckmc_cipher_ctx_h; + +/** * @brief Gets the alias from #ckmc_alias_info_s structure. * @since_tizen 5.5 * @remarks The @a alias should not be released. -- 2.7.4 From 647c61e72f911ab241d0c708f0894dfd161ce433 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 27 Apr 2023 11:33:20 +0200 Subject: [PATCH 02/16] Backend info API New API: - getting backend associated with given object - getting backend information for given backend - getting max encryption chunk size from backend information Change-Id: I8c66e623ba49ebda0a9fad28dcb3b48bd21b175f --- src/include/ckm/ckm-manager.h | 6 +-- src/include/ckm/ckm-type.h | 14 +++++- src/include/ckmc/ckmc-manager.h | 26 ++++++++++ src/include/ckmc/ckmc-type.h | 79 ++++++++++++++++++++++++++++-- src/manager/client-capi/ckmc-manager.cpp | 52 +++++++++++++++----- src/manager/client-capi/ckmc-type.cpp | 33 ++++++++++++- src/manager/client/client-common.h | 5 ++ src/manager/client/client-manager-impl.cpp | 19 +++---- src/manager/client/client-manager-impl.h | 10 ++-- src/manager/client/client-manager.cpp | 12 ++--- 10 files changed, 215 insertions(+), 41 deletions(-) diff --git a/src/include/ckm/ckm-manager.h b/src/include/ckm/ckm-manager.h index 2208def..8076456 100644 --- a/src/include/ckm/ckm-manager.h +++ b/src/include/ckm/ckm-manager.h @@ -74,13 +74,13 @@ public: // send request for list of all keys/certificates/data that application/user may use int getKeyAliasVector(AliasVector &aliasVector); - int getKeyAliasPwdVector(AliasPwdVector &aliasPwdVector); + int getKeyAliasInfoVector(AliasInfoVector &aliasInfoVector); int getKeyEncryptionStatus(const Alias &alias, bool &status); int getCertificateAliasVector(AliasVector &aliasVector); - int getCertificateAliasPwdVector(AliasPwdVector &aliasPwdVector); + int getCertificateAliasInfoVector(AliasInfoVector &aliasInfoVector); int getCertificateEncryptionStatus(const Alias &alias, bool &status); int getDataAliasVector(AliasVector &aliasVector); - int getDataAliasPwdVector(AliasPwdVector &aliasPwdVector); + int getDataAliasInfoVector(AliasInfoVector &aliasInfoVector); int getDataEncryptionStatus(const Alias &alias, bool &status); int createKeyPairRSA( diff --git a/src/include/ckm/ckm-type.h b/src/include/ckm/ckm-type.h index 2bc7610..72ab1c4 100644 --- a/src/include/ckm/ckm-type.h +++ b/src/include/ckm/ckm-type.h @@ -51,7 +51,19 @@ typedef std::string Alias; */ typedef std::string ClientId; typedef std::vector AliasVector; -typedef std::vector> AliasPwdVector; + +// backend identifiers +enum class BackendId : int { + SW = 0, + TZ, + // keep in sync with ckmc_backend_id_e ! +}; + +struct AliasInfo { + bool passwordProtected; + BackendId backend; +}; +typedef std::vector> AliasInfoVector; enum class KeyType : int { KEY_NONE = 0, diff --git a/src/include/ckmc/ckmc-manager.h b/src/include/ckmc/ckmc-manager.h index 07d5305..6edbe51 100644 --- a/src/include/ckmc/ckmc-manager.h +++ b/src/include/ckmc/ckmc-manager.h @@ -1374,6 +1374,32 @@ int ckmc_cipher_finalize(ckmc_cipher_ctx_h context, ckmc_raw_buffer_s **ppout); */ void ckmc_cipher_free(ckmc_cipher_ctx_h context); +/** + * @brief Retrieves backend information. + * + * @since_tizen 6.5 + * + * @remarks The newly created @a ppinfo must be destroyed using ckmc_backend_info_free() when it's + * no longer needed. + * + * @param[in] backend Backend identifier + * @param[out] ppinfo Backend information handle + * + * @return @c 0 on success, otherwise a negative error value + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_PERMISSION_DENIED Insufficient permissions to access key manager + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid (@a backend is invalid, + * @a ppinfo = NULL) + * @retval #CKMC_ERROR_SERVER_ERROR Unknown error + * + * @see #ckmc_backend_id_e + * @see #ckmc_backend_info_h + * @see ckmc_alias_info_get_backend() + * @see ckmc_backend_get_max_chunk_size() + * @see ckmc_backend_info_free() + */ +int ckmc_get_backend_info(ckmc_backend_id_e backend, ckmc_backend_info_h* ppinfo); + #ifdef __cplusplus } #endif diff --git a/src/include/ckmc/ckmc-type.h b/src/include/ckmc/ckmc-type.h index 8897712..54c1f06 100644 --- a/src/include/ckmc/ckmc-type.h +++ b/src/include/ckmc/ckmc-type.h @@ -172,7 +172,6 @@ typedef enum __ckmc_permission { CKMC_PERMISSION_REMOVE = 0x02 /**< Remove allowed */ } ckmc_permission_e; - /** * @brief The structure for binary buffer used in key manager CAPI. * @since_tizen 2.3 @@ -462,6 +461,29 @@ typedef enum __ckmc_algo_type { } ckmc_algo_type_e; /** + * @brief Enumeration for backend identifiers. + * @since_tizen 6.5 + * @see ckmc_get_backend_info() + * @see ckmc_alias_info_get_backend() + */ +typedef enum __ckmc_backend_id { + CKMC_BACKEND_SW = 0, /**< Software backend */ + CKMC_BACKEND_TZ /**< TrustZone backend */ +} ckmc_backend_id_e; + +struct __ckmc_backend_info_s; + +/** + * @brief Backend information handle. + * @since_tizen 6.5 + * @see ckmc_alias_info_get_backend() + * @see ckmc_get_backend_info() + * @see ckmc_backend_get_max_chunk_size() + * @see ckmc_backend_info_free() + */ +typedef struct __ckmc_backend_info_s *ckmc_backend_info_h; + +/** * @brief Encryption/decryption context handle. * @since_tizen 6.5 * @see ckmc_cipher_initialize() @@ -479,7 +501,7 @@ typedef struct __ckmc_cipher_ctx *ckmc_cipher_ctx_h; * @param[in] info The pointer to the #ckmc_alias_info_s structure * @param[out] alias The pointer to the alias * @return #CKMC_ERROR_NONE on success, - * othervise a negative error value + * otherwise a negative error value * @retval #CKMC_ERROR_NONE Successful * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid * @see #ckmc_alias_info_s @@ -492,12 +514,29 @@ int ckmc_alias_info_get_alias(const ckmc_alias_info_s* info, char** alias); * @param[in] info The pointer to the #ckmc_alias_info_s structure * @param[out] is_password_protected The pointer to the password protection flag * @return #CKMC_ERROR_NONE on success, - * othervise a negative error value + * otherwise a negative error value + * @retval #CKMC_ERROR_NONE Successful + * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * @see #ckmc_alias_info_s + */ +int ckmc_alias_info_is_password_protected(const ckmc_alias_info_s* info, + bool* is_password_protected); + +/** + * @brief Gets the backend identifier from #ckmc_alias_info_s structure. + * @since_tizen 6.5 + * @param[in] info The pointer to the #ckmc_alias_info_s structure + * @param[out] backend The pointer to the backend identifier + * @return #CKMC_ERROR_NONE on success, otherwise a negative error value * @retval #CKMC_ERROR_NONE Successful * @retval #CKMC_ERROR_INVALID_PARAMETER Input parameter is invalid + * @see #ckmc_backend_id_e * @see #ckmc_alias_info_s + * @see ckmc_get_backend_info() + * @see ckmc_backend_info_free() + * @see ckmc_backend_get_max_chunk_size() */ -int ckmc_alias_info_is_password_protected(const ckmc_alias_info_s* info, bool* is_password_protected); +int ckmc_alias_info_get_backend(const ckmc_alias_info_s* info, ckmc_backend_id_e* backend); /** * @brief Destroys the #ckmc_alias_info_list_s handle and releases resources of @@ -1053,6 +1092,38 @@ void ckmc_param_list_free(ckmc_param_list_h params); */ int ckmc_generate_new_params(ckmc_algo_type_e type, ckmc_param_list_h *pparams); +/** + * @brief Retrieves maximum data chunk size that can be passed to given backend. This is the maximum + * size of data passed for encryption/decryption. + * + * @since_tizen 6.5 + * + * @param[in] info Backend info handle + * @param[out] size Maximum chunk size + * + * @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 info is invalid, + * @a size = NULL) + * + * @see #ckmc_backend_info_h + * @see ckmc_get_backend_info() + */ +int ckmc_backend_get_max_chunk_size(const ckmc_backend_info_h info, size_t* size); + +/** + * @brief Destroys the backend information handle and releases all its resources. + * + * @since_tizen 6.5 + * + * @param[in] info Backend information handle created with ckmc_get_backend_info() + * + * @see #ckmc_backend_info_h + * @see ckmc_get_backend_info() + * @see ckmc_backend_get_max_chunk_size() + */ +void ckmc_backend_info_free(ckmc_backend_info_h info); + /** * @} diff --git a/src/manager/client-capi/ckmc-manager.cpp b/src/manager/client-capi/ckmc-manager.cpp index 1e12ee4..47bd944 100644 --- a/src/manager/client-capi/ckmc-manager.cpp +++ b/src/manager/client-capi/ckmc-manager.cpp @@ -37,7 +37,10 @@ namespace { const CKM::CertificateShPtrVector EMPTY_CERT_VECTOR; const CKM::AliasVector EMPTY_ALIAS_VECTOR; -int _ckmc_alias_info_new(const char* alias, bool is_password_protected, ckmc_alias_info_s** info) +int _ckmc_alias_info_new(const char* alias, + bool is_password_protected, + ckmc_backend_id_e backend, + ckmc_alias_info_s** info) { if (alias == NULL) return CKMC_ERROR_SERVER_ERROR; @@ -57,6 +60,7 @@ int _ckmc_alias_info_new(const char* alias, bool is_password_protected, ckmc_ali return CKMC_ERROR_OUT_OF_MEMORY; } _info->is_password_protected = is_password_protected; + _info->backend = backend; *info = _info; return CKMC_ERROR_NONE; } @@ -200,7 +204,7 @@ int _cryptoOperation(cryptoFn operation, return ckmc_buffer_new(outBuffer.data(), outBuffer.size(), ppout); } -int _toNewCkmcAliasInfoList(const CKM::AliasPwdVector &aliasPwdVector, +int _toNewCkmcAliasInfoList(const CKM::AliasInfoVector &aliasInfoVector, ckmc_alias_info_list_s **alias_info_list) { int ret = CKMC_ERROR_NONE; @@ -208,7 +212,7 @@ int _toNewCkmcAliasInfoList(const CKM::AliasPwdVector &aliasPwdVector, if (alias_info_list == nullptr) return CKMC_ERROR_UNKNOWN; - if (aliasPwdVector.size() == 0) { + if (aliasInfoVector.size() == 0) { *alias_info_list = nullptr; // according to documentation from header return CKMC_ERROR_DB_ALIAS_UNKNOWN; } @@ -217,7 +221,7 @@ int _toNewCkmcAliasInfoList(const CKM::AliasPwdVector &aliasPwdVector, ckmc_alias_info_list_s *plist = nullptr; ckmc_alias_info_list_s *previous = nullptr; - for (const auto &it : aliasPwdVector) { + for (const auto &it : aliasInfoVector) { previous = plist; @@ -235,7 +239,11 @@ int _toNewCkmcAliasInfoList(const CKM::AliasPwdVector &aliasPwdVector, if (previous != nullptr) previous->next = plist; - ret = _ckmc_alias_info_new(std::get<0>(it).c_str(), std::get<1>(it), &plist->info); + const auto& info = std::get<1>(it); + ret = _ckmc_alias_info_new(std::get<0>(it).c_str(), + info.passwordProtected, + static_cast(info.backend), + &plist->info); if (ret != CKMC_ERROR_NONE) break; } @@ -252,7 +260,7 @@ int _toNewCkmcAliasInfoList(const CKM::AliasPwdVector &aliasPwdVector, } int ckmc_generic_get_alias_info_list_helper(ckmc_alias_info_list_s **alias_info_list, - int(CKM::Manager::*func)(CKM::AliasPwdVector&)) + int(CKM::Manager::*func)(CKM::AliasInfoVector&)) { EXCEPTION_GUARD_START_CAPI @@ -262,12 +270,12 @@ int ckmc_generic_get_alias_info_list_helper(ckmc_alias_info_list_s **alias_info_ if (alias_info_list == nullptr) return CKMC_ERROR_INVALID_PARAMETER; - CKM::AliasPwdVector aliasPwdVector; + CKM::AliasInfoVector aliasInfoVector; - if ((ret = ((*mgr).*func)(aliasPwdVector)) != CKM_API_SUCCESS) + if ((ret = ((*mgr).*func)(aliasInfoVector)) != CKM_API_SUCCESS) return to_ckmc_error(ret); - if ((ret = _toNewCkmcAliasInfoList(aliasPwdVector, alias_info_list)) != CKM_API_SUCCESS) + if ((ret = _toNewCkmcAliasInfoList(aliasInfoVector, alias_info_list)) != CKM_API_SUCCESS) return ret; return CKMC_ERROR_NONE; @@ -400,7 +408,7 @@ int ckmc_get_key_alias_info_list(ckmc_alias_info_list_s **alias_info_list) { return ckmc_generic_get_alias_info_list_helper(alias_info_list, - &CKM::Manager::getKeyAliasPwdVector); + &CKM::Manager::getKeyAliasInfoVector); } KEY_MANAGER_CAPI @@ -464,7 +472,7 @@ KEY_MANAGER_CAPI int ckmc_get_cert_alias_info_list(ckmc_alias_info_list_s **alias_info_list) { return ckmc_generic_get_alias_info_list_helper(alias_info_list, - &CKM::Manager::getCertificateAliasPwdVector); + &CKM::Manager::getCertificateAliasInfoVector); } KEY_MANAGER_CAPI @@ -621,7 +629,7 @@ KEY_MANAGER_CAPI int ckmc_get_data_alias_info_list(ckmc_alias_info_list_s **alias_info_list) { return ckmc_generic_get_alias_info_list_helper(alias_info_list, - &CKM::Manager::getDataAliasPwdVector); + &CKM::Manager::getDataAliasInfoVector); } KEY_MANAGER_CAPI @@ -1096,3 +1104,23 @@ int ckmc_export_wrapped_key(const ckmc_param_list_h params, return ret; EXCEPTION_GUARD_END } + +KEY_MANAGER_CAPI +int ckmc_get_backend_info(ckmc_backend_id_e backend, ckmc_backend_info_h* ppinfo) +{ + EXCEPTION_GUARD_START_CAPI + + if (backend < CKMC_BACKEND_SW || backend > CKMC_BACKEND_TZ || ppinfo == nullptr) + return CKMC_ERROR_INVALID_PARAMETER; + + // TODO get it + auto _info = static_cast(malloc(sizeof(__ckmc_backend_info_s))); + if (_info == nullptr) + return CKMC_ERROR_OUT_OF_MEMORY; + + *ppinfo = _info; + + return CKMC_ERROR_SERVER_ERROR; + + EXCEPTION_GUARD_END +} diff --git a/src/manager/client-capi/ckmc-type.cpp b/src/manager/client-capi/ckmc-type.cpp index f79c2e1..fc7e431 100644 --- a/src/manager/client-capi/ckmc-type.cpp +++ b/src/manager/client-capi/ckmc-type.cpp @@ -616,7 +616,18 @@ int ckmc_alias_info_get_alias(const ckmc_alias_info_s* info, char** alias) } KEY_MANAGER_CAPI -int ckmc_alias_info_is_password_protected(const ckmc_alias_info_s* info, bool* is_password_protected) +int ckmc_alias_info_get_backend(const ckmc_alias_info_s* info, ckmc_backend_id_e* backend) +{ + if (info == NULL || backend == NULL) + return CKMC_ERROR_INVALID_PARAMETER; + + *backend = info->backend; + return CKMC_ERROR_NONE; +} + +KEY_MANAGER_CAPI +int ckmc_alias_info_is_password_protected(const ckmc_alias_info_s* info, + bool* is_password_protected) { if (info == NULL || is_password_protected == NULL) return CKMC_ERROR_INVALID_PARAMETER; @@ -838,3 +849,23 @@ int ckmc_generate_new_params(ckmc_algo_type_e type, ckmc_param_list_h *pparams) return CKMC_ERROR_NONE; } + +KEY_MANAGER_CAPI +int ckmc_backend_get_max_chunk_size(const ckmc_backend_info_h info, size_t* size) +{ + EXCEPTION_GUARD_START_CAPI + + if (info == nullptr || size == nullptr) + return CKMC_ERROR_INVALID_PARAMETER; + + *size = info->max_chunk_size; + return CKMC_ERROR_NONE; + + EXCEPTION_GUARD_END +} + +KEY_MANAGER_CAPI +void ckmc_backend_info_free(ckmc_backend_info_h info) +{ + free(info); +} diff --git a/src/manager/client/client-common.h b/src/manager/client/client-common.h index 35f57f9..98fe38f 100644 --- a/src/manager/client/client-common.h +++ b/src/manager/client/client-common.h @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -45,8 +46,12 @@ extern "C" { struct ckmc_alias_info_s { char* alias; bool is_password_protected; + ckmc_backend_id_e backend; }; + struct __ckmc_backend_info_s { + size_t max_chunk_size; + }; } namespace CKM { diff --git a/src/manager/client/client-manager-impl.cpp b/src/manager/client/client-manager-impl.cpp index 14173e1..540c93f 100644 --- a/src/manager/client/client-manager-impl.cpp +++ b/src/manager/client/client-manager-impl.cpp @@ -385,8 +385,8 @@ int Manager::Impl::getBinaryDataAliasVector(DataType dataType, EXCEPTION_GUARD_END } -int Manager::Impl::getBinaryDataAliasPwdVector(DataType dataType, - AliasPwdVector &aliasPwdVector) +int Manager::Impl::getBinaryDataAliasInfoVector(DataType dataType, + AliasInfoVector &aliasInfoVector) { EXCEPTION_GUARD_START_CPPAPI OwnerNameVector ownerNameVector; @@ -405,7 +405,8 @@ int Manager::Impl::getBinaryDataAliasPwdVector(DataType dataType, if (retCode != CKM_API_SUCCESS) return retCode; - aliasPwdVector.push_back(std::make_pair(alias, status)); + // TODO get the actual backend + aliasInfoVector.push_back(std::make_pair(alias, AliasInfo({status, BackendId::SW}))); } return CKM_API_SUCCESS; EXCEPTION_GUARD_END @@ -428,9 +429,9 @@ int Manager::Impl::getDataAliasVector(AliasVector &aliasVector) return getBinaryDataAliasVector(DataType::BINARY_DATA, aliasVector); } -int Manager::Impl::getKeyAliasPwdVector(AliasPwdVector &aliasPwdVector) +int Manager::Impl::getKeyAliasInfoVector(AliasInfoVector &aliasInfoVector) { - return getBinaryDataAliasPwdVector(DataType::DB_KEY_LAST, aliasPwdVector); + return getBinaryDataAliasInfoVector(DataType::DB_KEY_LAST, aliasInfoVector); } int Manager::Impl::getKeyEncryptionStatus(const Alias &alias, bool &status) @@ -438,9 +439,9 @@ int Manager::Impl::getKeyEncryptionStatus(const Alias &alias, bool &status) return getBinaryDataEncryptionStatus(DataType::DB_KEY_LAST, alias, status); } -int Manager::Impl::getCertificateAliasPwdVector(AliasPwdVector &aliasPwdVector) +int Manager::Impl::getCertificateAliasInfoVector(AliasInfoVector &aliasInfoVector) { - return getBinaryDataAliasPwdVector(DataType::CERTIFICATE, aliasPwdVector); + return getBinaryDataAliasInfoVector(DataType::CERTIFICATE, aliasInfoVector); } int Manager::Impl::getCertificateEncryptionStatus(const Alias &alias, bool &status) @@ -448,9 +449,9 @@ int Manager::Impl::getCertificateEncryptionStatus(const Alias &alias, bool &stat return getBinaryDataEncryptionStatus(DataType::CERTIFICATE, alias, status); } -int Manager::Impl::getDataAliasPwdVector(AliasPwdVector &aliasPwdVector) +int Manager::Impl::getDataAliasInfoVector(AliasInfoVector &aliasInfoVector) { - return getBinaryDataAliasPwdVector(DataType::BINARY_DATA, aliasPwdVector); + return getBinaryDataAliasInfoVector(DataType::BINARY_DATA, aliasInfoVector); } int Manager::Impl::getDataEncryptionStatus(const Alias &alias, bool &status) diff --git a/src/manager/client/client-manager-impl.h b/src/manager/client/client-manager-impl.h index fb06743..c10b6b4 100644 --- a/src/manager/client/client-manager-impl.h +++ b/src/manager/client/client-manager-impl.h @@ -35,7 +35,7 @@ public: int saveKey(const Alias &alias, const KeyShPtr &key, const Policy &policy); int getKey(const Alias &alias, const Password &password, KeyShPtr &key); int getKeyAliasVector(AliasVector &aliasVector); - int getKeyAliasPwdVector(AliasPwdVector &aliasPwdVector); + int getKeyAliasInfoVector(AliasInfoVector &aliasInfoVector); int getKeyEncryptionStatus(const Alias &alias, bool &status); int saveCertificate(const Alias &alias, const CertificateShPtr &cert, @@ -43,14 +43,14 @@ public: int getCertificate(const Alias &alias, const Password &password, CertificateShPtr &cert); int getCertificateAliasVector(AliasVector &aliasVector); - int getCertificateAliasPwdVector(AliasPwdVector &aliasPwdVector); + int getCertificateAliasInfoVector(AliasInfoVector &aliasInfoVector); int getCertificateEncryptionStatus(const Alias &alias, bool &status); int saveData(const Alias &alias, const RawBuffer &rawData, const Policy &policy); int getData(const Alias &alias, const Password &password, RawBuffer &cert); int getDataAliasVector(AliasVector &aliasVector); - int getDataAliasPwdVector(AliasPwdVector &aliasPwdVector); + int getDataAliasInfoVector(AliasInfoVector &aliasInfoVector); int getDataEncryptionStatus(const Alias &alias, bool &status); int savePKCS12( @@ -184,9 +184,9 @@ private: DataType sendDataType, OwnerNameVector &ownerNameVector); - int getBinaryDataAliasPwdVector( + int getBinaryDataAliasInfoVector( DataType sendDataType, - AliasPwdVector &aliasPwdVector); + AliasInfoVector &aliasInfoVector); int createKeyPair( const KeyType key_type, diff --git a/src/manager/client/client-manager.cpp b/src/manager/client/client-manager.cpp index 71be983..ee0d368 100644 --- a/src/manager/client/client-manager.cpp +++ b/src/manager/client/client-manager.cpp @@ -117,9 +117,9 @@ int Manager::getKeyAliasVector(AliasVector &aliasVector) return m_impl->getKeyAliasVector(aliasVector); } -int Manager::getKeyAliasPwdVector(AliasPwdVector &aliasPwdVector) +int Manager::getKeyAliasInfoVector(AliasInfoVector &aliasInfoVector) { - return m_impl->getKeyAliasPwdVector(aliasPwdVector); + return m_impl->getKeyAliasInfoVector(aliasInfoVector); } int Manager::getCertificateAliasVector(AliasVector &aliasVector) @@ -127,9 +127,9 @@ int Manager::getCertificateAliasVector(AliasVector &aliasVector) return m_impl->getCertificateAliasVector(aliasVector); } -int Manager::getCertificateAliasPwdVector(AliasPwdVector &aliasPwdVector) +int Manager::getCertificateAliasInfoVector(AliasInfoVector &aliasInfoVector) { - return m_impl->getCertificateAliasPwdVector(aliasPwdVector); + return m_impl->getCertificateAliasInfoVector(aliasInfoVector); } int Manager::getDataAliasVector(AliasVector &aliasVector) @@ -137,9 +137,9 @@ int Manager::getDataAliasVector(AliasVector &aliasVector) return m_impl->getDataAliasVector(aliasVector); } -int Manager::getDataAliasPwdVector(AliasPwdVector &aliasPwdVector) +int Manager::getDataAliasInfoVector(AliasInfoVector &aliasInfoVector) { - return m_impl->getDataAliasPwdVector(aliasPwdVector); + return m_impl->getDataAliasInfoVector(aliasInfoVector); } int Manager::createKeyPairRSA( -- 2.7.4 From eec9291ef51f719cf24d1f65cf7ed9ec63bf76d3 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Mon, 8 May 2023 20:43:51 +0200 Subject: [PATCH 03/16] Fix default value for KBKDF LLEN parameter Change the default value of CKMC_PARAM_KBKDF_LLEN from 0 to 32 according to API description. Change-Id: I972d95227b047394c5f59addc9242d43c9c68be7 --- src/manager/crypto/sw-backend/internals.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/manager/crypto/sw-backend/internals.cpp b/src/manager/crypto/sw-backend/internals.cpp index 9796b2e..26a5f33 100644 --- a/src/manager/crypto/sw-backend/internals.cpp +++ b/src/manager/crypto/sw-backend/internals.cpp @@ -1040,7 +1040,7 @@ Data deriveKBKDF(const RawBuffer &secret, const CryptoAlgorithm &alg) RawBuffer label, context, fixed; KbkdfCounterLocation counterLocation; KdfPrf prf; - size_t length, rlenBits = 32, llenBits = 0, tmp; + size_t length, rlenBits = 32, llenBits = 32, tmp; bool hasLabel = alg.getParam(ParamName::KBKDF_LABEL, label); bool hasContext = alg.getParam(ParamName::KBKDF_CONTEXT, context); bool hasFixed = alg.getParam(ParamName::KBKDF_FIXED_INPUT, fixed); @@ -1048,7 +1048,7 @@ Data deriveKBKDF(const RawBuffer &secret, const CryptoAlgorithm &alg) alg.getParam(ParamName::KDF_PRF, prf); alg.getParam(ParamName::KDF_LEN, length); alg.getParam(ParamName::KBKDF_RLEN, rlenBits); - alg.getParam(ParamName::KBKDF_LLEN, llenBits); + bool hasLLen = alg.getParam(ParamName::KBKDF_LLEN, llenBits); bool useSeparator = !alg.getParam(ParamName::KBKDF_NO_SEPARATOR, tmp); const EVP_MD* md = nullptr; @@ -1068,7 +1068,7 @@ Data deriveKBKDF(const RawBuffer &secret, const CryptoAlgorithm &alg) RawBuffer key; if (hasFixed) { - if (hasLabel || hasContext || !useSeparator || llenBits > 0 || + if (hasLabel || hasContext || !useSeparator || hasLLen || counterLocation == KbkdfCounterLocation::MIDDLE_FIXED) ThrowErr(Exc::Crypto::InputParam, "Unexpected parameters for fixed input mode."); -- 2.7.4 From 2bbadc1a86d85db0ad29ff26725e05c99629c312 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Tue, 16 May 2023 15:35:30 +0200 Subject: [PATCH 04/16] Fix backend selection logic In some cases the backend selection was not working properly: - Key derivation, wrapped key import: the backend compatibility was not checked at all. This resulted in a possibility of saving an exportable key in TZ backend which normally is not allowed. - Encrypted initial values could have been imported to incompatible SW backend if the TZ backend fails to initialize or the SW backend is forced. The Decider API was also unclear and different policies were in force depending on the usecase. This commit introduces following changes: * Keep the policy in a single place. * Return a prioritized list of backends compatible with given use case. * Add backend check to key derivation and wrapped key import. * Do not assume SW backend is suitable for all cases. * Handle illegal cases by returning empty list of compatible backends. Change-Id: I2d5dbbb3c4ba9385ac756eb419f95ac877cdd532 --- src/manager/common/data-type.h | 2 +- src/manager/crypto/platform/decider.cpp | 161 ++++++++++++++++++++------------ src/manager/crypto/platform/decider.h | 15 ++- src/manager/service/ckm-logic.cpp | 30 ++++-- 4 files changed, 139 insertions(+), 69 deletions(-) diff --git a/src/manager/common/data-type.h b/src/manager/common/data-type.h index 33884b7..017e214 100644 --- a/src/manager/common/data-type.h +++ b/src/manager/common/data-type.h @@ -81,7 +81,7 @@ public: bool isKey() const; /* - * Number of times someone mistook it for isKey() (or the opposite): 3 + * Number of times someone mistook it for isKey() (or the opposite): 4 * Increase the counter if it happened to you. * I will rename this function if the counter reaches 4. */ diff --git a/src/manager/crypto/platform/decider.cpp b/src/manager/crypto/platform/decider.cpp index 9109fb2..8dca91c 100644 --- a/src/manager/crypto/platform/decider.cpp +++ b/src/manager/crypto/platform/decider.cpp @@ -34,43 +34,6 @@ namespace CKM { namespace Crypto { -namespace { - -#ifdef TZ_BACKEND_ENABLED -CryptoBackend tryGetTzBackend() -{ - try { - LogDebug("Trying to open TA session..."); - TZ::Internals::TrustZoneContext::Instance(); - } catch (const Exc::Crypto::InternalError& e) { - LogDebug("...failed. Selecting SW backend."); - return CryptoBackend::OpenSSL; - } - - LogDebug("...succeeded. Selecting TZ backend."); - return CryptoBackend::TrustZone; -} -#endif - -template -CryptoBackend chooseBackend(const Policy &policy, const ForceOpenSSL &forceOpenSSL) -{ -#ifdef TZ_BACKEND_ENABLED - switch (policy.backend) { - case CKM::PolicyBackend::FORCE_SOFTWARE: return CryptoBackend::OpenSSL; - case CKM::PolicyBackend::FORCE_HARDWARE: return CryptoBackend::TrustZone; - case CKM::PolicyBackend::DEFAULT: break; - } - return forceOpenSSL() ? CryptoBackend::OpenSSL : tryGetTzBackend(); -#else // TZ_BACKEND_ENABLED - (void)policy; - (void)forceOpenSSL; - return CryptoBackend::OpenSSL; -#endif // TZ_BACKEND_ENABLED -} - -} // namespace - Decider::Decider() : m_swStore(CryptoBackend::OpenSSL) #ifdef TZ_BACKEND_ENABLED @@ -81,43 +44,125 @@ Decider::Decider() GStore &Decider::getStore(const Token &token) { - return getStore(token.backendId); -}; - -GStore &Decider::getStore(CryptoBackend cryptoBackend) -{ GStore *gStore = NULL; - if (cryptoBackend == CryptoBackend::OpenSSL) + if (token.backendId == CryptoBackend::OpenSSL) gStore = &m_swStore; #ifdef TZ_BACKEND_ENABLED - if (cryptoBackend == CryptoBackend::TrustZone) + if (token.backendId == CryptoBackend::TrustZone) gStore = &m_tzStore; #endif if (gStore) return *gStore; ThrowErr(Exc::Crypto::InternalError, - "Backend not available. BackendId: ", (int)cryptoBackend); + "Backend not available. BackendId: ", + static_cast(token.backendId)); +}; + +GStore* Decider::tryBackend(CryptoBackend backend) +{ + switch(backend) { + case CryptoBackend::OpenSSL: + return &m_swStore; + case CryptoBackend::TrustZone: +#ifdef TZ_BACKEND_ENABLED + try { + LogDebug("Trying to open TA session..."); + TZ::Internals::TrustZoneContext::Instance(); + LogDebug("...succeeded. Selecting TZ backend."); + return &m_tzStore; + } catch (const Exc::Crypto::InternalError& e) { + LogDebug("...failed."); + } +#endif + default: + break; + } + return nullptr; +} + +/* + * operation encrypted type extractable backend + * ---------------------------------------------- + * import FALSE binary - TZ/SW + * skey FALSE TZ/SW + * skey TRUE SW + * akey - SW + * cert - SW + * TRUE binary - TZ + * skey FALSE TZ + * skey TRUE NONE + * akey - NONE + * cert - NONE + * generate - binary FALSE TZ/SW + * - binary TRUE SW + * - cert - NONE + * - skey FALSE TZ/SW + * - skey TRUE SW + * - akey FALSE TZ/SW + * - akey TRUE SW + */ +std::deque Decider::getCompatibleBackends(DataType data, + const Policy &policy, + bool import, + bool encrypted) +{ + std::deque backends; + + auto addSW = [&]{ + if (policy.backend != CKM::PolicyBackend::FORCE_HARDWARE) + backends.push_back(CryptoBackend::OpenSSL); + }; + + auto addTZ = [&]{ +#ifdef TZ_BACKEND_ENABLED + if (policy.backend != CKM::PolicyBackend::FORCE_SOFTWARE) + backends.push_front(CryptoBackend::TrustZone); +#endif + }; + + if (import) { + if (!encrypted) + addSW(); + + if (data.isBinaryData() || (data.isSKey() && !policy.extractable)) + addTZ(); + } else { // generate/derive + assert(!encrypted); + + if (!data.isCertificate() && !data.isChainCert()) { + addSW(); + + if (!policy.extractable) + addTZ(); + } + } + return backends; } -GStore &Decider::getStore(DataType data, const Policy &policy, bool encrypted) +GStore &Decider::getStore(DataType data, const Policy &policy, bool import, bool encrypted) { - return getStore(chooseBackend(policy, [&]{ - return !encrypted && !data.isBinaryData() && ( - // tz-backend allows only for data binary export - policy.extractable || - // Use TrustZone only with symmetric keys or unencrypted binary - // data until asymmetric cryptography is implemented - !data.isSKey() - ); - })); + auto backends = getCompatibleBackends(data, policy, import, encrypted); + if (backends.empty()) + ThrowErr(Exc::Crypto::InputParam, "No backend supports this operation."); + + for (auto id : backends) { + auto backend = tryBackend(id); + if (backend != nullptr) + return *backend; + } + ThrowErr(Exc::Crypto::InternalError, "Failed to connect to a compatible backend."); } -GStore &Decider::getStore(const Policy &policyPrv) +bool Decider::checkStore(CryptoBackend requestedBackend, DataType data, const Policy &policy, bool import) { - // extractable private key can only be handled by OpenSSL - return getStore(chooseBackend(policyPrv, [&]{ return policyPrv.extractable; })); + auto backends = getCompatibleBackends(data, policy, import); + for (auto id : backends) { + if (id == requestedBackend) + return true; + } + return false; } } // namespace Crypto diff --git a/src/manager/crypto/platform/decider.h b/src/manager/crypto/platform/decider.h index 08ab78e..3315e76 100644 --- a/src/manager/crypto/platform/decider.h +++ b/src/manager/crypto/platform/decider.h @@ -20,6 +20,8 @@ */ #pragma once +#include + #include #include @@ -40,11 +42,18 @@ class Decider final { public: Decider(); GStore &getStore(const Token &token); - GStore &getStore(DataType data, const Policy &policy, bool encrypted = false); - GStore &getStore(const Policy &policyPrv); + GStore &getStore(DataType data, + const Policy &policy, + bool import = true, + bool encrypted = false); + bool checkStore(CryptoBackend id, DataType data, const Policy &policy, bool import); private: - GStore &getStore(CryptoBackend id); + GStore* tryBackend(CryptoBackend backend); + std::deque getCompatibleBackends(DataType data, + const Policy &policy, + bool import = true, + bool encrypted = false); SW::Store m_swStore; #ifdef TZ_BACKEND_ENABLED diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index 21f0ac3..a5b158e 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -1028,7 +1028,7 @@ int CKMLogic::importInitialData( if (retCode != CKM_API_SUCCESS) return retCode; - Crypto::GStore &store = m_decider.getStore(data.type, policy, !encParams.iv.empty()); + Crypto::GStore &store = m_decider.getStore(data.type, policy, true, !encParams.iv.empty()); Token token; if (encParams.iv.empty()) { @@ -1177,7 +1177,8 @@ RawBuffer CKMLogic::createKeyPair( bool exportable = policyPrv.extractable || policyPub.extractable; Policy lessRestricted(Password(), exportable, policyPrv.backend); - TokenPair keys = m_decider.getStore(policyPrv).generateAKey( + // For now any asymmetric key will do. If necessary we can extract it from keyGenParams. + TokenPair keys = m_decider.getStore(DataType::DB_KEY_FIRST, policyPrv, false).generateAKey( keyGenParams, policyPrv.password, policyPub.password, @@ -1210,9 +1211,9 @@ RawBuffer CKMLogic::createKeyAES( CryptoAlgorithm keyGenAlgorithm; keyGenAlgorithm.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GEN); keyGenAlgorithm.setParam(ParamName::GEN_KEY_LEN, size); - Token key = m_decider.getStore(DataType::KEY_AES, policy).generateSKey(keyGenAlgorithm, - policy.password, - digest); + + auto& store = m_decider.getStore(DataType::KEY_AES, policy, false); + Token key = store.generateSKey(keyGenAlgorithm, policy.password, digest); dbOp.finalize(std::move(key), policy); return CKM_API_SUCCESS; @@ -1537,14 +1538,15 @@ RawBuffer CKMLogic::deriveKey( return SerializeMessage(msgID, tryRet([&] { // Get key/secret for internal service use. It won't be exported to the client Crypto::GObjUPtr obj; + DataType objType; int retCode = readDataHelper(false, cred, DataType::DB_KEY_FIRST, - secretName, secretOwner, secretPassword, obj); + secretName, secretOwner, secretPassword, obj, objType); if (retCode != CKM_API_SUCCESS) { if (retCode != CKM_API_ERROR_DB_ALIAS_UNKNOWN) return retCode; retCode = readDataHelper(false, cred, DataType::BINARY_DATA, - secretName, secretOwner, secretPassword, obj); + secretName, secretOwner, secretPassword, obj, objType); if (retCode != CKM_API_SUCCESS) return retCode; } @@ -1553,6 +1555,14 @@ RawBuffer CKMLogic::deriveKey( if (ret != CKM_API_SUCCESS) return ret; + // ECDH (private key) -> binary secret, KBKDF -> symmetric key + DataType newKeyType = objType.isKeyPrivate() ? DataType::BINARY_DATA : DataType::KEY_AES; + if (!m_decider.checkStore(obj->backendId(), newKeyType, newKeyPolicy, false)) { + LogDebug("Can't import the derived key to backend " << + static_cast(obj->backendId()) << " with given policy"); + return CKM_API_ERROR_INPUT_PARAM; + } + // derive Token derived = obj->derive(params, newKeyPolicy.password, digest); @@ -1587,6 +1597,12 @@ RawBuffer CKMLogic::importWrappedKey( if (retCode != CKM_API_SUCCESS) return retCode; + if (!m_decider.checkStore(wrappingKey->backendId(), keyType, policy, true)) { + LogDebug("Can't import the wrapped key to backend " << + static_cast(wrappingKey->backendId()) << " with given policy"); + return CKM_API_ERROR_INPUT_PARAM; + } + Token token = wrappingKey->unwrap(params, Crypto::Data(keyType, std::move(wrappedKey)), policy.password, -- 2.7.4 From dcfdfe65365199420d8faf184df14c48e532ba75 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 18 May 2023 14:50:41 +0200 Subject: [PATCH 05/16] Rename DataType::isSKey Change-Id: I59e553cbf067baf3ad7209e07e5376b6601c5a6a --- src/manager/client-async/storage-receiver.cpp | 2 +- src/manager/client/client-manager-impl.cpp | 4 ++-- src/manager/common/data-type.cpp | 2 +- src/manager/common/data-type.h | 8 +------- src/manager/crypto/platform/decider.cpp | 2 +- src/manager/crypto/sw-backend/obj.cpp | 2 +- src/manager/crypto/sw-backend/store.cpp | 2 +- src/manager/crypto/tz-backend/store.cpp | 2 +- src/manager/service/ckm-logic.cpp | 2 +- unit-tests/test_data-type.cpp | 4 ++-- unit-tests/test_sw-backend.cpp | 2 +- 11 files changed, 13 insertions(+), 19 deletions(-) diff --git a/src/manager/client-async/storage-receiver.cpp b/src/manager/client-async/storage-receiver.cpp index 6095d09..8e71e0a 100644 --- a/src/manager/client-async/storage-receiver.cpp +++ b/src/manager/client-async/storage-receiver.cpp @@ -125,7 +125,7 @@ void StorageReceiver::parseGetCommand() return; } - if (dataType.isSKey()) + if (dataType.isSymmetricKey()) m_observer->ReceivedKey(KeyAESImpl(rawData)); else if (dataType.isKey()) m_observer->ReceivedKey(KeyImpl(rawData)); diff --git a/src/manager/client/client-manager-impl.cpp b/src/manager/client/client-manager-impl.cpp index 540c93f..75da00f 100644 --- a/src/manager/client/client-manager-impl.cpp +++ b/src/manager/client/client-manager-impl.cpp @@ -310,7 +310,7 @@ int Manager::Impl::getKey(const Alias &alias, const Password &password, if (retCode != CKM_API_SUCCESS) return retCode; - KeyShPtr keyParsed = recvDataType.isSKey() ? Key::createAES(rawData) : Key::create(rawData); + KeyShPtr keyParsed = recvDataType.isSymmetricKey() ? Key::createAES(rawData) : Key::create(rawData); if (!keyParsed) { LogDebug("Key empty - failed to parse!"); @@ -819,7 +819,7 @@ int Manager::Impl::exportWrappedKey(const CryptoAlgorithm ¶ms, if (retCode != CKM_API_SUCCESS) return retCode; - if (dataTypeKey.isSKey()) { + if (dataTypeKey.isSymmetricKey()) { keyType = KeyType::KEY_AES; } else if (dataTypeKey.isKeyPrivate()) { keyType = KeyType::KEY_RSA_PRIVATE; diff --git a/src/manager/common/data-type.cpp b/src/manager/common/data-type.cpp index c70175f..e59bd3f 100644 --- a/src/manager/common/data-type.cpp +++ b/src/manager/common/data-type.cpp @@ -106,7 +106,7 @@ bool DataType::isKey() const return false; } -bool DataType::isSKey() const +bool DataType::isSymmetricKey() const { return (KEY_AES == m_dataType); } diff --git a/src/manager/common/data-type.h b/src/manager/common/data-type.h index 017e214..1866204 100644 --- a/src/manager/common/data-type.h +++ b/src/manager/common/data-type.h @@ -79,13 +79,7 @@ public: operator int() const; bool isKey() const; - - /* - * Number of times someone mistook it for isKey() (or the opposite): 4 - * Increase the counter if it happened to you. - * I will rename this function if the counter reaches 4. - */ - bool isSKey() const; + bool isSymmetricKey() const; bool isChainCert() const; bool isKeyPrivate() const; bool isKeyPublic() const; diff --git a/src/manager/crypto/platform/decider.cpp b/src/manager/crypto/platform/decider.cpp index 8dca91c..ddfc373 100644 --- a/src/manager/crypto/platform/decider.cpp +++ b/src/manager/crypto/platform/decider.cpp @@ -126,7 +126,7 @@ std::deque Decider::getCompatibleBackends(DataType data, if (!encrypted) addSW(); - if (data.isBinaryData() || (data.isSKey() && !policy.extractable)) + if (data.isBinaryData() || (data.isSymmetricKey() && !policy.extractable)) addTZ(); } else { // generate/derive assert(!encrypted); diff --git a/src/manager/crypto/sw-backend/obj.cpp b/src/manager/crypto/sw-backend/obj.cpp index 49d0616..97ea75c 100644 --- a/src/manager/crypto/sw-backend/obj.cpp +++ b/src/manager/crypto/sw-backend/obj.cpp @@ -78,7 +78,7 @@ Token Key::unwrap(const CryptoAlgorithm ¶ms, } // validate the decrypted key - if (wrappedKey.type.isSKey()) { + if (wrappedKey.type.isSymmetricKey()) { auto tmp = CKM::Key::createAES(decrypted); if (!tmp) ThrowErr(Exc::Crypto::InputParam, "Wrapped data is not a valid AES key"); diff --git a/src/manager/crypto/sw-backend/store.cpp b/src/manager/crypto/sw-backend/store.cpp index 7d610f7..30776f5 100644 --- a/src/manager/crypto/sw-backend/store.cpp +++ b/src/manager/crypto/sw-backend/store.cpp @@ -94,7 +94,7 @@ GObjUPtr Store::getObject(const Token &token, const Password &pass) if (token.dataType.isKeyPrivate() || token.dataType.isKeyPublic()) return make(std::move(data), token.dataType); - if (token.dataType.isSKey()) + if (token.dataType.isSymmetricKey()) return make(std::move(data), token.dataType); if (token.dataType.isCertificate() || token.dataType.isChainCert()) diff --git a/src/manager/crypto/tz-backend/store.cpp b/src/manager/crypto/tz-backend/store.cpp index ff992ed..302fd2a 100644 --- a/src/manager/crypto/tz-backend/store.cpp +++ b/src/manager/crypto/tz-backend/store.cpp @@ -71,7 +71,7 @@ GObjUPtr Store::getObject(const Token &token, const Password &pass) if (token.dataType.isKeyPrivate() || token.dataType.isKeyPublic()) return make(scheme, std::move(id), Pwd(pass, iv, tag), token.dataType); - if (token.dataType.isSKey()) + if (token.dataType.isSymmetricKey()) return make(scheme, std::move(id), Pwd(pass, iv, tag), token.dataType); if (token.dataType.isCertificate() || token.dataType.isChainCert()) diff --git a/src/manager/service/ckm-logic.cpp b/src/manager/service/ckm-logic.cpp index a5b158e..0d0a06b 100644 --- a/src/manager/service/ckm-logic.cpp +++ b/src/manager/service/ckm-logic.cpp @@ -81,7 +81,7 @@ int toBinaryData(const Crypto::Data &input, Crypto::Data &output) if (input.type.isKey()) { KeyShPtr output_key; - if (input.type.isSKey()) + if (input.type.isSymmetricKey()) output_key = CKM::Key::createAES(input.data); else output_key = CKM::Key::create(input.data); diff --git a/unit-tests/test_data-type.cpp b/unit-tests/test_data-type.cpp index a237d6a..984e151 100644 --- a/unit-tests/test_data-type.cpp +++ b/unit-tests/test_data-type.cpp @@ -86,8 +86,8 @@ POSITIVE_TEST_CASE(KEY_TYPE_CASTING) POSITIVE_TEST_CASE(UNARY_OPERATIONS) { - BOOST_REQUIRE(DataType(DataType::KEY_AES).isSKey()); - BOOST_REQUIRE(!DataType(DataType::KEY_RSA_PUBLIC).isSKey()); + BOOST_REQUIRE(DataType(DataType::KEY_AES).isSymmetricKey()); + BOOST_REQUIRE(!DataType(DataType::KEY_RSA_PUBLIC).isSymmetricKey()); BOOST_REQUIRE(DataType(DataType::DB_CHAIN_FIRST).isChainCert()); BOOST_REQUIRE(DataType(DataType::DB_CHAIN_LAST).isChainCert()); diff --git a/unit-tests/test_sw-backend.cpp b/unit-tests/test_sw-backend.cpp index a4e6077..19879ae 100644 --- a/unit-tests/test_sw-backend.cpp +++ b/unit-tests/test_sw-backend.cpp @@ -74,7 +74,7 @@ void checkKey(const Token& token, KeyType keyType, const Password& pass) BOOST_REQUIRE(!data.empty()); KeyShPtr key; - if (dataType.isSKey()) + if (dataType.isSymmetricKey()) key = CKM::Key::createAES(data); else key = CKM::Key::create(data); -- 2.7.4 From 61b910797b706b3e8494eb5841e4462bf1356125 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Tue, 23 May 2023 08:45:16 +0200 Subject: [PATCH 06/16] Test proper GCM IV length handling GCM implementation was using only the first 12B of IV regardless of its actual length. This modification makes the test check if the remaining bytes of the IV are ignored. Change-Id: I94281747bbe9363854484844fa038ae9bcd47a19 --- src/manager/crypto/generic-backend/crypto-params.h | 1 + unit-tests/test_sw-backend.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/manager/crypto/generic-backend/crypto-params.h b/src/manager/crypto/generic-backend/crypto-params.h index ae23fba..41a4461 100644 --- a/src/manager/crypto/generic-backend/crypto-params.h +++ b/src/manager/crypto/generic-backend/crypto-params.h @@ -27,6 +27,7 @@ class Params { public: static const size_t DEFAULT_AES_IV_LEN = 16; // max acceptable size of IV + static const size_t DEFAULT_AES_GCM_IV_LEN = 12; // default size of IV in GCM mode static const int DEFAULT_AES_GCM_TAG_LEN_BYTES = 16; // length of AES GCM tag static const int DEFAULT_AES_GCM_TAG_LEN_BITS = DEFAULT_AES_GCM_TAG_LEN_BYTES * 8; static const int DERIVED_KEY_LENGTH = 16; // length of AES key derived from password in bytes diff --git a/unit-tests/test_sw-backend.cpp b/unit-tests/test_sw-backend.cpp index 19879ae..7c6a760 100644 --- a/unit-tests/test_sw-backend.cpp +++ b/unit-tests/test_sw-backend.cpp @@ -645,9 +645,17 @@ NEGATIVE_TEST_CASE(symmetricEncryptDecryptGcm) // wrong iv auto wrongIv = iv; - wrongIv[0] ^= 0x1; + wrongIv[iv.size() - 1] ^= 0x1; ca2.setParam(ParamName::ED_IV, wrongIv); BOOST_REQUIRE_THROW(key->decrypt(ca2, encrypted), Exc::Crypto::InputParam); + + // shortened iv + auto shortenedIv = iv; + static_assert(Params::DEFAULT_AES_GCM_IV_LEN < Params::DEFAULT_AES_IV_LEN); + shortenedIv.resize(Params::DEFAULT_AES_GCM_IV_LEN); + ca2.setParam(ParamName::ED_IV, shortenedIv); + BOOST_REQUIRE_THROW(key->decrypt(ca2, encrypted), Exc::Crypto::InputParam); + ca2.setParam(ParamName::ED_IV, iv); // wrong ciphertext -- 2.7.4 From 1e6e268703fc313a973f06581e21cf62c112e903 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Mon, 22 May 2023 21:29:17 +0200 Subject: [PATCH 07/16] Fix GCM IV length setting IV length was not properly set in case of GCM. The default 12B IV was used at all times. GCM supports 1 to 2^64-1 byte long IVs. Reflect it in the SW backend implementation, its tests and client API description. Change-Id: Idfa18c1c3cfd06de6618b4ac7632133ace6ab8dc --- src/include/ckmc/ckmc-type.h | 5 +++-- .../crypto/generic-backend/algo-validation.h | 15 ++++++++++++++ src/manager/crypto/sw-backend/crypto.h | 23 +++++++++++++++++----- src/manager/crypto/sw-backend/internals.cpp | 3 ++- unit-tests/test_crypto-logic.cpp | 5 ----- unit-tests/test_sw-backend.cpp | 12 +++++------ 6 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/include/ckmc/ckmc-type.h b/src/include/ckmc/ckmc-type.h index 54c1f06..192598b 100644 --- a/src/include/ckmc/ckmc-type.h +++ b/src/include/ckmc/ckmc-type.h @@ -293,7 +293,7 @@ typedef struct __ckmc_pkcs12 { typedef enum __ckmc_param_name { CKMC_PARAM_ALGO_TYPE = 1, /**< integer - type of algorithm (see #ckmc_algo_type_e) */ - CKMC_PARAM_ED_IV = 101, /**< 16B buffer (up to 2^64-1 bytes long in case of AES GCM) */ + CKMC_PARAM_ED_IV = 101, /**< buffer - initialization vector */ CKMC_PARAM_ED_CTR_LEN, /**< integer - ctr length in bits*/ CKMC_PARAM_ED_AAD, /**< buffer - Additional Authentication Data for AES GCM */ CKMC_PARAM_ED_TAG_LEN, /**< integer - tag length in bits */ @@ -418,7 +418,8 @@ typedef enum __ckmc_algo_type { CKMC_ALGO_AES_GCM, /**< AES-GCM algorithm Supported parameters: - #CKMC_PARAM_ALGO_TYPE = #CKMC_ALGO_AES_GCM (mandatory), - - #CKMC_PARAM_ED_IV = initialization vector (mandatory) + - #CKMC_PARAM_ED_IV = 1 to (2^64-1) bytes long initialization vector. + Recommended length is 12B (mandatory) - #CKMC_PARAM_ED_TAG_LEN = GCM tag length in bits. One of {32, 64, 96, 104, 112, 120, 128} (optional, if not present, the length 128 is used; since Tizen 5.0, if TrustZone backend is used, diff --git a/src/manager/crypto/generic-backend/algo-validation.h b/src/manager/crypto/generic-backend/algo-validation.h index dc14966..8946a35 100644 --- a/src/manager/crypto/generic-backend/algo-validation.h +++ b/src/manager/crypto/generic-backend/algo-validation.h @@ -98,6 +98,21 @@ struct Type { }; }; +// Validates as true if parameter value is equal or greater than Min +template +struct GreaterOrEqual { +public: + static bool Check(const T &value) + { + return value >= Min; + } + + static void Why(std::ostringstream &os) + { + os << "is smaller than " << static_cast(Min); + } +}; + template struct Unsupported { static bool Check(const T &) diff --git a/src/manager/crypto/sw-backend/crypto.h b/src/manager/crypto/sw-backend/crypto.h index 08ba272..a8a522e 100644 --- a/src/manager/crypto/sw-backend/crypto.h +++ b/src/manager/crypto/sw-backend/crypto.h @@ -80,12 +80,25 @@ public: ThrowErr(Exc::Crypto::InternalError, "Wrong key size! Expected: ", EVP_CIPHER_key_length(type), " Get: ", key.size()); - if (static_cast(iv.size()) < EVP_CIPHER_iv_length(type)) - ThrowErr(Exc::Crypto::InternalError, "Wrong iv size! Expected: ", - EVP_CIPHER_iv_length(type), " Get: ", iv.size()); + bool gcm = (EVP_CIPHER_mode(type) == EVP_CIPH_GCM_MODE); + int iv_len = EVP_CIPHER_iv_length(type); - OPENSSL_ERROR_HANDLE(EVP_CipherInit_ex(m_ctx, type, NULL, key.data(), iv.data(), - encryption ? 1 : 0)); + OPENSSL_ERROR_HANDLE(EVP_CipherInit_ex(m_ctx, type, NULL, NULL, NULL, encryption ? 1 : 0)); + + if (gcm) { + if (iv.empty()) + ThrowErr(Exc::Crypto::InternalError, "Empty iv provided!"); + + OPENSSL_ERROR_HANDLE( + EVP_CIPHER_CTX_ctrl(m_ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size(), NULL)); + } else { + if (static_cast(iv.size()) != iv_len) + ThrowErr(Exc::Crypto::InternalError, "Wrong iv size! Expected: ", iv_len, " Got: ", + iv.size()); + } + + OPENSSL_ERROR_HANDLE( + EVP_CipherInit_ex(m_ctx, NULL, NULL, key.data(), iv.data(), encryption ? 1 : 0)); EVP_CIPHER_CTX_set_padding(m_ctx, 1); } diff --git a/src/manager/crypto/sw-backend/internals.cpp b/src/manager/crypto/sw-backend/internals.cpp index 26a5f33..b6aecae 100644 --- a/src/manager/crypto/sw-backend/internals.cpp +++ b/src/manager/crypto/sw-backend/internals.cpp @@ -116,7 +116,8 @@ typedef ParamCheck> GcmIvCheck; + GreaterOrEqual, + BufferSizeGetter> GcmIvCheck; typedef ParamCheckencrypt(ca, data), Exc::Crypto::InputParam); - // short iv - ca.setParam(ParamName::ED_IV, RawBuffer(1)); - BOOST_REQUIRE_THROW(key->encrypt(ca, data), Exc::Crypto::InternalError); ca.setParam(ParamName::ED_IV, iv); // short key @@ -628,9 +631,6 @@ NEGATIVE_TEST_CASE(symmetricEncryptDecryptGcm) // no iv BOOST_REQUIRE_THROW(key->decrypt(ca2, encrypted), Exc::Crypto::InputParam); - // short iv - ca2.setParam(ParamName::ED_IV, RawBuffer(1)); - BOOST_REQUIRE_THROW(key->decrypt(ca2, encrypted), Exc::Crypto::InternalError); ca2.setParam(ParamName::ED_IV, iv); // short key -- 2.7.4 From d6606535ac51bb3e574312106088f3f15843536e Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Tue, 23 May 2023 11:07:23 +0200 Subject: [PATCH 08/16] Workaround for GCM IV length issue GCM implementation was ignoring IV bytes except first 12B. The issue has been fixed but we need to support the decryption of the data encrypted the old way. This workaround retries the decryption with an IV truncated to 12B if the decryption with original IV length fails. Unit-test included. Change-Id: Ia1c06d9a7c6f3b75a69c2e1cb3e5f0801776e057 --- src/manager/crypto/sw-backend/internals.cpp | 35 +++++++++++++++++--------- unit-tests/test_sw-backend.cpp | 38 +++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/src/manager/crypto/sw-backend/internals.cpp b/src/manager/crypto/sw-backend/internals.cpp index b6aecae..529f4f1 100644 --- a/src/manager/crypto/sw-backend/internals.cpp +++ b/src/manager/crypto/sw-backend/internals.cpp @@ -823,21 +823,34 @@ RawBuffer decryptDataAesGcm( const RawBuffer &tag, const RawBuffer &aad) { - EvpCipherPtr dec; - selectCipher(AlgoType::AES_GCM, key.size(), false)(dec, key, iv); - void *ptr = (void *)tag.data(); + RawBuffer result, tmp; - dec->Control(EVP_CTRL_GCM_SET_TAG, tag.size(), ptr); + auto decrypt = [&](const RawBuffer &actualIv){ + EvpCipherPtr dec; + selectCipher(AlgoType::AES_GCM, key.size(), false)(dec, key, actualIv); + void *ptr = (void *)tag.data(); - if (!aad.empty()) - dec->AppendAAD(aad); + dec->Control(EVP_CTRL_GCM_SET_TAG, tag.size(), ptr); + + if (!aad.empty()) + dec->AppendAAD(aad); + + result = dec->Append(data); + try { + tmp = dec->Finalize(); + } catch (const Exc::Exception &e) { + ThrowErr(Exc::InputParam, + "Tag authentication failed in AES finalize function (the tag doesn't match)."); + } + }; - RawBuffer result = dec->Append(data); - RawBuffer tmp; try { - tmp = dec->Finalize(); - } catch (const Exc::Exception &e) { - ThrowErr(Exc::InputParam, "Tag authentication failed in AES finalize function (the tag doesn't match)."); + decrypt(iv); + } catch (const Exc::InputParam &e) { + LogDebug("AES GCM decryption failed. Retry with default iv length."); + RawBuffer shortIv = iv; + shortIv.resize(Params::DEFAULT_AES_GCM_IV_LEN); + decrypt(shortIv); } std::copy(tmp.begin(), tmp.end(), std::back_inserter(result)); return result; diff --git a/unit-tests/test_sw-backend.cpp b/unit-tests/test_sw-backend.cpp index 9fd0264..c064340 100644 --- a/unit-tests/test_sw-backend.cpp +++ b/unit-tests/test_sw-backend.cpp @@ -675,6 +675,44 @@ NEGATIVE_TEST_CASE(symmetricEncryptDecryptGcm) BOOST_REQUIRE_THROW(key->decrypt(ca2, encrypted), Exc::Crypto::InputParam); } +POSITIVE_TEST_CASE(gcmIvLengthScrewUpWorkaround) +{ + const auto key = generateAes(128); + const auto data = createRandom(128); + const auto iv = createRandom(Params::DEFAULT_AES_IV_LEN); + CryptoAlgorithm ca; + RawBuffer encrypted, decrypted; + auto shortIv = iv; + shortIv.resize(Params::DEFAULT_AES_GCM_IV_LEN); + + ca.setParam(ParamName::ALGO_TYPE, AlgoType::AES_GCM); + ca.setParam(ParamName::ED_IV, shortIv); + ca.setParam(ParamName::ED_TAG_LEN, 128); + + // encrypt with 12B IV + BOOST_REQUIRE_NO_THROW(encrypted = key->encrypt(ca, data)); + + // decrypt with 12B IV + BOOST_REQUIRE_NO_THROW(decrypted = key->decrypt(ca, encrypted)); + BOOST_REQUIRE(decrypted == data); + + // decrypt with 16B IV should also succeed (workaround) + ca.setParam(ParamName::ED_IV, iv); + BOOST_REQUIRE_NO_THROW(decrypted = key->decrypt(ca, encrypted)); + BOOST_REQUIRE(decrypted == data); + + // encrypt with 16B IV + BOOST_REQUIRE_NO_THROW(encrypted = key->encrypt(ca, data)); + + // decrypt with 16B IV + BOOST_REQUIRE_NO_THROW(decrypted = key->decrypt(ca, encrypted)); + BOOST_REQUIRE(decrypted == data); + + // decrypt with 12B IV should fail + ca.setParam(ParamName::ED_IV, shortIv); + BOOST_REQUIRE_THROW(key->decrypt(ca, encrypted), Exc::Crypto::InputParam); +} + NEGATIVE_TEST_CASE(symmetricEncryptDecryptCtr) { const auto key = generateAes(128); -- 2.7.4 From 478c26b4861d643caa6552ccb2de433ac31d563c Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 18 May 2023 13:50:04 +0200 Subject: [PATCH 09/16] Add missing KBKDF params in TZ backend Change-Id: I4cadca649889190c30868c55a2e91c9f49252d84 --- src/manager/crypto/tz-backend/internals.cpp | 7 +++++++ src/manager/crypto/tz-backend/tz-context.cpp | 17 +++++++++++++++-- src/manager/crypto/tz-backend/tz-context.h | 3 +++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/manager/crypto/tz-backend/internals.cpp b/src/manager/crypto/tz-backend/internals.cpp index d732c4c..51bce1d 100644 --- a/src/manager/crypto/tz-backend/internals.cpp +++ b/src/manager/crypto/tz-backend/internals.cpp @@ -755,6 +755,10 @@ void deriveKBKDF(const RawBuffer &secret, RawBuffer &keyTag, const RawBuffer &keyHash) { + RawBuffer label, context, fixed; + alg.getParam(ParamName::KBKDF_LABEL, label); + alg.getParam(ParamName::KBKDF_CONTEXT, context); + alg.getParam(ParamName::KBKDF_FIXED_INPUT, fixed); auto prf = unpack(alg, ParamName::KDF_PRF); auto mode = unpack(alg, ParamName::KBKDF_MODE); auto location = unpack(alg, ParamName::KBKDF_COUNTER_LOCATION); @@ -767,6 +771,9 @@ void deriveKBKDF(const RawBuffer &secret, RawBuffer keyPwdBuf(keyPwd.begin(), keyPwd.end()); TrustZoneContext::Instance().executeKbkdf(secret, + label, + context, + fixed, toTzPrf(prf), toTzKbkdfMode(mode), toTzCtrLoc(location), diff --git a/src/manager/crypto/tz-backend/tz-context.cpp b/src/manager/crypto/tz-backend/tz-context.cpp index bf603c9..06e9706 100644 --- a/src/manager/crypto/tz-backend/tz-context.cpp +++ b/src/manager/crypto/tz-backend/tz-context.cpp @@ -801,6 +801,9 @@ void TrustZoneContext::executeEcdh(const RawBuffer &prvKeyId, } void TrustZoneContext::executeKbkdf(const RawBuffer& secret, + const RawBuffer& label, + const RawBuffer& context, + const RawBuffer& fixed, tz_prf prf, tz_kbkdf_mode mode, tz_kbkdf_ctr_loc location, @@ -815,8 +818,18 @@ void TrustZoneContext::executeKbkdf(const RawBuffer& secret, // command ID = CMD_DERIVE LogDebug("TrustZoneContext::executeKbkdf"); - auto sIn = makeSerializer( - secret, prf, mode, location, rlen, llen, noSeparator, EncPwd{keyPwdBuf, keyPwdIV}, keyHash); + auto sIn = makeSerializer(secret, + label, + context, + fixed, + prf, + mode, + location, + rlen, + llen, + noSeparator, + EncPwd{keyPwdBuf, keyPwdIV}, keyHash); + TrustZoneMemory inMemory(m_Context, sIn.GetSize(), TEEC_MEM_INPUT); sIn.Serialize(inMemory); diff --git a/src/manager/crypto/tz-backend/tz-context.h b/src/manager/crypto/tz-backend/tz-context.h index e48e642..bee3dd5 100644 --- a/src/manager/crypto/tz-backend/tz-context.h +++ b/src/manager/crypto/tz-backend/tz-context.h @@ -167,6 +167,9 @@ public: const RawBuffer &secretHash); void executeKbkdf(const RawBuffer& secret, + const RawBuffer& label, + const RawBuffer& context, + const RawBuffer& fixed, tz_prf prf, tz_kbkdf_mode mode, tz_kbkdf_ctr_loc location, -- 2.7.4 From 5ed9b80ed58d265913172f7f3bb6d42431d4cc78 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Mon, 22 May 2023 22:12:35 +0200 Subject: [PATCH 10/16] Allow generating unexportable binary data in TZ TZ backend already supports importing exportable binary data. Follow the same rule for secret derivation and allow storing an exportable secret (binary data), derived from TZ key, in TZ. Change-Id: I61d202469a3df43e5f35746a0c09ca179d823336 --- src/manager/crypto/platform/decider.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/manager/crypto/platform/decider.cpp b/src/manager/crypto/platform/decider.cpp index ddfc373..ff67a1e 100644 --- a/src/manager/crypto/platform/decider.cpp +++ b/src/manager/crypto/platform/decider.cpp @@ -95,8 +95,7 @@ GStore* Decider::tryBackend(CryptoBackend backend) * skey TRUE NONE * akey - NONE * cert - NONE - * generate - binary FALSE TZ/SW - * - binary TRUE SW + * generate - binary - TZ/SW * - cert - NONE * - skey FALSE TZ/SW * - skey TRUE SW @@ -134,7 +133,7 @@ std::deque Decider::getCompatibleBackends(DataType data, if (!data.isCertificate() && !data.isChainCert()) { addSW(); - if (!policy.extractable) + if (data.isBinaryData() || !policy.extractable) addTZ(); } } -- 2.7.4 From bf0a202bd62b029103922b92c27f9a5c76fb5503 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 18 May 2023 12:16:03 +0200 Subject: [PATCH 11/16] Update ckmc_generate_new_params with new algorithms Change-Id: I094372d55a89a9fe5b7c212bd8c2e2dc7e325c11 --- src/manager/client-capi/ckmc-type.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/manager/client-capi/ckmc-type.cpp b/src/manager/client-capi/ckmc-type.cpp index fc7e431..e385355 100644 --- a/src/manager/client-capi/ckmc-type.cpp +++ b/src/manager/client-capi/ckmc-type.cpp @@ -828,6 +828,10 @@ int ckmc_generate_new_params(ckmc_algo_type_e type, ckmc_param_list_h *pparams) // no iv by default break; + case CKMC_ALGO_KBKDF: + case CKMC_ALGO_ECDH: + break; + default: ret = CKMC_ERROR_INVALID_PARAMETER; break; -- 2.7.4 From 96cbbf19ea601d1053a0615884fe4841452eb7d8 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Mon, 15 May 2023 14:44:43 +0200 Subject: [PATCH 12/16] Improve AAD and GCM tag handling in cipher API * AAD may also be a subject of backend chunk size limitation. Allow calling ckmc_cipher_init multiple time do provide consecutive AAD portions. * When encrypted data is split in to chunks there's no way to locate the trailing GCM tag part. Add optional buffer argument to ckmc_cipher_finalize() to allow passing the tag explicitly. This function will also return the tag in the output buffer during encryption. Change-Id: Ic9ddb86e294f8180fb44327c1f4ac4f4650b3e4c --- src/include/ckmc/ckmc-manager.h | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/include/ckmc/ckmc-manager.h b/src/include/ckmc/ckmc-manager.h index 6edbe51..7febfd7 100644 --- a/src/include/ckmc/ckmc-manager.h +++ b/src/include/ckmc/ckmc-manager.h @@ -1008,8 +1008,8 @@ int ckmc_remove_alias(const char *alias); * and at least 500 kB. For RSA the size must be smaller or equal to key size * in bytes - 42. * Example: for 1024 RSA key the maximum data size is 1024/8 - 42 = 86. - * @param[out] ppencrypted Encrypted data (some algorithms may return additional information - * embedded in encrypted data. AES GCM is an example) + * @param[out] ppencrypted Encrypted data. In #CKMC_ALGO_AES_GCM mode it includes the GCM tag + * appended at the end. * * @return @c 0 on success, otherwise a negative error value * @retval #CKMC_ERROR_NONE Successful @@ -1062,10 +1062,10 @@ int ckmc_encrypt_data(ckmc_param_list_h params, * @param[in] key_alias Alias of the key to be used for encryption * @param[in] password The password used in decrypting a key value. If password of the policy is * provided in ckmc_save_key(), the same password should be provided - * @param[in] encrypted Data to be decrypted (some algorithms may require additional information - * embedded in encrypted data. AES GCM is an example) Since Tizen 5.0, on - * chosen images where module is using TEE backend, data size is limited to at - * least 500 kB (TEE implementation-specific). + * @param[in] encrypted Data to be decrypted. #CKMC_ALGO_AES_GCM mode requires GCM tag to be + * appended at the end. Since Tizen 5.0, on chosen images where module is using + * TEE backend, data size is limited to at least 500 kB (TEE + * implementation-specific). * @param[out] ppdecrypted Decrypted data * * @return @c 0 on success, otherwise a negative error value @@ -1126,7 +1126,8 @@ int ckmc_decrypt_data(ckmc_param_list_h params, * @param[in] wrapping_key_alias The name of the wrapping key. * @param[in] wrapping_key_password An optional password of the wrapping key * @param[in] alias The name of a key to be stored - * @param[in] wrapped_key The wrapped key to be unwrapped and stored + * @param[in] wrapped_key The wrapped key to be unwrapped and stored. #CKMC_ALGO_AES_GCM mode + * requires GCM tag to be appended at the end of the @a wrapped_key. * @param[in] policy The policy about how to store a key securely * * @return @c 0 on success, otherwise a negative error value @@ -1181,7 +1182,8 @@ int ckmc_import_wrapped_key(const ckmc_param_list_h params, * @param[in] wrapping_key_password An optional password of the wrapping key * @param[in] alias The name of the key to be wrapped and exported * @param[in] password An optional password used to decrypt the key pointed by @a alias - * @param[out] ppwrapped_key The wrapped key + * @param[out] ppwrapped_key The wrapped key. In #CKMC_ALGO_AES_GCM mode it includes the GCM tag + * appended at the end. * * @return @c 0 on success, otherwise a negative error value * @retval #CKMC_ERROR_NONE Successful @@ -1271,6 +1273,9 @@ int ckmc_key_derive(const ckmc_param_list_h params, * longer needed. * @remarks To perform the encryption/decryption, one or more calls to ckmc_cipher_update() must be * folowed by one call to ckmc_cipher_finalize(). + * @remarks To pass #CKMC_PARAM_ED_AAD in multiple chunks call the ckmc_cipher_initialize() multiple + * times with consecutive portions of the AAD in the @a params and the @a context returned + * from the first call. It must be done before the first call to ckmc_cipher_update(). * * @param[in] params Algorithm parameter list handle. See #ckmc_param_list_h and #ckmc_algo_type_e * for details. Supported algorithms: @@ -1278,7 +1283,8 @@ int ckmc_key_derive(const ckmc_param_list_h params, * @param[in] key_alias Alias of the key to be used for encryption/decryption * @param[in] key_password Optional password of the key used for encryption/decryption * @param[in] encrypt Encryption/decryption switch (true=encryption, false=decryption) - * @param[out] context Encryption/decryption context + * @param[out] context Encryption/decryption context. Must point to NULL if it's the first call. + * Otherwise, it must point to the previously returned context. * * @return @c 0 on success, otherwise a negative error value * @retval #CKMC_ERROR_NONE Successful @@ -1343,8 +1349,12 @@ int ckmc_cipher_update(ckmc_cipher_ctx_h context, * @remarks After the call to this function the ckmc_cipher_update() can be called no more. * @remarks The newly created @a ppout must be destroyed using ckmc_buffer_free() when it's no * longer needed. + * @remarks When using #CKMC_ALGO_AES_GCM decryption the GCM tag must be passed as @a in. In other + * cases @a in should be set to NULL. + * @remarks When using #CKMC_ALGO_AES_GCM encryption the GCM tag will be returned in @a ppout. * * @param[in] context Encryption/decryption context created with ckmc_cipher_initialize() + * @param[in] in Optional additional decryption input required by some of the modes. * @param[out] ppout Encryption/decryption output * * @return @c 0 on success, otherwise a negative error value @@ -1358,7 +1368,9 @@ int ckmc_cipher_update(ckmc_cipher_ctx_h context, * @see ckmc_cipher_update() * @see ckmc_cipher_free() */ -int ckmc_cipher_finalize(ckmc_cipher_ctx_h context, ckmc_raw_buffer_s **ppout); +int ckmc_cipher_finalize(ckmc_cipher_ctx_h context, + const ckmc_raw_buffer_s *in, + ckmc_raw_buffer_s **ppout); /** * @brief Destroys the encryption/decryption context and releases all its resources. -- 2.7.4 From 137a4778a3d222948221ca08d400f371645f0191 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 24 May 2023 11:02:48 +0200 Subject: [PATCH 13/16] Update cipher api description Encryption may return an empty buffer. Specify the return value in such case. Change-Id: Iabcbe30dc002d4dc7eb932fdbd5418263488ba2a --- src/include/ckmc/ckmc-manager.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/ckmc/ckmc-manager.h b/src/include/ckmc/ckmc-manager.h index 7febfd7..76cca21 100644 --- a/src/include/ckmc/ckmc-manager.h +++ b/src/include/ckmc/ckmc-manager.h @@ -1324,7 +1324,7 @@ int ckmc_cipher_initialize(ckmc_param_list_h params, * * @param[in] context Encryption/decryption context created with ckmc_cipher_initialize() * @param[in] in Encryption/decryption input - * @param[out] ppout Encryption/decryption output + * @param[out] ppout Encryption/decryption output. Will be set to NULL if the output is empty. * * @return @c 0 on success, otherwise a negative error value * @retval #CKMC_ERROR_NONE Successful @@ -1355,7 +1355,7 @@ int ckmc_cipher_update(ckmc_cipher_ctx_h context, * * @param[in] context Encryption/decryption context created with ckmc_cipher_initialize() * @param[in] in Optional additional decryption input required by some of the modes. - * @param[out] ppout Encryption/decryption output + * @param[out] ppout Encryption/decryption output. Will be set to NULL if the output is empty. * * @return @c 0 on success, otherwise a negative error value * @retval #CKMC_ERROR_NONE Successful -- 2.7.4 From 660ca6ddd808b22293cb06d1b4e51694190a4ab0 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 17 May 2023 14:35:13 +0200 Subject: [PATCH 14/16] Drop all encryption requests upon disconnection If client disconnects before finishing the request the request should be removed from the map. Change-Id: I7bb0fa71b12f0a07bac5e62e5191bd9729829bfe --- src/manager/service/encryption-logic.cpp | 10 ++++++++++ src/manager/service/encryption-logic.h | 2 +- src/manager/service/encryption-service.cpp | 8 ++++++++ src/manager/service/encryption-service.h | 8 ++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/manager/service/encryption-logic.cpp b/src/manager/service/encryption-logic.cpp index e3cf1d6..6698317 100644 --- a/src/manager/service/encryption-logic.cpp +++ b/src/manager/service/encryption-logic.cpp @@ -54,6 +54,16 @@ void EncryptionLogic::Crypt(const CryptoRequest &request) } } +void EncryptionLogic::DropRequests(const ConnectionID& connectionID) +{ + for (auto it = m_requestsMap.begin(); it != m_requestsMap.end();) { + if (it->second.conn.counter == connectionID.counter) + it = m_requestsMap.erase(it); + else + it++; + } +} + void EncryptionLogic::KeyRetrieved(MsgKeyResponse response) { auto it = m_requestsMap.find(response.id); diff --git a/src/manager/service/encryption-logic.h b/src/manager/service/encryption-logic.h index 7ae1e00..65c9d0d 100644 --- a/src/manager/service/encryption-logic.h +++ b/src/manager/service/encryption-logic.h @@ -37,7 +37,7 @@ public: void Crypt(const CryptoRequest &request); void KeyRetrieved(MsgKeyResponse response); - + void DropRequests(const ConnectionID& connectionID); private: IEncryptionService &m_service; diff --git a/src/manager/service/encryption-service.cpp b/src/manager/service/encryption-service.cpp index f642870..d254be4 100644 --- a/src/manager/service/encryption-service.cpp +++ b/src/manager/service/encryption-service.cpp @@ -152,4 +152,12 @@ void EncryptionService::CustomHandle(const SecurityEvent &/*event*/) LogError("This should not happend! SecurityEvent was called on EncryptionService!"); } +void EncryptionService::CustomHandle(const CloseEvent &event) +{ + // call the default handler + ThreadService::Handle(event); + + m_logic.DropRequests(event.connectionID); +} + } /* namespace CKM */ diff --git a/src/manager/service/encryption-service.h b/src/manager/service/encryption-service.h index 264b0fc..27a007f 100644 --- a/src/manager/service/encryption-service.h +++ b/src/manager/service/encryption-service.h @@ -55,6 +55,13 @@ public: }); } + virtual void Event(const CloseEvent &event) + { + CreateEvent([this, event]() { + this->CustomHandle(event); + }); + } + void Start(); void Stop(); @@ -62,6 +69,7 @@ protected: // CustomHandle is used to bypass security check void CustomHandle(const ReadEvent &event); void CustomHandle(const SecurityEvent &event); + void CustomHandle(const CloseEvent &event); private: virtual void SetCommManager(CommMgr *manager); -- 2.7.4 From bd23a18e279664632730e828f084b3bb959a5435 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Wed, 26 Apr 2023 23:11:33 +0200 Subject: [PATCH 15/16] Cipher API implementation (client part) Change-Id: I191f606819ae306f570fe538674f943e336ec86f --- src/include/ckm/ckm-manager.h | 8 ++ src/manager/client-capi/ckmc-manager.cpp | 131 +++++++++++++++++++++++++++++ src/manager/client/client-manager-impl.cpp | 53 ++++++++++++ src/manager/client/client-manager-impl.h | 8 ++ src/manager/client/client-manager.cpp | 22 ++++- src/manager/common/protocols.h | 5 +- 6 files changed, 225 insertions(+), 2 deletions(-) diff --git a/src/include/ckm/ckm-manager.h b/src/include/ckm/ckm-manager.h index 8076456..dd91e99 100644 --- a/src/include/ckm/ckm-manager.h +++ b/src/include/ckm/ckm-manager.h @@ -192,6 +192,14 @@ public: KeyType &keyType, RawBuffer &wrappedKey); + int initializeCipher(const CryptoAlgorithm ¶ms, + const Alias &keyAlias, + const Password &keyPassword, + bool encrypt, + int& requestId); + int updateCipher(int requestId, const RawBuffer &in, RawBuffer &out); + int finalizeCipher(int requestId, const RawBuffer &in, RawBuffer &out); + static ManagerShPtr create(); private: diff --git a/src/manager/client-capi/ckmc-manager.cpp b/src/manager/client-capi/ckmc-manager.cpp index 47bd944..9c9ca34 100644 --- a/src/manager/client-capi/ckmc-manager.cpp +++ b/src/manager/client-capi/ckmc-manager.cpp @@ -32,11 +32,18 @@ #include #include #include +#include namespace { const CKM::CertificateShPtrVector EMPTY_CERT_VECTOR; const CKM::AliasVector EMPTY_ALIAS_VECTOR; +struct CipherCtx +{ + CKM::ManagerShPtr mgr; + int requestId; +}; + int _ckmc_alias_info_new(const char* alias, bool is_password_protected, ckmc_backend_id_e backend, @@ -1124,3 +1131,127 @@ int ckmc_get_backend_info(ckmc_backend_id_e backend, ckmc_backend_info_h* ppinfo EXCEPTION_GUARD_END } + +KEY_MANAGER_CAPI +int ckmc_cipher_initialize(ckmc_param_list_h params, + const char *key_alias, + const char *key_password, + bool encrypt, + ckmc_cipher_ctx_h *context) +{ + if (params == nullptr || key_alias == nullptr || context == nullptr) + return CKMC_ERROR_INVALID_PARAMETER; + + const CKM::CryptoAlgorithm *ca = reinterpret_cast(params); + + EXCEPTION_GUARD_START_CAPI + + int ret = 0; + int requestId; + CKM::ManagerShPtr mgr; + + if (*context != nullptr) { + auto ctx = reinterpret_cast(*context); + requestId = ctx->requestId; + mgr = ctx->mgr; + } else { + requestId = 0; + mgr = CKM::Manager::create(); + } + + ret = to_ckmc_error(mgr->initializeCipher(*ca, + CKM::Alias(key_alias), + _tostring(key_password), + encrypt, + requestId)); + if (ret == CKMC_ERROR_NONE && *context == nullptr) { + auto ctx = new(std::nothrow)(CipherCtx); + ctx->mgr = mgr; + ctx->requestId = requestId; + *context = reinterpret_cast(ctx); + } + return ret; + + EXCEPTION_GUARD_END +} + +KEY_MANAGER_CAPI +int ckmc_cipher_update(ckmc_cipher_ctx_h context, + const ckmc_raw_buffer_s in, + ckmc_raw_buffer_s **ppout) +{ + if (context == nullptr || ppout == nullptr) + return CKMC_ERROR_INVALID_PARAMETER; + + EXCEPTION_GUARD_START_CAPI + + int ret = 0; + CKM::RawBuffer inBuffer(in.data, in.data + in.size); + CKM::RawBuffer outBuffer; + + auto ctx = reinterpret_cast(context); + ret = ctx->mgr->updateCipher(ctx->requestId, inBuffer, outBuffer); + if (ret != CKM_API_SUCCESS) + return to_ckmc_error(ret); + + if (outBuffer.empty()) { + *ppout = nullptr; + return CKMC_ERROR_NONE; + } + + return ckmc_buffer_new(outBuffer.data(), outBuffer.size(), ppout); + EXCEPTION_GUARD_END +} + +KEY_MANAGER_CAPI +int ckmc_cipher_finalize(ckmc_cipher_ctx_h context, + const ckmc_raw_buffer_s *in, + ckmc_raw_buffer_s **ppout) +{ + if (context == nullptr || ppout == nullptr) + return CKMC_ERROR_INVALID_PARAMETER; + + EXCEPTION_GUARD_START_CAPI + + int ret = 0; + CKM::RawBuffer outBuffer; + CKM::RawBuffer inBuffer; + + if (in != nullptr) + inBuffer.assign(in->data, in->data + in->size); + + auto ctx = reinterpret_cast(context); + ret = ctx->mgr->finalizeCipher(ctx->requestId, inBuffer, outBuffer); + if (ret != CKM_API_SUCCESS) + return to_ckmc_error(ret); + + if (outBuffer.empty()) { + *ppout = nullptr; + return CKMC_ERROR_NONE; + } + + return ckmc_buffer_new(outBuffer.data(), outBuffer.size(), ppout); + + EXCEPTION_GUARD_END +} + +KEY_MANAGER_CAPI +void ckmc_cipher_free(ckmc_cipher_ctx_h context) +{ + if (context == nullptr) + return; + + auto ctx = reinterpret_cast(context); + try { + ctx->mgr.reset(); + } catch (const std::exception &e) { + LogError("STD exception " << e.what()); + } catch (const abi::__forced_unwind &) { + LogDebug("abi::__forced_unwind caught. Thread cancelation."); + throw; + } catch (...) { + LogError("Unknown exception occured"); + } + + delete ctx; +} diff --git a/src/manager/client/client-manager-impl.cpp b/src/manager/client/client-manager-impl.cpp index 75da00f..9a89839 100644 --- a/src/manager/client/client-manager-impl.cpp +++ b/src/manager/client/client-manager-impl.cpp @@ -832,4 +832,57 @@ int Manager::Impl::exportWrappedKey(const CryptoAlgorithm ¶ms, EXCEPTION_GUARD_END } +int Manager::Impl::initializeCipher( + const CryptoAlgorithm ¶ms, + const Alias &keyAlias, + const Password &keyPassword, + bool encrypt, + int &requestId) +{ + EXCEPTION_GUARD_START_CPPAPI + + AliasSupport helper(keyAlias); + + return Request(*this, + EncryptionCommand::INITIALIZE_CIPHER, + m_encryptionConnection, + requestId, + CryptoAlgorithmSerializable(params), + helper.getName(), + helper.getOwner(), + keyPassword, + encrypt + ).maybeDeserialize(requestId); + + EXCEPTION_GUARD_END +} + +int Manager::Impl::updateCipher(int requestId, const RawBuffer &in, RawBuffer &out) +{ + EXCEPTION_GUARD_START_CPPAPI + + return Request(*this, + EncryptionCommand::UPDATE_CIPHER, + m_encryptionConnection, + requestId, + in + ).maybeDeserialize(out); + + EXCEPTION_GUARD_END +} + +int Manager::Impl::finalizeCipher(int requestId, const RawBuffer &in, RawBuffer &out) +{ + EXCEPTION_GUARD_START_CPPAPI + + return Request(*this, + EncryptionCommand::FINALIZE_CIPHER, + m_encryptionConnection, + requestId, + in + ).maybeDeserialize(out); + + EXCEPTION_GUARD_END +} + } // namespace CKM diff --git a/src/manager/client/client-manager-impl.h b/src/manager/client/client-manager-impl.h index c10b6b4..52ec1cc 100644 --- a/src/manager/client/client-manager-impl.h +++ b/src/manager/client/client-manager-impl.h @@ -157,6 +157,14 @@ public: KeyType &keyType, RawBuffer &wrappedKey); + int initializeCipher(const CryptoAlgorithm ¶ms, + const Alias &keyAlias, + const Password &keyPassword, + bool encrypt, + int &requestId); + int updateCipher(int requestId, const RawBuffer &in, RawBuffer &out); + int finalizeCipher(int requestId, const RawBuffer &in, RawBuffer &out); + private: int saveBinaryData( const Alias &alias, diff --git a/src/manager/client/client-manager.cpp b/src/manager/client/client-manager.cpp index ee0d368..46a822a 100644 --- a/src/manager/client/client-manager.cpp +++ b/src/manager/client/client-manager.cpp @@ -314,7 +314,7 @@ int Manager::importWrappedKey( ); } -int Manager::exportWrappedKey( +int Manager::exportWrappedKey( const CryptoAlgorithm ¶ms, const Alias &wrappingKeyAlias, const Password &wrappingKeyPassword, @@ -334,6 +334,26 @@ int Manager::exportWrappedKey( ); } +int Manager::initializeCipher( + const CryptoAlgorithm ¶ms, + const Alias &keyAlias, + const Password &keyPassword, + bool encrypt, + int& requestId) +{ + return m_impl->initializeCipher(params, keyAlias, keyPassword, encrypt, requestId); +} + +int Manager::updateCipher(int requestId, const RawBuffer &in, RawBuffer &out) +{ + return m_impl->updateCipher(requestId, in, out); +} + +int Manager::finalizeCipher(int requestId, const RawBuffer &in, RawBuffer &out) +{ + return m_impl->finalizeCipher(requestId, in, out); +} + ManagerShPtr Manager::create() { try { diff --git a/src/manager/common/protocols.h b/src/manager/common/protocols.h index 3b1cad8..4a2c2bb 100644 --- a/src/manager/common/protocols.h +++ b/src/manager/common/protocols.h @@ -74,7 +74,10 @@ enum class LogicCommand : int { enum class EncryptionCommand : int { ENCRYPT, - DECRYPT + DECRYPT, + INITIALIZE_CIPHER, + UPDATE_CIPHER, + FINALIZE_CIPHER }; // (client side) Alias = (service side) Owner::Name -- 2.7.4 From 0194f1a948870949e18f26ad5eed827b899cba40 Mon Sep 17 00:00:00 2001 From: Krzysztof Jackiewicz Date: Thu, 11 May 2023 14:32:56 +0200 Subject: [PATCH 16/16] Cipher API implementation (backend part) Change-Id: I7d2e5ef36a539a34f7e93a7fd9c16c90534d6aad --- misc/ckm_db_tool/CMakeLists.txt | 1 + src/CMakeLists.txt | 1 + src/manager/crypto/generic-backend/gctx.h | 36 +++++++++ src/manager/crypto/generic-backend/gobj.h | 7 ++ src/manager/crypto/sw-backend/crypto.h | 23 +++++- src/manager/crypto/sw-backend/ctx.cpp | 113 ++++++++++++++++++++++++++++ src/manager/crypto/sw-backend/ctx.h | 42 +++++++++++ src/manager/crypto/sw-backend/internals.cpp | 26 ++++++- src/manager/crypto/sw-backend/internals.h | 7 ++ src/manager/crypto/sw-backend/obj.cpp | 16 ++++ src/manager/crypto/sw-backend/obj.h | 2 + unit-tests/CMakeLists.txt | 1 + 12 files changed, 270 insertions(+), 5 deletions(-) create mode 100644 src/manager/crypto/generic-backend/gctx.h create mode 100644 src/manager/crypto/sw-backend/ctx.cpp create mode 100644 src/manager/crypto/sw-backend/ctx.h diff --git a/misc/ckm_db_tool/CMakeLists.txt b/misc/ckm_db_tool/CMakeLists.txt index 4cf1b3e..00b800e 100644 --- a/misc/ckm_db_tool/CMakeLists.txt +++ b/misc/ckm_db_tool/CMakeLists.txt @@ -29,6 +29,7 @@ SET(CKM_DB_TOOLS_SOURCES ${KEY_MANAGER_PATH}/crypto/sw-backend/obj.cpp ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp ${KEY_MANAGER_PATH}/crypto/sw-backend/kbkdf.cpp + ${KEY_MANAGER_PATH}/crypto/sw-backend/ctx.cpp ${KEY_MANAGER_PATH}/dpl/core/src/colors.cpp ${KEY_MANAGER_PATH}/dpl/db/src/naive_synchronization_object.cpp ${KEY_MANAGER_PATH}/dpl/db/src/sql_connection.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 21946dd..a9b1f15 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,6 +49,7 @@ SET(KEY_MANAGER_SOURCES ${KEY_MANAGER_PATH}/crypto/sw-backend/internals.cpp ${KEY_MANAGER_PATH}/crypto/sw-backend/store.cpp ${KEY_MANAGER_PATH}/crypto/sw-backend/kbkdf.cpp + ${KEY_MANAGER_PATH}/crypto/sw-backend/ctx.cpp ${KEY_MANAGER_PATH}/crypto/platform/decider.cpp ${SECURITY_MANAGER_WRAPPER_PATH} ${CYNARA_WRAPPER_PATH} diff --git a/src/manager/crypto/generic-backend/gctx.h b/src/manager/crypto/generic-backend/gctx.h new file mode 100644 index 0000000..bcee76f --- /dev/null +++ b/src/manager/crypto/generic-backend/gctx.h @@ -0,0 +1,36 @@ +/* + * 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 +#include + +namespace CKM { +namespace Crypto { + +class GCtx { +public: + virtual void customize(const CryptoAlgorithm& algo) = 0; + virtual RawBuffer update(const RawBuffer& input) = 0; + virtual RawBuffer finalize(const RawBuffer& input) = 0; + + virtual ~GCtx() {} +}; + +typedef std::shared_ptr GCtxShPtr; + +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/generic-backend/gobj.h b/src/manager/crypto/generic-backend/gobj.h index 8433e67..f67a0bb 100644 --- a/src/manager/crypto/generic-backend/gobj.h +++ b/src/manager/crypto/generic-backend/gobj.h @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -91,6 +92,12 @@ public: ThrowErr(Exc::Crypto::OperationNotSupported); } + // onward = true for encryption/signing, false for decryption/verification + virtual GCtxShPtr initContext(const CryptoAlgorithm &, bool /*onward*/) + { + ThrowErr(Exc::Crypto::OperationNotSupported); + } + virtual ~GObj() { } diff --git a/src/manager/crypto/sw-backend/crypto.h b/src/manager/crypto/sw-backend/crypto.h index a8a522e..0b49afd 100644 --- a/src/manager/crypto/sw-backend/crypto.h +++ b/src/manager/crypto/sw-backend/crypto.h @@ -45,9 +45,19 @@ struct Base { "Unsupported type inside conatainer."); } Base(const Base &) = delete; - Base(Base &&) = delete; + Base(Base &&other) { + this->m_ctx = other->m_ctx; + other->m_ctx = nullptr; + } Base &operator=(const Base &) = delete; - Base &operator=(Base &&) = delete; + Base &operator=(Base &&other) { + if (this == &other) + return *this; + + this->m_ctx = other->m_ctx; + other->m_ctx = nullptr; + return *this; + } // Low level api. // Allows various cipher specific parameters to be determined and set. @@ -63,6 +73,15 @@ struct Base { { EVP_CIPHER_CTX_free(m_ctx); } + int Mode() const + { + return EVP_CIPHER_CTX_mode(m_ctx); + } + + bool Encrypting() const + { + return (EVP_CIPHER_CTX_encrypting(m_ctx) == 1); + } protected: EVP_CIPHER_CTX *m_ctx; diff --git a/src/manager/crypto/sw-backend/ctx.cpp b/src/manager/crypto/sw-backend/ctx.cpp new file mode 100644 index 0000000..cffd4f4 --- /dev/null +++ b/src/manager/crypto/sw-backend/ctx.cpp @@ -0,0 +1,113 @@ +/* + * 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 +#include +#include + +namespace CKM { +namespace Crypto { + +namespace { +constexpr uint8_t STATE_INITIALIZED = 1; +constexpr uint8_t STATE_UPDATED = 2; +constexpr uint8_t STATE_FINALIZED = 3; +} + +CipherCtx::CipherCtx(SW::Internals::EvpCipherPtr&& ctx, int tagLen) : + m_ctx(std::move(ctx)), + m_tagLen(tagLen), + m_state(STATE_INITIALIZED) +{ +} + +void CipherCtx::customize(const CryptoAlgorithm& algo) +{ + if (m_ctx->Mode() != EVP_CIPH_GCM_MODE) + ThrowErr(Exc::InputParam, "Cipher mode does not support customization"); + + if (m_state > STATE_INITIALIZED) + ThrowErr(Exc::InputParam, "Customization is not allowed at this point"); + + RawBuffer aad; + if (!algo.getParam(ParamName::ED_AAD, aad)) + ThrowErr(Exc::InputParam, "Missing AAD"); + + m_ctx->AppendAAD(aad); +} + +RawBuffer CipherCtx::update(const RawBuffer& input) +{ + if (m_state > STATE_UPDATED) + ThrowErr(Exc::InputParam, "Update is not allowed at this point"); + m_state = STATE_UPDATED; + + return m_ctx->Append(input); +} + +RawBuffer CipherCtx::finalize(const RawBuffer& input) +{ + m_state = STATE_FINALIZED; + + auto mode = m_ctx->Mode(); + bool encrypting = m_ctx->Encrypting(); + + if (!input.empty()) { + if (mode != EVP_CIPH_GCM_MODE) + ThrowErr(Exc::InputParam, "Cipher mode does not support authentication tags"); + + if (encrypting) + ThrowErr(Exc::InputParam, "Authentication tag can only be provided during decryption."); + + // In case of GCM decryption input must be a complete tag only + m_ctx->Control(EVP_CTRL_GCM_SET_TAG, + input.size(), + const_cast(input.data())); + } + + RawBuffer ret; + try { + ret = m_ctx->Finalize(); + } catch (const Exc::Exception &) { + ThrowErr(Exc::InputParam, + "Tag authentication failed in AES finalize function (the tag doesn't match)."); + } + + if (mode != EVP_CIPH_GCM_MODE || !encrypting) + return ret; + + /* + * It is assumed that finalize for GCM encryption will return no data. Instead the complete GCM + * tag will be retrieved with a separate call and returned. + * + * https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption + * + * Finalise the encryption. Normally ciphertext bytes may be written at + * this stage, but this does not occur in GCM mode + * + * if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) + * ... + */ + if (!ret.empty()) + ThrowErr(Exc::InternalError, "Finalize() returned non-empty output for GCM."); + + RawBuffer tag(m_tagLen); + m_ctx->Control(EVP_CTRL_GCM_GET_TAG, m_tagLen, tag.data()); + return tag; +} + +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/sw-backend/ctx.h b/src/manager/crypto/sw-backend/ctx.h new file mode 100644 index 0000000..04f65a3 --- /dev/null +++ b/src/manager/crypto/sw-backend/ctx.h @@ -0,0 +1,42 @@ +/* + * 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 +#include +#include +#include +#include + +namespace CKM { +namespace Crypto { + +class CipherCtx : public GCtx { +public: + CipherCtx(SW::Internals::EvpCipherPtr&& ctx, int tagLen); + + void customize(const CryptoAlgorithm& algo) override; + RawBuffer update(const RawBuffer& input) override; + RawBuffer finalize(const RawBuffer& input) override; + +private: + SW::Internals::EvpCipherPtr m_ctx; + int m_tagLen; // in bytes, GCM only + uint8_t m_state; +}; + +} // namespace Crypto +} // namespace CKM diff --git a/src/manager/crypto/sw-backend/internals.cpp b/src/manager/crypto/sw-backend/internals.cpp index 529f4f1..77d1252 100644 --- a/src/manager/crypto/sw-backend/internals.cpp +++ b/src/manager/crypto/sw-backend/internals.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #include #include "kbkdf.h" @@ -285,8 +284,6 @@ void validateParams(const CryptoAlgorithm &ca) validator->Check(ca); } -typedef std::unique_ptr> EvpCipherPtr; - typedef std::function InitCipherFn; @@ -902,6 +899,29 @@ RawBuffer symmetricDecrypt(const RawBuffer &key, return decryptDataAes(algo, key, data, unpack(alg, ParamName::ED_IV)); } +EvpCipherPtr initCipher(const RawBuffer &key, const CryptoAlgorithm &alg, bool encrypt, int& tagLen) +{ + validateParams(alg); + AlgoType algo = unpack(alg, ParamName::ALGO_TYPE); + auto iv = unpack(alg, ParamName::ED_IV); + tagLen = 0; + + EvpCipherPtr cipher; + selectCipher(algo, key.size(), encrypt)(cipher, key, iv); + + if (algo == AlgoType::AES_GCM) { + int tagLenBits = Params::DEFAULT_AES_GCM_TAG_LEN_BITS; + alg.getParam(ParamName::ED_TAG_LEN, tagLenBits); + tagLen = tagLenBits / 8; + + RawBuffer aad; + alg.getParam(ParamName::ED_AAD, aad); + if (!aad.empty()) + cipher->AppendAAD(aad); + } + return cipher; +} + RawBuffer asymmetricEncrypt(const EvpShPtr &pkey, const CryptoAlgorithm &alg, const RawBuffer &data) diff --git a/src/manager/crypto/sw-backend/internals.h b/src/manager/crypto/sw-backend/internals.h index b2669a6..d91dddb 100644 --- a/src/manager/crypto/sw-backend/internals.h +++ b/src/manager/crypto/sw-backend/internals.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace CKM { namespace Crypto { @@ -37,6 +38,8 @@ struct Data { typedef std::pair DataPair; +typedef std::unique_ptr> EvpCipherPtr; + DataPair generateAKey(const CryptoAlgorithm &algorithm); Data generateSKey(const CryptoAlgorithm &algorithm); @@ -80,6 +83,10 @@ RawBuffer decryptDataAes(AlgoType type, const RawBuffer &key, const RawBuffer &data, const RawBuffer &iv); +EvpCipherPtr initCipher(const RawBuffer &key, + const CryptoAlgorithm &alg, + bool encrypt, + int& tagLen); RawBuffer sign(EVP_PKEY *pkey, const CryptoAlgorithm &alg, diff --git a/src/manager/crypto/sw-backend/obj.cpp b/src/manager/crypto/sw-backend/obj.cpp index 97ea75c..9043f83 100644 --- a/src/manager/crypto/sw-backend/obj.cpp +++ b/src/manager/crypto/sw-backend/obj.cpp @@ -18,6 +18,8 @@ * @author Bartłomiej Grzelewski (b.grzelewski@samsung.com) * @version 1.0 */ +#include + #include #include #include @@ -29,6 +31,7 @@ #include #include #include +#include #include namespace CKM { @@ -112,6 +115,14 @@ RawBuffer SKey::decrypt(const CryptoAlgorithm &alg, const RawBuffer &cipher) return Internals::symmetricDecrypt(getBinary(), alg, cipher); } +GCtxShPtr SKey::initContext(const CryptoAlgorithm &alg, bool onward) +{ + int tagLen = 0; + auto ctx = Internals::initCipher(getBinary(), alg, onward, tagLen); + + return std::make_shared(std::move(ctx), tagLen); +} + RawBuffer AKey::sign( const CryptoAlgorithm &alg, const RawBuffer &message) @@ -203,6 +214,11 @@ EvpShPtr AKey::getEvpShPtr() return m_evp; } +GCtxShPtr AKey::initContext(const CryptoAlgorithm &, bool) +{ + ThrowErr(Exc::Crypto::OperationNotSupported); +} + EvpShPtr Cert::getEvpShPtr() { if (m_evp) diff --git a/src/manager/crypto/sw-backend/obj.h b/src/manager/crypto/sw-backend/obj.h index 945a85f..697e4ff 100644 --- a/src/manager/crypto/sw-backend/obj.h +++ b/src/manager/crypto/sw-backend/obj.h @@ -70,6 +70,7 @@ public: RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &) override; RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &) override; + GCtxShPtr initContext(const CryptoAlgorithm &, bool) override; }; class AKey : public Key { @@ -83,6 +84,7 @@ public: RawBuffer encrypt(const CryptoAlgorithm &, const RawBuffer &) override; RawBuffer decrypt(const CryptoAlgorithm &, const RawBuffer &) override; Token derive(const CryptoAlgorithm &, const Password &, const RawBuffer &) override; + GCtxShPtr initContext(const CryptoAlgorithm &, bool) override; protected: virtual EvpShPtr getEvpShPtr(); diff --git a/unit-tests/CMakeLists.txt b/unit-tests/CMakeLists.txt index 349e221..b862516 100644 --- a/unit-tests/CMakeLists.txt +++ b/unit-tests/CMakeLists.txt @@ -115,6 +115,7 @@ SET(UNIT_TESTS_SOURCES ${MANAGER_PATH}/crypto/sw-backend/obj.cpp ${MANAGER_PATH}/crypto/sw-backend/store.cpp ${MANAGER_PATH}/crypto/sw-backend/kbkdf.cpp + ${MANAGER_PATH}/crypto/sw-backend/ctx.cpp ${MANAGER_PATH}/dpl/core/src/binary_queue.cpp ${MANAGER_PATH}/dpl/core/src/colors.cpp ${MANAGER_PATH}/dpl/core/src/errno_string.cpp -- 2.7.4