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; }