openssl引擎的例子
ENGINE是OPENSSL预留的用以加载第三方加密库引擎,主要包括了动态库加载的代码和加密函数指针管理的一系列接口。
自定义一个引擎
void
ENGINE_load_rtl8651b(void)
{
ENGINE *engine = ENGINE_new();
if (engine == NULL)
return;
if (!ENGINE_set_id(engine, "rtl8651b") ||
!ENGINE_set_name(engine, "BSD rtl8651b engine") ||
!ENGINE_set_ciphers(engine, rtl8651b_engine_ciphers)||
!ENGINE_set_digests(engine, rtl8651b_engine_digests)||
!ENGINE_set_ctrl_function(engine, rtl8651b_ctrl) ||
!ENGINE_set_cmd_defns(engine, rtl8651b_defns)
){
ENGINE_free(engine);
return;
}
if(!ENGINE_set_default(engine, ENGINE_METHOD_DIGESTS) )
ENGINE_add(engine);
ENGINE_free(engine);
ERR_clear_error();
}
设置替换哪些算法
你可以使用自己的实现来替换openssl的默认算法。
ENGINE_set_default(ENGINE *e, int Flag)
其中Flag的说明如下:
ENGINE_METHOD_ALL 使用所有存在的算法(默认)
ENGINE_METHOD_RSA 仅使用RSA算法
ENGINE_METHOD_DSA 仅使用DSA算法
ENGINE_METHOD_DH 仅使用DH算法
ENGINE_METHOD_RAND 仅使用随机数算法
ENGINE_METHOD_CIPHERS 仅使用对称加解密算法
ENGINE_METHOD_DIGESTS 仅使用摘要算法
动态引擎
动态引擎是openssl提供的一个引擎,这个引擎是用来加载其他引擎的(加载你实现的引擎库so)。
openssl提供了动态绑定宏方法
IMPLEMENT_DYNAMIC_CHECK_FN()
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
其实就是帮我们定义了两个方法,然后这两个方法是在动态引擎的load方法中调用的。
# define IMPLEMENT_DYNAMIC_CHECK_FN() \
OPENSSL_EXPORT unsigned long v_check(unsigned long v); \
OPENSSL_EXPORT unsigned long v_check(unsigned long v) { \
if (v >= OSSL_DYNAMIC_OLDEST) return OSSL_DYNAMIC_VERSION; \
return 0; }
# define IMPLEMENT_DYNAMIC_BIND_FN(fn) \
OPENSSL_EXPORT \
int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns); \
OPENSSL_EXPORT \
int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) { \
if (ENGINE_get_static_state() == fns->static_state) goto skip_cbs; \
CRYPTO_set_mem_functions(fns->mem_fns.malloc_fn, \
fns->mem_fns.realloc_fn, \
fns->mem_fns.free_fn); \
skip_cbs: \
if (!fn(e, id)) return 0; \
return 1; }
定义绑定方法
如下,我们自定义了几个方法。其实就是替换openssl的默认实现,实现自己的功能。
//返回值 1为成功 0为失败
int bind_fn(ENGINE *e, const char *id)
{
if (id && (strcmp(id, FILE_ENGINE_ID) != 0)) {
fprintf(stderr, "bad engine id\n");
return 0;
}
if (!bind_helper(e)) {
fprintf(stderr, "bind failed\n");
return 0;
}
}
//设置新引擎的相关方法。
static int bind_helper(ENGINE *e) {
if (!ENGINE_set_id(e, FILE_ENGINE_ID) ||
!ENGINE_set_destroy_function(e, file_engine_destroy) ||
!ENGINE_set_init_function(e, file_init) ||
!ENGINE_set_finish_function(e, file_finish) ||
!ENGINE_set_ctrl_function(e, file_engine_ctrl) ||
!ENGINE_set_cmd_defns(e, file_cmd_defns) ||
!ENGINE_set_name(e, FILE_ENGINE_NAME) ||
!ENGINE_set_RSA(e, RSA_get_default_method()) ||
!ENGINE_set_load_pubkey_function(e, file_load_public_key) ||
!ENGINE_set_load_privkey_function(e, file_load_private_key)) {
return 0;
} else {
return 1;
}
}
IMPLEMENT_DYNAMIC_CHECK_FN()
IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
将上面的新引擎编译成动态库
动态引擎初始化我们定义的引擎库
例子如下。
- 判断以前是否已经加载,没有加载才进行加载
- 加载动态引擎,因为我们的引擎是个so库,我们需要动态引擎来加载它
- 使用动态引擎的命令加载我们的引擎,pszEnginePath是引擎的路径,此方法只是把我们引擎库路径赋值给动态引擎的一个内部变量
ENGINE_ctrl_cmd_string(e, “SO_PATH”, pszEnginePath, 0) - 调用load方法,此方法会动态加载so库,并调用上面宏定义的检测版本和绑定方法。ENGINE_ctrl_cmd_string(e, “LOAD”, NULL, 0)
- 设置引擎的默认flag, 例子中使用引擎所有方法,但是不用他的RSA方法ENGINE_set_default(e, ENGINE_METHOD_ALL & ~ENGINE_METHOD_RSA)
- 调用我么定义的引擎初始化方法 ENGINE_init
- 调用我们定义的引擎内部定义的命令控制方法ENGINE_ctrl_cmd_string(e, “MODULE_PATH”, m_szProvider, 0),可选
- 将引擎加入到链表中。
do{
ENGINE *e = NULL;
e = ENGINE_by_id("file");
if (NULL != e) {
PLOGD << "FileEngine is found in the Engine list!";
nRet = ST_SUCCESS;
break;
}
int rv = 0;
char szErr[1024] = "";
ENGINE_load_dynamic();
e = ENGINE_by_id("dynamic");
if (!e) {
PLOGE << "get dynamic engine error!";
break;
}
if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", pszEnginePath, 0)) {
PLOGE << "so_path command call error!";
break;
}
if (!ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) {
PLOGE << "load command call error!";
break;
}
if (!ENGINE_set_default(e, ENGINE_METHOD_ALL & ~ENGINE_METHOD_RSA)) {
PLOGE << "engine_method_all command call error!";
break;
}
if (!ENGINE_init(e)) {
PLOGE << "file engine init error!";
break;
}
if (!ENGINE_ctrl_cmd_string(e, "MODULE_PATH", m_szProvider, 0)) {
PLOGE << "Setup Engine failed to set the Engine!";
break;
}
if (!ENGINE_add(e)) {
PLOGE << "ENGINE_add to the gloable list error!";
break;
}
}while(0);
使用新的引擎库
e = ENGINE_by_id(“file”);
然后传入到EVP相关方法或者自定义的命令中ENGINE_ctrl_cmd_string中实现调用就行了。