/*! @file @id $Id$ */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 #ifndef __OPENSSL_ENGINE_HXX__ #define __OPENSSL_ENGINE_HXX__ #include #ifndef OPENSSL_VERSION_NUMBER # error OpenSSL Version Number not Found #elif OPENSSL_VERSION_NUMBER < 0x10000000L # define OPENSSL_0 # define OPENSSL_V0_CONST #else # define OPENSSL_1 # define OPENSSL_V0_CONST const #endif #undef DATADIR #include #include #include #ifndef OPENSSL_CHECK #include #include #if __GNUC__ >= 2 //! Macro for internal OpenSSL checks. /*! You can define a different implementation in your compile call */ #define OPENSSL_CHECK(X) if (!X) {ERR_load_ENGINE_strings(); std::stringstream ss; for (unsigned int err(0); err=ERR_get_error();) ss<<"Error: "< #if __GNUC__ >= 2 //! Openssl Logging /*! If you want to change openssl logging mechanism, just redefine your own OPENSSL_LOG macro before #include <openssl.hxx>. Define it empty for no logging at all. By default logs to std::clog. */ #define OPENSSL_LOG(X) std::clog<#include <openssl.hxx>. Define it empty for no logging at all. By default logs to std::clog. */ #define OPENSSL_LOG(X) std::clog< openssl::RegisterEngine myEngine(new MyEngine); */ class Engine { public: Engine(): _e(ENGINE_new()) { OPENSSL_LOG("log"); } virtual ~Engine() { OPENSSL_LOG("log"); // removed EngineMapper::destroy because of crash: // https://dev.marc.waeckerlin.org/projects/libpcscxx/ticket/25 //OPENSSL_CHECK(ENGINE_free(_e)); } virtual const char* id() = 0; virtual const char* name() = 0; virtual int init() { OPENSSL_LOG("log"); return 1; } virtual int finish() { OPENSSL_LOG("log"); return 1; } virtual int ctrl(int, long, void*, void(*)()) { OPENSSL_LOG("log"); return 1; } virtual int cmd() { OPENSSL_LOG("log"); return 1; } virtual EVP_PKEY* pubkey(const char*, UI_METHOD*, void*) { OPENSSL_LOG("log"); return 0; } virtual EVP_PKEY* privkey(const char*, UI_METHOD*, void*) { OPENSSL_LOG("log"); return 0; } virtual int rsaEncrypt() { OPENSSL_LOG("log"); return 1; } virtual int rsaDecrypt() { OPENSSL_LOG("log"); return 1; } virtual std::string rsaSign(const std::string&, unsigned int) { OPENSSL_LOG("log"); throw std::runtime_error("rsaSign not implemented"); } virtual int rsaVerify() { OPENSSL_LOG("log"); return 1; } virtual int rsaFinish() { OPENSSL_LOG("log"); return 1; } protected: friend class EngineMapper; ENGINE* _e; }; class EngineMapper { public: static void add(Engine *e) { OPENSSL_LOG("log"); _prototypes[e->id()] = e; _map[e->_e] = e; OPENSSL_CHECK(ENGINE_set_id(e->_e, e->id())); OPENSSL_CHECK(ENGINE_set_name(e->_e, e->name())); // removed EngineMapper::destroy because of crash: // https://dev.marc.waeckerlin.org/projects/libpcscxx/ticket/25 //OPENSSL_CHECK(ENGINE_set_destroy_function // (e->_e, EngineMapper::destroy)); OPENSSL_CHECK(ENGINE_set_init_function(e->_e, EngineMapper::init)); OPENSSL_CHECK(ENGINE_set_finish_function(e->_e, EngineMapper::finish)); OPENSSL_CHECK(ENGINE_set_ctrl_function(e->_e, EngineMapper::ctrl)); //OPENSSL_CHECK(ENGINE_set_cmd_defns(e->_e, EngineMapper::cmd)); #ifndef OPENSSL_NO_RSA OPENSSL_CHECK(ENGINE_set_RSA(e->_e, rsa())); #endif #ifndef OPENSSL_NO_DSA // OPENSSL_CHECK(ENGINE_set_DSA(e->_e, DSA_get_default_method())); #endif #ifndef OPENSSL_NO_DH // OPENSSL_CHECK(ENGINE_set_DH(e->_e, DSA_get_default_method())); #endif // OPENSSL_CHECK(ENGINE_set_RAND(e->_e, rand())); OPENSSL_CHECK(ENGINE_set_load_pubkey_function(e->_e, pubkey)); OPENSSL_CHECK(ENGINE_set_load_privkey_function(e->_e, privkey)); OPENSSL_CHECK(ENGINE_init(e->_e)); OPENSSL_CHECK(ENGINE_add(e->_e)); } static void remove(Engine *e) { OPENSSL_LOG("log"); OPENSSL_CHECK(ENGINE_remove(e->_e)); OPENSSL_CHECK(ENGINE_finish(e->_e)); _map.erase(e->_e); delete e; } private: static int destroy(ENGINE* e) { OPENSSL_LOG("log"); return 1; } static int init(ENGINE* e) { OPENSSL_LOG("log"); Map::iterator it(_map.find(e)); return it!=_map.end()?it->second->init():0; } static int finish(ENGINE* e) { OPENSSL_LOG("log"); Map::iterator it(_map.find(e)); return it!=_map.end()?it->second->finish():0; } static int ctrl(ENGINE* e, int cmd, long i, void* p, void(*f)()) { OPENSSL_LOG("log"); Map::iterator it(_map.find(e)); return it!=_map.end()?it->second->ctrl(cmd, i, p, f):0; } static EVP_PKEY* pubkey(ENGINE* e, const char* c, UI_METHOD* u, void* d) { OPENSSL_LOG("log"); Map::iterator it(_map.find(e)); return it!=_map.end()?it->second->pubkey(c, u, d):0; } static EVP_PKEY* privkey(ENGINE* e, const char* c, UI_METHOD* u, void* d) { OPENSSL_LOG("log"); Map::iterator it(_map.find(e)); return it!=_map.end()?it->second->privkey(c, u, d):0; } static int rsaEncrypt(int flen,const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { OPENSSL_LOG("log"); Map::iterator it(_map.find(rsa->engine)); return it!=_map.end()?it->second->rsaEncrypt():0; } static int rsaDecrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { OPENSSL_LOG("log"); Map::iterator it(_map.find(rsa->engine)); return it!=_map.end()?it->second->rsaDecrypt():0; } static int rsaSign(int type, const unsigned char *from, unsigned int flen, unsigned char *to, unsigned int*tlen, const RSA *rsa) { OPENSSL_LOG("log"); Map::iterator it(_map.find(rsa->engine)); if (it==_map.end()) return 0; try { std::string res(it->second->rsaSign (std::string((const char*)from, flen), type)); OPENSSL_LOG("to="<<(void*)to<<"; len="<<*tlen); OPENSSL_LOG("siglen="<engine)); return it!=_map.end()?it->second->rsaVerify():0; } static int rsaFinish(RSA *rsa) { OPENSSL_LOG("log"); Map::iterator it(_map.find(rsa->engine)); return it!=_map.end()?it->second->rsaFinish():0; } protected: static RSA_METHOD* rsa() { OPENSSL_LOG("log"); static RSA_METHOD ops; if (!ops.rsa_priv_enc) { ops = *RSA_get_default_method(); ops.rsa_pub_enc = rsaEncrypt; ops.rsa_priv_dec = rsaDecrypt; // a.k.a Verify/Sign. actLibrary just allows the proper functions // and has this 'backdoor' closed. Breaks 'rsautl', sadly. ops.rsa_pub_dec = NULL; ops.rsa_priv_enc = NULL; ops.rsa_sign = rsaSign; ops.rsa_verify = rsaVerify; ops.finish = rsaFinish; } return &ops; } private: typedef std::map Map; static Map _map; static std::map _prototypes; }; //! Scoped Engine Registry /*! Engine will be deregistered and freed at destruction */ template class RegisterEngine { public: RegisterEngine(ENGINE* e = 0): _e(e) { OPENSSL_LOG("log"); if (_e) EngineMapper::add(_e); } ~RegisterEngine() { OPENSSL_LOG("log"); if (_e) EngineMapper::remove(_e); } RegisterEngine& operator=(ENGINE* e) { OPENSSL_LOG("log"); if (_e) EngineMapper::remove(_e); _e = e; if (_e) EngineMapper::add(_e); return *this; } operator ENGINE*() { OPENSSL_LOG("log"); return _e; } ENGINE* operator->() { OPENSSL_LOG("log"); return _e; } ENGINE& operator*() { OPENSSL_LOG("log"); return *_e; } private: ENGINE* _e; }; //@} } #endif