* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "hitls_build.h"
#ifdef HITLS_CRYPTO_PROVIDER
#include <string.h>
#include "bsl_err_internal.h"
#include "bsl_list.h"
#include "eal_drbg_local.h"
#include "crypt_eal_entropy.h"
#include "crypt_errno.h"
#include "crypt_drbg.h"
#include "crypt_provider_local.h"
#include "crypt_provider.h"
#include "crypt_utils.h"
static CRYPT_EAL_LibCtx *g_libCtx = NULL;
CRYPT_EAL_LibCtx *CRYPT_EAL_GetGlobalLibCtx(void)
{
return g_libCtx;
}
int32_t CRYPT_EAL_ProviderGetFuncs(CRYPT_EAL_LibCtx *libCtx, int32_t operaId, int32_t algId,
const char *attribute, const CRYPT_EAL_Func **funcs, void **provCtx)
{
CRYPT_EAL_ProvMgrCtx *mgrCtx = NULL;
int32_t ret = CRYPT_EAL_ProviderGetFuncsAndMgrCtx(libCtx, operaId, algId, attribute, funcs, &mgrCtx, false);
if (ret != CRYPT_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
if (mgrCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_NOT_FOUND);
return CRYPT_PROVIDER_NOT_FOUND;
}
if (provCtx != NULL) {
*provCtx = mgrCtx->provCtx;
}
return CRYPT_SUCCESS;
}
int32_t CRYPT_EAL_ProviderGetFuncsAndMgrCtx(CRYPT_EAL_LibCtx *libCtx, int32_t operaId, int32_t algId,
const char *attribute, const CRYPT_EAL_Func **funcs, CRYPT_EAL_ProvMgrCtx **mgrCtx, bool noPushError)
{
if (funcs == NULL || mgrCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
CRYPT_EAL_LibCtx *localCtx = GetCurrentProviderLibCtx(libCtx);
if (localCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_NULL_INPUT);
return CRYPT_NULL_INPUT;
}
if (attribute != NULL && strlen(attribute) > (INT32_MAX >> 1)) {
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_ERR_ATTRIBUTE);
return CRYPT_PROVIDER_ERR_ATTRIBUTE;
}
return CRYPT_EAL_CompareAlgAndAttr(localCtx, operaId, algId, attribute, funcs, mgrCtx, noPushError);
}
int32_t CRYPT_EAL_ProvMgrCtrl(CRYPT_EAL_ProvMgrCtx *ctx, int32_t cmd, void *val, uint32_t valLen)
{
(void)valLen;
if (ctx == NULL || val == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_INVALID_ARG);
return CRYPT_INVALID_ARG;
}
switch (cmd) {
#ifdef HITLS_CRYPTO_ENTROPY_DEFAULT
case CRYPT_EAL_MGR_GETSEEDCTX:
*(void **)val = ctx->providerSeed.seed;
return CRYPT_SUCCESS;
#endif
case CRYPT_EAL_MGR_GETLIBCTX:
*(void **)val = ctx->libCtx;
return CRYPT_SUCCESS;
default:
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_NOT_FOUND);
return CRYPT_PROVIDER_NOT_FOUND;
}
}
static void MountMgrMethod(CRYPT_EAL_Func *funcs, CRYPT_EAL_ProvMgrCtx *ctx)
{
for (uint32_t i = 0; funcs[i].id != 0; i++) {
switch (funcs[i].id) {
case CRYPT_EAL_PROVCB_FREE:
ctx->provFreeCb = (CRYPT_EAL_ProvFreeCb)funcs[i].func;
break;
case CRYPT_EAL_PROVCB_QUERY:
ctx->provQueryCb = (CRYPT_EAL_ProvQueryCb)funcs[i].func;
break;
case CRYPT_EAL_PROVCB_CTRL:
ctx->provCtrlCb = (CRYPT_EAL_ProvCtrlCb)funcs[i].func;
break;
case CRYPT_EAL_PROVCB_GETCAPS:
ctx->provGetCap = (CRYPT_EAL_ProvGetCapsCb)funcs[i].func;
break;
default:
break;
}
}
}
#ifdef HITLS_CRYPTO_ENTROPY_DEFAULT
static void ProviderSeedDeinit(EAL_SeedDrbg *seedDrbg)
{
if (seedDrbg == NULL) {
return;
}
if (seedDrbg->seed != NULL) {
EAL_SeedDrbgRandDeinit(seedDrbg->seed);
seedDrbg->seed = NULL;
CRYPT_EAL_SeedPoolFree(seedDrbg->seedCtx);
seedDrbg->seedCtx = NULL;
BSL_SAL_ReferencesFree(&(seedDrbg->references));
memset(seedDrbg, 0, sizeof(EAL_SeedDrbg));
}
}
#endif
int32_t CRYPT_EAL_InitProviderMethod(CRYPT_EAL_ProvMgrCtx *ctx, BSL_Param *param,
CRYPT_EAL_ImplProviderInit providerInit)
{
int32_t ret;
#ifdef HITLS_CRYPTO_ENTROPY_DEFAULT
CRYPT_RandSeedMethod method = {0};
EAL_SeedDrbgEntropyMeth(&method);
ctx->providerSeed.id = HITLS_SEED_DRBG_INIT_RAND_ALG;
RETURN_RET_IF_ERR(EAL_SeedDrbgInit(&(ctx->providerSeed)), ret);
#endif
CRYPT_EAL_Func capFuncs[] = {
#ifdef HITLS_CRYPTO_ENTROPY_DEFAULT
{CRYPT_EAL_CAP_GETENTROPY, method.getEntropy},
{CRYPT_EAL_CAP_CLEANENTROPY, method.cleanEntropy},
{CRYPT_EAL_CAP_GETNONCE, method.getNonce},
{CRYPT_EAL_CAP_CLEANNONCE, method.cleanNonce},
#endif
{CRYPT_EAL_CAP_MGRCTXCTRL, CRYPT_EAL_ProvMgrCtrl},
CRYPT_EAL_FUNC_END
};
CRYPT_EAL_Func *outFuncs = NULL;
GOTO_ERR_IF(providerInit(ctx, param, capFuncs, &outFuncs, &ctx->provCtx), ret);
if (outFuncs == NULL) {
ret = CRYPT_PROVIDER_ERR_UNEXPECTED_IMPL;
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_ERR_UNEXPECTED_IMPL);
goto ERR;
}
MountMgrMethod(outFuncs, ctx);
if (ctx->provQueryCb == NULL) {
if (ctx->provFreeCb != NULL) {
ctx->provFreeCb(ctx->provCtx);
ctx->provCtx = NULL;
}
ret = CRYPT_PROVIDER_ERR_IMPL_NULL;
BSL_ERR_PUSH_ERROR(CRYPT_PROVIDER_ERR_IMPL_NULL);
goto ERR;
}
return CRYPT_SUCCESS;
ERR:
#ifdef HITLS_CRYPTO_ENTROPY_DEFAULT
ProviderSeedDeinit(&(ctx->providerSeed));
#endif
return ret;
}
CRYPT_EAL_LibCtx *CRYPT_EAL_LibCtxNewInternal(void)
{
CRYPT_EAL_LibCtx *libCtx = (CRYPT_EAL_LibCtx *)BSL_SAL_Calloc(1, sizeof(CRYPT_EAL_LibCtx));
if (libCtx == NULL) {
BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
return NULL;
}
libCtx->providers = BSL_LIST_New(sizeof(struct EAL_ProviderMgrCtx *));
if (libCtx->providers == NULL) {
goto ERR;
}
if (BSL_SAL_ThreadLockNew(&libCtx->lock) != BSL_SUCCESS) {
BSL_LIST_FREE(libCtx->providers, NULL);
goto ERR;
}
return libCtx;
ERR:
BSL_SAL_Free(libCtx);
libCtx = NULL;
return NULL;
}
void CRYPT_EAL_ProviderMgrCtxFree(CRYPT_EAL_ProvMgrCtx *ctx)
{
if (ctx == NULL) {
return;
}
if (ctx->provFreeCb != NULL) {
ctx->provFreeCb(ctx->provCtx);
ctx->provCtx = NULL;
}
BSL_SAL_FREE(ctx->providerName);
BSL_SAL_FREE(ctx->providerPath);
BSL_SAL_ReferencesFree(&(ctx->ref));
#ifdef HITLS_BSL_SAL_DL
if (ctx->handle != NULL) {
BSL_SAL_UnLoadLib(ctx->handle);
ctx->handle = NULL;
}
#endif
#ifdef HITLS_CRYPTO_ENTROPY_DEFAULT
ProviderSeedDeinit(&(ctx->providerSeed));
#endif
BSL_SAL_Free(ctx);
}
int32_t CRYPT_EAL_AddNewProvMgrCtx(CRYPT_EAL_LibCtx *libCtx, const char *providerName, const char *providerPath,
CRYPT_EAL_ImplProviderInit init, void *handle, BSL_Param *param, CRYPT_EAL_ProvMgrCtx **ctx)
{
(void)handle;
CRYPT_EAL_ProvMgrCtx *mgrCtx = (CRYPT_EAL_ProvMgrCtx *)BSL_SAL_Calloc(1, sizeof(CRYPT_EAL_ProvMgrCtx));
if (mgrCtx == NULL) {
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
mgrCtx->libCtx = libCtx;
mgrCtx->providerName = BSL_SAL_Dump(providerName, BSL_SAL_Strnlen(providerName, DEFAULT_PROVIDER_NAME_LEN_MAX) + 1);
if (mgrCtx->providerName == NULL) {
BSL_SAL_Free(mgrCtx);
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
if (providerPath != NULL) {
mgrCtx->providerPath = BSL_SAL_Dump(providerPath,
BSL_SAL_Strnlen(providerPath, DEFAULT_PROVIDER_PATH_LEN_MAX) + 1);
if (mgrCtx->providerPath == NULL) {
BSL_SAL_Free(mgrCtx->providerName);
BSL_SAL_Free(mgrCtx);
BSL_ERR_PUSH_ERROR(CRYPT_MEM_ALLOC_FAIL);
return CRYPT_MEM_ALLOC_FAIL;
}
}
int32_t ret = BSL_SAL_ReferencesInit(&mgrCtx->ref);
if (ret != BSL_SUCCESS) {
CRYPT_EAL_ProviderMgrCtxFree(mgrCtx);
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
ret = CRYPT_EAL_InitProviderMethod(mgrCtx, param, init);
if (ret != BSL_SUCCESS) {
CRYPT_EAL_ProviderMgrCtxFree(mgrCtx);
return ret;
}
ret = BSL_LIST_AddElement(libCtx->providers, mgrCtx, BSL_LIST_POS_END);
if (ret != CRYPT_SUCCESS) {
CRYPT_EAL_ProviderMgrCtxFree(mgrCtx);
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
if (ctx != NULL) {
*ctx = mgrCtx;
}
#ifdef HITLS_BSL_SAL_DL
mgrCtx->handle = handle;
#endif
return ret;
}
int32_t CRYPT_EAL_InitPreDefinedProviders(void)
{
CRYPT_EAL_LibCtx *libCtx = CRYPT_EAL_LibCtxNewInternal();
if (libCtx == NULL) {
BSL_ERR_PUSH_ERROR(BSL_MALLOC_FAIL);
return BSL_MALLOC_FAIL;
}
g_libCtx = libCtx;
int32_t ret = CRYPT_EAL_AddNewProvMgrCtx(g_libCtx, CRYPT_EAL_DEFAULT_PROVIDER, NULL, CRYPT_EAL_DefaultProvInit,
NULL, NULL, NULL);
if (ret != CRYPT_SUCCESS) {
BSL_LIST_FREE(g_libCtx->providers, NULL);
BSL_SAL_ThreadLockFree(g_libCtx->lock);
BSL_SAL_FREE(g_libCtx);
return ret;
}
return ret;
}
void CRYPT_EAL_FreePreDefinedProviders(void)
{
CRYPT_EAL_LibCtx *libCtx = g_libCtx;
if (libCtx == NULL) {
return;
}
#ifdef HITLS_CRYPTO_DRBG
if (libCtx->drbg != NULL) {
EAL_RandDeinit(libCtx->drbg);
libCtx->drbg = NULL;
}
#endif
if (libCtx->providers != NULL) {
BSL_LIST_FREE(libCtx->providers, (BSL_LIST_PFUNC_FREE)CRYPT_EAL_ProviderMgrCtxFree);
}
#ifdef HITLS_BSL_SAL_DL
BSL_SAL_FREE(libCtx->searchProviderPath);
#endif
if (libCtx->lock != NULL) {
BSL_SAL_ThreadLockFree(libCtx->lock);
libCtx->lock = NULL;
}
BSL_SAL_Free(libCtx);
g_libCtx = NULL;
}
#endif