You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
5.8 KiB
262 lines
5.8 KiB
|
|
#include <memory> |
|
#include <cstring> |
|
#include <openssl/dso.h> |
|
#include <openssl/rsa.h> |
|
|
|
#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<SecureTokenEngine> 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, |
|
unsigned char *signature, unsigned int siglen, const RSA *rsa) |
|
{ |
|
CATCH_ALL(int,0,g_engine->rsa_verify(type, msg, msglen, 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); |
|
|
|
} |
|
|
|
|