28 #include <openssl/ssl.h>
29 #include <openssl/err.h>
30 #include <openssl/rand.h>
68 explicit Context(
const std::string & pem_file = std::string() ,
unsigned int flags = 0U ) ;
74 void operator=(
const Context & ) ;
75 void init(
const std::string & pem_file ) ;
76 static void check(
int ,
const char * ) ;
90 std::string
str()
const ;
107 explicit LibraryImp(
const std::string & pem_file = std::string(),
unsigned int flags = 0U, LogFn log_fn = NULL ) ;
110 std::string
pem()
const ;
111 LogFn
logFn()
const ;
112 unsigned int flags()
const ;
120 std::string m_pem_file ;
121 unsigned int m_flags ;
142 Result
read(
char * buffer , size_type buffer_size , ssize_type & read_size ) ;
143 Result
write(
const char * buffer , size_type size_in , ssize_type & size_out ) ;
149 int error(
const char * ,
int )
const ;
153 static Result convert(
int ) ;
154 static void clearErrors() ;
158 unsigned int m_flags ;
169 explicit Error(
const std::string & ) ;
170 Error(
const std::string & ,
unsigned long ) ;
171 virtual ~Error()
throw() ;
172 virtual const char *
what()
const throw() ;
182 m_pem_file(pem_file) ,
186 SSL_load_error_strings() ;
194 G_IGNORE_RETURN(
int) RAND_status() ;
196 m_context =
new Context( pem_file , flags ) ;
244 m_imp =
new LibraryImp( pem_file , flags , log_fn ) ;
261 return m_imp != NULL && ( !for_server || !m_imp->pem().empty() ) ;
267 throw G::Exception(
"internal error: no ssl library instance" ) ;
271 std::string
GSsl::Library::credit(
const std::string & prefix ,
const std::string & eol ,
const std::string &
final )
273 std::ostringstream ss ;
275 << prefix <<
"This product includes software developed by the OpenSSL Project" << eol
276 << prefix <<
"for use in the OpenSSL Toolkit (http://www.openssl.org/)" << eol
285 int verify_callback_always_pass(
int , X509_STORE_CTX * )
293 if( (flags&3U) == 2U )
294 m_ssl_ctx = SSL_CTX_new(SSLv23_method()) ;
295 else if( (flags&3U) == 3U ) {
296 m_ssl_ctx = SSL_CTX_new(SSLv23_method()) ;
297 SSL_CTX_set_options(m_ssl_ctx, SSL_OP_NO_SSLv2) ;
299 m_ssl_ctx = SSL_CTX_new(SSLv23_method()) ;
300 SSL_CTX_set_options(m_ssl_ctx, SSL_OP_NO_SSLv2| SSL_OP_NO_SSLv3) ;
303 if( m_ssl_ctx == NULL )
304 throw Error(
"SSL_CTX_new" , ERR_get_error() ) ;
309 SSL_CTX_set_verify( m_ssl_ctx , SSL_VERIFY_PEER , verify_callback_always_pass ) ;
311 if( (flags&8U) && !pem_file.empty() )
314 SSL_CTX_set_verify( m_ssl_ctx , SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT , NULL ) ;
315 check( SSL_CTX_load_verify_locations( m_ssl_ctx , NULL ,
316 G::Path(pem_file).dirname().str().c_str() ) ,
"load_verify_locations" ) ;
324 SSL_CTX_free( m_ssl_ctx ) ;
332 void GSsl::Context::init(
const std::string & pem_file )
334 G_DEBUG(
"GSsl::Context::init: [" << pem_file <<
"]" ) ;
335 SSL_CTX_set_quiet_shutdown( m_ssl_ctx , 1 ) ;
336 if( !pem_file.empty() )
338 check( SSL_CTX_use_certificate_chain_file(m_ssl_ctx,pem_file.c_str()) ,
"use_certificate_chain_file" ) ;
339 check( SSL_CTX_use_RSAPrivateKey_file(m_ssl_ctx,pem_file.c_str(),SSL_FILETYPE_PEM) ,
"use_RSAPrivateKey_file" );
340 check( SSL_CTX_set_cipher_list(m_ssl_ctx,
"DEFAULT") ,
"set_cipher_list" ) ;
344 void GSsl::Context::check(
int rc ,
const char * op )
347 throw Error( std::string() +
"SSL_CTX_" + op ) ;
353 m_what(std::string()+
"ssl error: "+s)
358 m_what(std::string()+
"ssl error: "+s)
360 std::vector<char> v( 300 ) ;
361 ERR_error_string_n( e , &v[0] , v.size() ) ;
362 std::string reason( &v[0] , v.size() ) ;
363 reason = std::string( reason.c_str() ) ;
364 m_what.append( std::string() +
": [" + reason +
"]" ) ;
373 return m_what.c_str() ;
379 m_imp( new
ProtocolImp(library.imp().ctx(),library.imp().flags(),library.imp().logFn()) )
384 m_imp( new
ProtocolImp(library.imp().ctx(),library.imp().flags(),log_fn) )
395 return m_imp->peerCertificate() ;
400 if( result == Result_ok )
return "Result_ok" ;
401 if( result == Result_read )
return "Result_read" ;
402 if( result == Result_write )
return "Result_write" ;
403 if( result == Result_error )
return "Result_error" ;
404 return "Result_undefined" ;
409 return m_imp->connect( fd ) ;
414 return m_imp->accept( fd ) ;
419 return m_imp->stop() ;
424 return m_imp->read( buffer , buffer_size_in , data_size_out ) ;
430 return m_imp->write( buffer , data_size_in , data_size_out ) ;
441 m_ssl = SSL_new( c.
p() ) ;
443 throw Error(
"SSL_new" , ERR_get_error() ) ;
452 m_ssl = SSL_new( c.
p() ) ;
454 throw Error(
"SSL_new" , ERR_get_error() ) ;
462 void GSsl::ProtocolImp::clearErrors()
464 for(
int i = 0 ; ERR_get_error() && i < 10000 ; i++ )
468 int GSsl::ProtocolImp::error(
const char * op ,
int rc )
const
470 int e = SSL_get_error( m_ssl , rc ) ;
472 if( m_log_fn != NULL )
474 std::ostringstream ss ;
475 ss <<
"ssl error: " << op <<
": rc=" << rc <<
": error " << e <<
" => " <<
Protocol::str(convert(e)) ;
476 (*m_log_fn)( 1 , ss.str() ) ;
477 unsigned long ee = 0 ;
478 for(
int i = 2 ; i < 10000 ; i++ )
480 ee = ERR_get_error() ;
481 if( ee == 0 ) break ;
482 Error eee( op , ee ) ;
483 (*m_log_fn)( 2 , std::string() + eee.what() ) ;
509 void GSsl::ProtocolImp::set(
int fd )
513 int rc = SSL_set_fd( m_ssl , fd ) ;
515 throw Error(
"SSL_set_fd" , ERR_get_error() ) ;
519 BIO_set_callback( SSL_get_rbio(m_ssl) , BIO_debug_callback ) ;
520 BIO_set_callback( SSL_get_wbio(m_ssl) , BIO_debug_callback ) ;
530 int rc = SSL_connect( m_ssl ) ;
537 return convert(error(
"SSL_connect",rc)) ;
541 return convert(error(
"SSL_connect",rc)) ;
548 int rc = SSL_accept( m_ssl ) ;
555 return convert(error(
"SSL_accept",rc)) ;
559 return convert(error(
"SSL_accept",rc)) ;
565 int rc = SSL_shutdown( m_ssl ) ;
574 int buffer_size =
static_cast<int>(buffer_size_in) ;
575 int rc = SSL_read( m_ssl , buffer , buffer_size ) ;
583 return convert(error(
"SSL_read",rc)) ;
587 return convert(error(
"SSL_read",rc)) ;
596 int size =
static_cast<int>(size_in) ;
597 int rc = SSL_write( m_ssl , buffer , size ) ;
605 return convert(error(
"SSL_write",rc)) ;
609 return convert(error(
"SSL_write",rc)) ;
615 std::pair<std::string,bool> result ;
616 result.first =
Certificate(SSL_get_peer_certificate(m_ssl)).
str() ;
617 result.second = false ;
636 if( m_p == NULL )
return std::string() ;
637 BIO * bio = BIO_new( BIO_s_mem() ) ;
638 int rc = PEM_write_bio_X509( bio , m_p ) ;
639 if( !rc )
return std::string() ;
640 BUF_MEM * mem = NULL ;
641 BIO_get_mem_ptr( bio , &mem ) ;
642 size_t n = mem ?
static_cast<size_t>(mem->length) : 0U ;
643 const char * p = mem ? mem->data : NULL ;
644 std::string data = p&&n ? std::string(p,n) : std::string() ;
Result write(const char *buffer, size_type size_in, ssize_type &size_out)
static Library * instance()
Returns a pointer to a library object, if any.
static std::string printable(const std::string &in, char escape= '\\')
Returns a printable represention of the given input string.
Context(const std::string &pem_file=std::string(), unsigned int flags=0U)
Error(const std::string &)
A private exception class used by ssl classes.
static std::string str(Result result)
Converts a result enumeration into a printable string.
A private pimple class used by GSsl::Library.
~Library()
Destructor. Cleans up the underlying ssl library.
Result connect(int fd)
Starts the protocol actively.
std::pair< std::string, bool > peerCertificate(int format=0)
Returns the peer certificate and a verified flag.
std::pair< std::string, bool > peerCertificate()
static unsigned int replaceAll(std::string &s, const std::string &from, const std::string &to)
Does a global replace on string 's', replacing all occurences of sub-string 'from' with 'to'...
Result stop()
Initiates the protocol shutdown.
static bool enabled()
Returns true if test features are enabled.
void(* LogFn)(int, const std::string &)
A private pimple class used by GSsl::Protocol.
static std::string credit(const std::string &prefix, const std::string &eol, const std::string &final)
Returns a credit string.
Result read(char *buffer, size_type buffer_size, ssize_type &read_size)
virtual const char * what() const
LibraryImp(const std::string &pem_file=std::string(), unsigned int flags=0U, LogFn log_fn=NULL)
Protocol(const Library &)
Constructor.
A general-purpose exception class derived from std::exception and containing a std::string.
Protocol::size_type size_type
unsigned int flags() const
Result read(char *buffer, size_type buffer_size_in, ssize_type &data_size_out)
Reads user data into the supplied buffer.
A RAII class for initialising the underlying ssl library.
bool enabled(bool for_serving=false) const
Returns true if this is a real and enabled ssl library.
TLS/SSL transport layer security classes.
Result write(const char *buffer, size_type data_size_in, ssize_type &data_size_out)
Writes user data.
ProtocolImp(const Context &c, unsigned int flags)
An openssl X509 RAII class.
An openssl context wrapper.
Protocol::ssize_type ssize_type
A Path object represents a file system path.
Result accept(int fd)
Starts the protocol passively.