/*! @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 #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()), _cleanup(true) { CRYPTOLOG("log"); } virtual ~Engine() noexcept(false) try { CRYPTOLOG("log"); if (_cleanup) OPENSSL_CHECK(ENGINE_free(_e)); } catch (...) { if (!std::uncaught_exception()) throw; } 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; } class iterator; protected: friend class EngineMapper; friend class iterator; Engine(ENGINE* e): _e(e), _cleanup(false) { CRYPTOLOG("log"); } Engine(const Engine&); // forbidden Engine& operator=(const Engine&); // forbidden ENGINE* _e; bool _cleanup; }; class Engine::iterator { private: class MyEngine: public Engine { public: MyEngine(ENGINE*e): Engine(e) {} virtual const char* id() { return ENGINE_get_id(_e); } virtual const char* name() { return ENGINE_get_name(_e); } }; public: iterator(): _e(new MyEngine(ENGINE_get_first())) { CRYPTOLOG("log"); } ~iterator() { CRYPTOLOG("log"); delete _e; } Engine& operator*() { CRYPTOLOG("log"); return *_e; } Engine* operator->() { CRYPTOLOG("log"); return _e; } iterator& operator++() { CRYPTOLOG("log"); _e->_e = ENGINE_get_next(_e->_e); return *this; } operator bool() const { CRYPTOLOG("log: "<<_e->_e<<" ---- "<_e!=0; } private: 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_get0_engine(rsa))); 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: "<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: "<second->rsaSign (std::string((const char*)from, flen), type)); CRYPTOLOG("to="<<(void*)to<<"; len="<<*tlen); CRYPTOLOG("siglen="<second->rsaVerify():0; } static int rsaFinish(RSA *rsa) { CRYPTOLOG("log"); Map::iterator it(_map.find(RSA_get0_engine(rsa))); return it!=_map.end()?it->second->rsaFinish():0; } protected: static RSA_METHOD* rsa() { CRYPTOLOG("log"); static RSA_METHOD* ops(0); if (!ops) { ops = RSA_meth_dup(RSA_get_default_method()); RSA_meth_set_pub_enc(ops, rsaEncrypt); RSA_meth_set_priv_dec(ops, rsaDecrypt); // a.k.a Verify/Sign. actLibrary just allows the proper functions // and has this 'backdoor' closed. Breaks 'rsautl', sadly. RSA_meth_set_pub_dec(ops, 0); RSA_meth_set_priv_enc(ops, 0); RSA_meth_set_sign(ops, rsaSign); RSA_meth_set_verify(ops, rsaVerify); RSA_meth_set_finish(ops, 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