I'm trying to use my custom engine however I cannot get it to clean up
nicely.
For the initialization i used the sample in openssl ENGINE(3) documentation.
Here's how it goes:
ENGINE *loadEngine()
{
ENGINE *e;
e = ENGINE_by_id(MY_ENGINE_ID);
if(!e)
ENGINE_load_my();
e = ENGINE_by_id(MY_ENGINE_ID); /* try again */
if(!e)
/* the engine isn't available */
return NULL;
if(!ENGINE_init(e)) {
/* the engine couldn't initialise, release 'e' */
ENGINE_free(e);
return NULL;
}
ENGINE_set_default(e, ENGINE_METHOD_ALL);
return e;
}
void unloadEngine(ENGINE *e)
{
/* Release the functional reference from ENGINE_init() */
ENGINE_finish(e);
/* Release the structural reference from ENGINE_by_id() */
ENGINE_free(e);
/* ENGINE_cleanup(); my engine_finish method does not get
called unless I include this line */
}
void testKeyGen()
{
/* some openssl initialization code such as loading ciphers,
algorithms, existing engines, establishing dynamic locks and so on */
ENGINE *e = loadEngine();
ASSERT(e, "could not create the engine\n");
EVP_PKEY *pkey = NULL;
genPKey(e, &pkey); /* some calls to EVP_PKEY_CTX_new_id,
EVP_PKEY_keygen and so on */
ASSERT(pkey, "could not generate PKEY\n");
/* so far so good */
if(pkey)
EVP_PKEY_free(pkey);
unloadEngine(e);
/* at the end of this I have unfreed memory (the dynamic lock I
created in my engine because my_finish was not called */
}
And here's my engine initialization and deinit routines. I stepped
through the code in ENGINE_finish() and realized that the following line
(to_return = e->finish(e); ) does not get executed because apparently
the ref count is not zero:
********* file openssl/crypto/engine/eng_init.c **************
int engine_unlocked_finish(ENGINE *e, int unlock_for_handlers)
{
if((e->funct_ref == 0) && e->finish)
{
if(unlock_for_handlers)
CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
to_return = e->finish(e);
if(unlock_for_handlers)
CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
if(!to_return)
return 0;
...
}
********* continuation of my code -- my engine init routines *********
static int my_init(ENGINE *e)
{
ERR_load_MY_strings();
my_lock_id = CRYPTO_get_new_dynlockid();
...
return 1;
}
static int my_finish(ENGINE *e)
{
ERR_unload_MY_strings();
CRYPTO_destroy_dynlockid(my_lock_id);
return 1;
}
static int bind_helper(ENGINE *e)
{
...
if (!ENGINE_set_id(e, MY_ENGINE_ID)
|| !ENGINE_set_name(e, MY_ENGINE_NAME)
|| !ENGINE_set_destroy_function(e, my_destroy)
|| !ENGINE_set_init_function(e, my_init)
|| !ENGINE_set_finish_function(e, my_finish)
...
return 0;
return 1;
}
static ENGINE *engine_my(void)
{
ENGINE *ret = ENGINE_new();
if (!ret)
return NULL;
if (!bind_helper(ret))
{
ENGINE_free(ret);
return NULL;
}
return ret;
}
void ENGINE_load_my(void)
{
ENGINE *toadd = engine_my();
if (!toadd)
return;
ENGINE_add(toadd);
ENGINE_free(toadd);
ERR_clear_error();
}
This email contains Morega Systems Inc. Privileged and Confidential information.