Hello!

It seems to me I've found a bug in openssl req command.
I use a 2005-01-17 snapshot of 0.9.8 branch.
openssl is configured with libefence in debug mode with

./config -d shared.

In my script I load fake engine looking like simplified rsaref demo, but
registering its own cipher algorithm via OBJ_create && EVP_add_cipher
inside the engine.

I export LD_LIBRARY_PATH with values pointing to snapshot dir and engine
dir and use openssl in interactive mode.

I load my "engine" with command

engine -vvvv dynamic -pre SO_PATH:../minimum/obj_mid.lnx/eng_min.so -pre 
LIST_ADD:1  -pre LOAD

and create rsa certificate request with command

req -newkey rsa:512 -keyout rsakey.pem -nodes -out rsareq.pem

After that I exit from app, getting a SEGFAULT. It seems to me it is
caused by double free() on cleanup, because commenting out OBJ_cleanup
at apps/req.c saves from SEGFAULT, and nothing happens without
libefence.

"Engine" source code is attached.

Please, tell me where is my mistake. Thank you.

-- 
SY, Dmitry Belyavsky (ICQ UIN 11116575)
#include <string.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/engine.h>
#include <openssl/objects.h>

static int NID_minimum_cipher_GOST = NID_undef;

#define OID_gost89 "1.2.643.2.9.1.1.1"
#define SN_gost89 "gost89"
#define LN_gost89 "GOST 28147-89 symmetric cipher"

int register_minimum_NID (void)
{
	NID_minimum_cipher_GOST = OBJ_create(OID_gost89, SN_gost89, LN_gost89);
	if (NID_minimum_cipher_GOST == NID_undef) {goto err;}
	return 1;
	
err:
	 NID_minimum_cipher_GOST = NID_undef;
	return 0;
}

/* Fake crypt functions */
int cce_cipher_init(EVP_CIPHER_CTX *ctx, const unsigned char *key,
		const unsigned char *iv, int enc){return 1;}

int	cce_cipher_do(EVP_CIPHER_CTX *ctx, unsigned char *out,
		const unsigned char *in, unsigned int inl){return 1;}

int cce_cipher_cleanup(EVP_CIPHER_CTX *ctx){return 1;}

#define minimum_LIB_NAME "minimum GOST engine"

static const char *engine_minimum_id = "minimum";
static const char *engine_minimum_name = "minimum GOST engine";

static int cce_destroy(ENGINE *e);
static int cce_init(ENGINE *e);
static int cce_finish(ENGINE *e);

/* Engine commands */
static const ENGINE_CMD_DEFN cce_cmd_defns[] = {
		{0, NULL, NULL, 0}
	};

/* Symetric cipher and digest function registrar */

static int cce_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
		 const int **nids, int nid);

static int cce_cipher_nids[]=
    {NID_undef,0};

static EVP_CIPHER cipher_gost = 
	{
	  NID_undef,
	  1,/*block_size*/
	  32,/*key_size*/
	  8,
	  EVP_CIPH_CFB_MODE|EVP_CIPH_CUSTOM_IV|EVP_CIPH_NO_PADDING,
	  cce_cipher_init,
	  cce_cipher_do,
	  cce_cipher_cleanup,
	  0,/* ctx_size */
	  NULL,
	  NULL,
	  NULL,
	  NULL,
	};

static int cce_init(ENGINE *e) { 
	return 1;
}
static int cce_finish(ENGINE *e) { 
	return 1;
}

static int cce_destroy(ENGINE *e) {
	return 1;
}

static int bind_cce (ENGINE *e,const char *id) {
	if (id && strcmp(id, engine_minimum_id)) return 0;
	if (!ENGINE_set_id(e, engine_minimum_id)) {
		printf("ENGINE_set_id failed\n"); 
		return 0;
	}	
	if (!ENGINE_set_name(e, engine_minimum_name)) {
		printf("ENGINE_set_name failed\n");
		return 0;
	}	
	if (!register_minimum_NID()) return 0;
	/* -------- set up NIDs */
	cipher_gost.nid = NID_minimum_cipher_GOST;
	/* -------- end set up NIDs */
    if (! ENGINE_set_ciphers(e, cce_ciphers)) {
		printf("ENGINE_set_ciphers failed\n");
		return 0;
	}	
	if ( ! ENGINE_set_destroy_function(e, cce_destroy)
		|| ! ENGINE_set_init_function(e,cce_init)
		|| ! ENGINE_set_finish_function(e,cce_finish)) return 0;
	if (!EVP_add_cipher(&cipher_gost)) return 0;
	return 1;
}	

#ifdef _WIN32
extern __declspec( dllexport ) 
#endif
	
#ifndef OPENSSL_NO_DYNAMIC_ENGINE
IMPLEMENT_DYNAMIC_BIND_FN(bind_cce);
IMPLEMENT_DYNAMIC_CHECK_FN();
#else
static ENGINE *engine_cce(void)
	{
	ENGINE *ret = ENGINE_new();
	if(!ret)
		return NULL;
	if(!bind_cce(ret, engine_minimum_id))
		{
		ENGINE_free(ret);
		return NULL;
		}
	return ret;
	}

void ENGINE_load_cce(void)
	{
	/* Copied from eng_[openssl|dyn].c */
	ENGINE *toadd = engine_cce();
	if(!toadd) return;
	ENGINE_add(toadd);
	ENGINE_free(toadd);
	ERR_clear_error();
	}
#endif /* OPENSSL_NO_DYNAMIC_ENGINE */

static int cce_ciphers (ENGINE *e,const EVP_CIPHER **cipher,
		const int **nids, int nid) {
	int ok = 1;
	if (!cipher) {
		/* return list of supported nids */
		if (cce_cipher_nids[0] == NID_undef) {
			cce_cipher_nids[0] = NID_minimum_cipher_GOST;
		}
		*nids = cce_cipher_nids;
		return 1; /* Only one cipher supported */
	}

	if(nid == NID_minimum_cipher_GOST) {
			*cipher = &cipher_gost;
	} else {
		ok = 0;
	}
	return ok;
}	

Reply via email to