/*! @file @id $Id$ This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit (http://www.openssl.org/) This product includes cryptographic software written by Eric Young (eay@cryptsoft.com) */ // 1 2 3 4 5 6 7 8 // 45678901234567890123456789012345678901234567890123456789012345678901234567890 #ifndef __OPENSSL_ENGINE_HXX__ #define __OPENSSL_ENGINE_HXX__ #include #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 long err(0); (err=ERR_get_error());) \ ss<<"Error: "< openssl::RegisterEngine myEngine(new MyEngine); */ class Engine { public: Engine(): _e(ENGINE_new()) { CRYPTOLOG("log"); } virtual ~Engine() { CRYPTOLOG("log"); OPENSSL_CHECK(ENGINE_free(_e)); } virtual const char* id() = 0; virtual const char* name() = 0; virtual int init() { CRYPTOLOG("log"); return 1; } virtual int finish() { CRYPTOLOG("log"); return 1; } virtual int ctrl(int, long, void*, void(*)()) { CRYPTOLOG("log"); return 1; } virtual int cmd() { CRYPTOLOG("log"); return 1; } virtual EVP_PKEY* pubkey(const char*, UI_METHOD*, void*) { CRYPTOLOG("log"); return 0; } virtual EVP_PKEY* privkey(const char*, UI_METHOD*, void*) { CRYPTOLOG("log"); return 0; } virtual std::string rsaEncrypt(const std::string&, int) { CRYPTOLOG("log"); throw std::runtime_error("rsaEncrypt not implemented"); } virtual std::string rsaDecrypt(const std::string&, int) { CRYPTOLOG("log"); throw std::runtime_error("rsaDecrypt not implemented"); } virtual std::string rsaSign(const std::string&, unsigned int) { CRYPTOLOG("log"); throw std::runtime_error("rsaSign not implemented"); } virtual int rsaVerify() { CRYPTOLOG("log"); return 1; } virtual int rsaFinish() { CRYPTOLOG("log"); return 1; } protected: friend class EngineMapper; ENGINE* _e; }; class EngineMapper { public: static void add(Engine *e) { CRYPTOLOG("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())); 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_CHECK(ENGINE_remove(e->_e)); OPENSSL_CHECK(ENGINE_finish(e->_e)); _map.erase(e->_e); delete e; } private: static int destroy(ENGINE*) { CRYPTOLOG("log"); return 1; } static int init(ENGINE* e) { CRYPTOLOG("log"); Map::iterator it(_map.find(e)); return it!=_map.end()?it->second->init():0; } static int finish(ENGINE* e) { CRYPTOLOG("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)()) { CRYPTOLOG("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) { CRYPTOLOG("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) { CRYPTOLOG("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) { CRYPTOLOG("log"); Map::iterator it(_map.find(rsa->engine)); if (it==_map.end()) return 0; try { std::string res(it->second->rsaEncrypt (std::string((const char*)from, flen), padding)); std::copy(res.begin(), res.end(), to); return 1; } catch (const std::exception& e) { CRYPTOLOG("ERROR: "<engine)); if (it==_map.end()) return 0; try { std::string res(it->second->rsaDecrypt (std::string((const char*)from, flen), padding)); std::copy(res.begin(), res.end(), to); return 1; } catch (const std::exception& e) { CRYPTOLOG("ERROR: "<engine)); if (it==_map.end()) return 0; try { std::string res(it->second->rsaSign (std::string((const char*)from, flen), type)); CRYPTOLOG("to="<<(void*)to<<"; len="<<*tlen); CRYPTOLOG("siglen="<engine)); return it!=_map.end()?it->second->rsaVerify():0; } static int rsaFinish(RSA *rsa) { CRYPTOLOG("log"); Map::iterator it(_map.find(rsa->engine)); return it!=_map.end()?it->second->rsaFinish():0; } protected: static RSA_METHOD* rsa() { CRYPTOLOG("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) { if (_e) EngineMapper::add(_e); } ~RegisterEngine() { if (_e) EngineMapper::remove(_e); } RegisterEngine& operator=(ENGINE* e) { if (_e) EngineMapper::remove(_e); _e = e; if (_e) EngineMapper::add(_e); return *this; } operator ENGINE*() { return _e; } ENGINE* operator->() { return _e; } ENGINE& operator*() { return *_e; } private: ENGINE* _e; }; //@} } #endif