/*! @file
@ id $ Id $
*/
// 1 2 3 4 5 6 7 8
// 45678901234567890123456789012345678901234567890123456789012345678901234567890
# ifndef __OPENSSL_ENGINE_HXX__
# define __OPENSSL_ENGINE_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 int 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 int 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
# ifndef OPENSSL_LOG
# include <iostream>
# if __GNUC__ >= 2
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before < code > # include
& lt ; openssl . hxx & gt ; < / code > . Define it empty for no logging at
all . By default logs to < code > std : : clog < / code > . */
# define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__PRETTY_FUNCTION__<<std::endl
# else
//! Openssl Logging
/*! If you want to change openssl logging mechanism, just
redefine your own OPENSSL_LOG macro before < code > # include
& lt ; openssl . hxx & gt ; < / code > . Define it empty for no logging at
all . By default logs to < code > std : : clog < / code > . */
# define OPENSSL_LOG(X) std::clog<<X<<" @ "<<__FILE__<<__LINE__<<std::endl
# 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 ( ) ) {
OPENSSL_LOG ( " log " ) ;
}
virtual ~ Engine ( ) {
OPENSSL_LOG ( " log " ) ;
// removed EngineMapper::destroy because of crash:
// https://dev.marc.waeckerlin.org/projects/libpcscxx/ticket/25
//OPENSSL_CHECK(ENGINE_free(_e));
}
virtual const char * id ( ) = 0 ;
virtual const char * name ( ) = 0 ;
virtual int init ( ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
virtual int finish ( ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
virtual int ctrl ( int , long , void * , void ( * ) ( ) ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
virtual int cmd ( ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
virtual EVP_PKEY * pubkey ( const char * , UI_METHOD * , void * ) {
OPENSSL_LOG ( " log " ) ;
return 0 ;
}
virtual EVP_PKEY * privkey ( const char * , UI_METHOD * , void * ) {
OPENSSL_LOG ( " log " ) ;
return 0 ;
}
virtual int rsaEncrypt ( ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
virtual int rsaDecrypt ( ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
virtual std : : string rsaSign ( const std : : string & , unsigned int ) {
OPENSSL_LOG ( " log " ) ;
throw std : : runtime_error ( " rsaSign not implemented " ) ;
}
virtual int rsaVerify ( ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
virtual int rsaFinish ( ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
protected :
friend class EngineMapper ;
ENGINE * _e ;
} ;
class EngineMapper {
public :
static void add ( Engine * e ) {
OPENSSL_LOG ( " 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 ( ) ) ) ;
// removed EngineMapper::destroy because of crash:
// https://dev.marc.waeckerlin.org/projects/libpcscxx/ticket/25
//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_LOG ( " log " ) ;
OPENSSL_CHECK ( ENGINE_remove ( e - > _e ) ) ;
OPENSSL_CHECK ( ENGINE_finish ( e - > _e ) ) ;
_map . erase ( e - > _e ) ;
delete e ;
}
private :
static int destroy ( ENGINE * e ) {
OPENSSL_LOG ( " log " ) ;
return 1 ;
}
static int init ( ENGINE * e ) {
OPENSSL_LOG ( " log " ) ;
Map : : iterator it ( _map . find ( e ) ) ;
return it ! = _map . end ( ) ? it - > second - > init ( ) : 0 ;
}
static int finish ( ENGINE * e ) {
OPENSSL_LOG ( " 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 ) ( ) ) {
OPENSSL_LOG ( " 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 ) {
OPENSSL_LOG ( " 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 ) {
OPENSSL_LOG ( " 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 ) {
OPENSSL_LOG ( " log " ) ;
Map : : iterator it ( _map . find ( rsa - > engine ) ) ;
return it ! = _map . end ( ) ? it - > second - > rsaEncrypt ( ) : 0 ;
}
static int rsaDecrypt ( int flen , const unsigned char * from , unsigned char * to , RSA * rsa , int padding ) {
OPENSSL_LOG ( " log " ) ;
Map : : iterator it ( _map . find ( rsa - > engine ) ) ;
return it ! = _map . end ( ) ? it - > second - > rsaDecrypt ( ) : 0 ;
}
static int rsaSign ( int type , const unsigned char * from ,
unsigned int flen ,
unsigned char * to ,
unsigned int * tlen ,
const RSA * rsa ) {
OPENSSL_LOG ( " 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 ) ) ;
OPENSSL_LOG ( " to= " < < ( void * ) to < < " ; len= " < < * tlen ) ;
OPENSSL_LOG ( " siglen= " < < res . size ( ) ) ;
* tlen = res . size ( ) ;
std : : copy ( res . begin ( ) , res . end ( ) , to ) ;
return 1 ;
} catch ( const std : : exception & e ) {
OPENSSL_LOG ( " ERROR: " < < e . what ( ) ) ;
return 0 ;
}
}
static int rsaVerify ( int , const unsigned char * ,
unsigned int , OPENSSL_V0_CONST unsigned char * ,
unsigned int , const RSA * rsa ) {
OPENSSL_LOG ( " log " ) ;
Map : : iterator it ( _map . find ( rsa - > engine ) ) ;
return it ! = _map . end ( ) ? it - > second - > rsaVerify ( ) : 0 ;
}
static int rsaFinish ( RSA * rsa ) {
OPENSSL_LOG ( " log " ) ;
Map : : iterator it ( _map . find ( rsa - > engine ) ) ;
return it ! = _map . end ( ) ? it - > second - > rsaFinish ( ) : 0 ;
}
protected :
static RSA_METHOD * rsa ( ) {
OPENSSL_LOG ( " 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 ) {
OPENSSL_LOG ( " log " ) ;
if ( _e ) EngineMapper : : add ( _e ) ;
}
~ RegisterEngine ( ) {
OPENSSL_LOG ( " log " ) ;
if ( _e ) EngineMapper : : remove ( _e ) ;
}
RegisterEngine & operator = ( ENGINE * e ) {
OPENSSL_LOG ( " log " ) ;
if ( _e ) EngineMapper : : remove ( _e ) ;
_e = e ;
if ( _e ) EngineMapper : : add ( _e ) ;
return * this ;
}
operator ENGINE * ( ) {
OPENSSL_LOG ( " log " ) ;
return _e ;
}
ENGINE * operator - > ( ) {
OPENSSL_LOG ( " log " ) ;
return _e ;
}
ENGINE & operator * ( ) {
OPENSSL_LOG ( " log " ) ;
return * _e ;
}
private :
ENGINE * _e ;
} ;
//@}
}
# endif