This library provides a simple and nice C++ wrapper around these libraries, so that programmers can concentrate on functionality. It offers general support for PCSC-lite, OpenSSL, PKCS#11, plus specific functionality for the SuisseID.
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.
341 lines
11 KiB
341 lines
11 KiB
/*! @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 <cryptaux.hxx> |
|
|
|
#include <openssl/opensslv.h> |
|
#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 <openssl/engine.h> |
|
#include <map> |
|
#include <string> |
|
|
|
#ifndef OPENSSL_CHECK |
|
#include <stdexcept> |
|
#include <sstream> |
|
#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: "<<ERR_error_string(err, 0)<<"; "; \ |
|
ss<<"Command "<<#X<<" failed in function "<<__PRETTY_FUNCTION__ \ |
|
<<" in file "<<__FILE__<<":"<<__LINE__; \ |
|
throw std::runtime_error(ss.str()); \ |
|
} |
|
#else |
|
#define OPENSSL_CHECK(X) \ |
|
if (!(X)) { \ |
|
ERR_load_ENGINE_strings(); \ |
|
std::stringstream ss; \ |
|
for (unsigned long err(0); (err=ERR_get_error());) \ |
|
ss<<"Error: "<<ERR_error_string(err, 0)<<"; "; \ |
|
ss<<"Command "<<#X<<" failed in file "<<__FILE__<<":"<<__LINE__; \ |
|
throw std::runtime_error(ss.str()); \ |
|
} |
|
#endif |
|
#endif |
|
|
|
//! @addtogroup gopenssl |
|
//@{ |
|
//! @defgroup opensslengine OpenSSL Engine C++ Wrapper |
|
//@} |
|
|
|
namespace openssl { |
|
|
|
//! @addtogroup opensslengine |
|
//@{ |
|
|
|
//! Abstract Engine Base |
|
/*! Inherit and overwrite to implement your own Engine. |
|
|
|
Then in the scope where you need it, register your engine: |
|
<code> |
|
openssl::RegisterEngine myEngine(new MyEngine); |
|
</code> */ |
|
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: "<<e.what()); |
|
return 0; |
|
} |
|
} |
|
static int rsaDecrypt(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->rsaDecrypt |
|
(std::string((const char*)from, flen), |
|
padding)); |
|
std::copy(res.begin(), res.end(), to); |
|
return 1; |
|
} catch (const std::exception& e) { |
|
CRYPTOLOG("ERROR: "<<e.what()); |
|
return 0; |
|
} |
|
} |
|
static int rsaSign(int type, const unsigned char *from, |
|
unsigned int flen, |
|
unsigned char *to, |
|
unsigned int*tlen, |
|
const RSA *rsa) { |
|
CRYPTOLOG("log"); |
|
Map::iterator it(_map.find(rsa->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="<<res.size()); |
|
*tlen = (unsigned int)res.size(); |
|
std::copy(res.begin(), res.end(), to); |
|
return 1; |
|
} catch (const std::exception& e) { |
|
CRYPTOLOG("ERROR: "<<e.what()); |
|
return 0; |
|
} |
|
} |
|
static int rsaVerify(int, const unsigned char*, |
|
unsigned int, OPENSSL_V0_CONST unsigned char*, |
|
unsigned int, const RSA* rsa) { |
|
CRYPTOLOG("log"); |
|
Map::iterator it(_map.find(rsa->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<ENGINE*, Engine*> Map; |
|
static Map _map; |
|
static std::map<std::string, Engine*> _prototypes; |
|
}; |
|
|
|
//! Scoped Engine Registry |
|
/*! Engine will be deregistered and freed at destruction */ |
|
template <class ENGINE=Engine> 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
|
|
|