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.
 
 
 
 

399 lines
12 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-compatibility.hxx>
#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()), _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<<" ---- "<<ENGINE_get_first());
return _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: "<<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_get0_engine(rsa)));
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_get0_engine(rsa)));
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_get0_engine(rsa)));
return it!=_map.end()?it->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<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