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.
263 lines
5.8 KiB
263 lines
5.8 KiB
14 years ago
|
|
||
|
#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);
|
||
|
|
||
|
}
|
||
|
|