#include #include #include #include #include "engine_sct.h" #include "engine_sct_internal.h" #ifndef ENGINE_CMD_BASE #error did not get engine.h #endif #define SCT_ENGINE_ID "act" #define SCT_ENGINE_NAME "cv act library SecureToken interface engine" enum { CMD_SO_PATH = ENGINE_CMD_BASE, CMD_PIN, CMD_VERBOSE, CMD_QUIET, CMD_LOAD_CERT_CTRL, CMD_ENUM_CERTS, CMD_INIT_ARGS }; static std::auto_ptr g_engine; static int sct_engine_construct(ENGINE *e); static int sct_engine_destruct(ENGINE *e); static int sct_engine_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)() ); static const ENGINE_CMD_DEFN sct_cmd_defns[] = { { CMD_SO_PATH, "SO_PATH", "Specifies the path to the 'securetoken-engine' shared library", ENGINE_CMD_FLAG_STRING }, { CMD_PIN, "PIN", "Specifies the PIN to use for access", ENGINE_CMD_FLAG_STRING }, { CMD_VERBOSE, "VERBOSE", "Increases the amount of progress information", ENGINE_CMD_FLAG_NO_INPUT }, { CMD_LOAD_CERT_CTRL, "LOAD_CERT_CTRL", "Get the certificate from card", ENGINE_CMD_FLAG_INTERNAL }, { CMD_ENUM_CERTS, "ENUM_CERTS", "Return the certificates and the ID's of the key pairs", ENGINE_CMD_FLAG_INTERNAL }, { CMD_INIT_ARGS, "INIT_ARGS", "Additional initialization arguments", ENGINE_CMD_FLAG_STRING }, { 0, NULL, NULL, 0 } }; // Encapsule a "return function()" statement with a catch-all block which will emit an error message and return // a predefined (error) return value in that case. #define CATCH_ALL(rettype, retval, function) \ do { \ rettype result = retval; \ try \ { \ result = (function); \ } \ catch(...) \ { \ fprintf(stderr, "Unhandled exception caught!\n"); \ } \ return result; \ } while(0) \ static int sct_engine_construct(ENGINE *e) { if(g_engine.get() != 0) return 1; g_engine.reset(new SecureTokenEngine()); return 1; } static int sct_engine_destruct(ENGINE *e) { g_engine.reset(0); return 1; } static int sct_engine_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)() ) { switch(cmd) { case CMD_PIN: return g_engine->setPin((char *) p); case CMD_VERBOSE: return g_engine->incVerbosity(); case CMD_LOAD_CERT_CTRL: return g_engine->loadCertCtrl(e, (load_cert_params *)p); case CMD_INIT_ARGS: return g_engine->setInitArgs((const char *)p); case CMD_ENUM_CERTS: return g_engine->enumerate_certs(e, (enum_certs_s **)p); default: break; } return 0; } static int sct_init(ENGINE *e) { CATCH_ALL(int,0,g_engine->init()); } static int sct_finish(ENGINE *e) { CATCH_ALL(int,0,g_engine->finish()); } static int sct_rsa_finish(RSA *rsa) { CATCH_ALL(int,0,g_engine->rsa_finish(rsa)); } static EVP_PKEY *sct_load_public_key( ENGINE *e, const char *s_key_id, UI_METHOD *ui_method, void *callback_data) { CATCH_ALL(EVP_PKEY*,NULL,g_engine->load_pubkey(s_key_id, ui_method, callback_data)); } static EVP_PKEY *sct_load_private_key( ENGINE *e, const char *s_key_id, UI_METHOD *ui_method, void *callback_data) { CATCH_ALL(EVP_PKEY*,NULL,g_engine->load_privkey(s_key_id, ui_method, callback_data)); } static int sct_rsa_encrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { CATCH_ALL(int,-1,g_engine->rsa_encrypt(flen, from, to, EXTRACT_CARD_KEY(rsa), padding)); } static int sct_rsa_decrypt(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { CATCH_ALL(int,-1,g_engine->rsa_decrypt(flen, from, to, EXTRACT_CARD_KEY(rsa), padding)); } static int sct_rsa_sign(int type, const unsigned char *msg, unsigned int msglen, unsigned char *sigret, unsigned int *siglen, const RSA *rsa) { CATCH_ALL(int,0,g_engine->rsa_sign(type, msg, msglen, sigret, siglen, EXTRACT_CARD_KEY(rsa))); } static int sct_rsa_verify(int type, const unsigned char *msg, unsigned int msglen, const unsigned char *signature, unsigned int siglen, const RSA *rsa) { CATCH_ALL(int,0,g_engine->rsa_verify(type, msg, msglen, const_cast(signature), siglen, EXTRACT_CARD_KEY(rsa))); } /* * Following part is for binding the engine into OpenSSL */ // Overlay the standard RSA operations with smartcard based ones RSA_METHOD* RSA_get_sct_method() { static RSA_METHOD ops; if(!ops.rsa_priv_enc) { ops = *RSA_get_default_method(); ops.rsa_pub_enc = sct_rsa_encrypt; ops.rsa_priv_dec = sct_rsa_decrypt; ops.rsa_pub_dec = NULL; // a.k.a Verify/Sign. actLibrary just allows the proper functions ops.rsa_priv_enc = NULL; // and has this 'backdoor' closed. Breaks 'rsautl', sadly. ops.rsa_sign = sct_rsa_sign; ops.rsa_verify = sct_rsa_verify; ops.finish = sct_rsa_finish; } return &ops; } static int bind_helper(ENGINE *e) { if( !sct_engine_construct(e) || !ENGINE_set_id(e, SCT_ENGINE_ID) || !ENGINE_set_name(e, SCT_ENGINE_NAME) || !ENGINE_set_destroy_function(e, sct_engine_destruct) || !ENGINE_set_init_function(e, sct_init) || !ENGINE_set_finish_function(e, sct_finish) || !ENGINE_set_ctrl_function(e, sct_engine_ctrl) || !ENGINE_set_cmd_defns(e, sct_cmd_defns) || #ifndef OPENSSL_NO_RSA !ENGINE_set_RSA(e, RSA_get_sct_method()) || #endif #ifndef OPENSSL_NO_DSA !ENGINE_set_DSA(e, DSA_get_default_method()) || #endif #ifndef OPENSSL_NO_DH !ENGINE_set_DH(e, DH_get_default_method()) || #endif !ENGINE_set_RAND(e, RAND_SSLeay()) || #if 0 !ENGINE_set_BN_mod_exp(e, BN_mod_exp) || #endif !ENGINE_set_load_pubkey_function(e, sct_load_public_key) || !ENGINE_set_load_privkey_function(e, sct_load_private_key)) { return 0; } else { return 1; } } static int bind_fn(ENGINE * e, const char *id) { #ifndef DEBUG if (id && (strcmp(id, SCT_ENGINE_ID) != 0)) { fprintf(stderr, "bad engine id (%s vs. %s)\n", id, SCT_ENGINE_ID); return 0; } #endif if (!bind_helper(e)) { fprintf(stderr, "bind failed\n"); return 0; } return 1; } extern "C" { IMPLEMENT_DYNAMIC_CHECK_FN(); IMPLEMENT_DYNAMIC_BIND_FN(bind_fn); }