00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "config.h"
00034
00035 #include <openssl/ssl.h>
00036 #include <openssl/err.h>
00037 #include <sys/socket.h>
00038 #include <netinet/in.h>
00039 #include <arpa/inet.h>
00040 #include <netdb.h>
00041 #include <ctype.h>
00042
00043 #include <cstring>
00044 #include <iostream>
00045 #ifdef HAVE_UNISTD_H
00046 #include <unistd.h>
00047 #endif
00048
00049 using std::endl ;
00050
00051 #include "SSLClient.h"
00052 #include "BESInternalError.h"
00053 #include "BESDebug.h"
00054
00055 SSLClient::SSLClient( const string &hostStr, int portVal,
00056 const string &cert_file, const string &cert_auth_file,
00057 const string &key_file )
00058 : SSLConnection(),
00059 _host( hostStr ),
00060 _port( portVal ),
00061 _cfile( cert_file ),
00062 _cafile( cert_auth_file),
00063 _kfile( key_file )
00064 {
00065 }
00066
00067 SSLClient::~SSLClient()
00068 {
00069 }
00070
00071 void
00072 SSLClient::initConnection()
00073 {
00074 BESDEBUG( "ppt", "Loading SSL error strings ... " << endl )
00075 SSL_load_error_strings() ;
00076 BESDEBUG( "ppt", "OK" << endl )
00077
00078 BESDEBUG( "ppt", "Initializing SSL library ... " << endl )
00079 SSL_library_init() ;
00080 BESDEBUG( "ppt", "OK" << endl )
00081
00082 #if OPENSSL_VERSION_NUMBER < 0x10000000L
00083 SSL_METHOD *method = NULL ;
00084 #else
00085 const SSL_METHOD *method = NULL ;
00086 #endif
00087 SSL_CTX *context = NULL ;
00088
00089 BESDEBUG( "ppt", "Creating method and context ... " << endl )
00090 method = SSLv3_client_method() ;
00091 if( method )
00092 {
00093 context = SSL_CTX_new( method ) ;
00094 }
00095 if( !context )
00096 {
00097 string msg = "Failed to create SSL context\n" ;
00098 msg += ERR_error_string( ERR_get_error(), NULL ) ;
00099 throw BESInternalError( msg, __FILE__, __LINE__ ) ;
00100 }
00101 else
00102 {
00103 BESDEBUG( "ppt", "OK" << endl )
00104 }
00105
00106 bool ok_2_continue = false ;
00107 string err_msg ;
00108 BESDEBUG( "ppt", "Setting certificate and key ... " << endl )
00109 if( SSL_CTX_use_certificate_file( context, _cfile.c_str(), SSL_FILETYPE_PEM ) <= 0 )
00110 {
00111 err_msg = "FAILED to use certificate file " + _cfile + "\n" ;
00112 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00113 }
00114 else if( SSL_CTX_use_PrivateKey_file( context, _kfile.c_str(), SSL_FILETYPE_PEM ) <= 0 )
00115 {
00116 err_msg = "FAILED to use private key file " + _kfile + "\n" ;
00117 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00118 }
00119 else if( !SSL_CTX_check_private_key( context ) )
00120 {
00121 err_msg = "FAILED to authenticate private key\n" ;
00122 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00123 }
00124 else
00125 {
00126 ok_2_continue = true ;
00127 }
00128
00129 if( ok_2_continue )
00130 {
00131 BESDEBUG( "ppt", "OK" << endl )
00132 BESDEBUG( "ppt", "Certificate setup ... " << endl )
00133 SSL_CTX_set_verify( context, SSL_VERIFY_PEER, SSLClient::verify_server ) ;
00134 SSL_CTX_set_client_CA_list( context, SSL_load_client_CA_file( _cafile.c_str() ));
00135 if( ( !SSL_CTX_load_verify_locations( context, _cafile.c_str(), NULL )) ||
00136 ( !SSL_CTX_set_default_verify_paths( context ) ) )
00137 {
00138 err_msg = "Certificate setup failed\n" ;
00139 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00140 ok_2_continue = false ;
00141 }
00142 }
00143
00144 int sock_fd = -1 ;
00145 if( ok_2_continue )
00146 {
00147 BESDEBUG( "ppt", "OK" << endl )
00148
00149 BESDEBUG( "ppt", "Establishing TCP connection to " << _host << ":" << _port << " ... " << endl )
00150 sock_fd = connect_to_server() ;
00151 if( sock_fd < 0 )
00152 {
00153 err_msg = "Failed to establish TCP connection" ;
00154 ok_2_continue = false ;
00155 }
00156 }
00157
00158 if( ok_2_continue )
00159 {
00160 BESDEBUG( "ppt", "OK" << endl )
00161
00162 BESDEBUG( "ppt", "Establishing secure connection ... " << endl )
00163 int ssl_ret = 0 ;
00164 _connection = SSL_new( context ) ;
00165 if( !_connection )
00166 {
00167 err_msg = "FAILED to create new connection\n" ;
00168 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00169 ok_2_continue = false ;
00170 }
00171 else if( ( ssl_ret = SSL_set_fd( _connection, sock_fd ) ) < 0 )
00172 {
00173 err_msg = "FAILED to set the socket descriptor\n" ;
00174 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00175 ok_2_continue = false ;
00176 }
00177 else if( ( ssl_ret = SSL_connect( _connection ) ) < 0 )
00178 {
00179 err_msg = "FAILED to create SSL connection\n" ;
00180 err_msg += ERR_error_string( SSL_get_error( _connection, ssl_ret ), NULL ) ;
00181 ok_2_continue = false ;
00182 }
00183 else if( verify_connection() < 0 )
00184 {
00185 err_msg = "FAILED to verify SSL connection\n" ;
00186 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00187 ok_2_continue = false ;
00188 }
00189 }
00190
00191 if( ok_2_continue )
00192 {
00193 BESDEBUG( "ppt", "OK" << endl )
00194 }
00195 else
00196 {
00197 BESDEBUG( "ppt", "FAILED" << endl )
00198 if( _context ) SSL_CTX_free( _context ) ; _context = NULL ;
00199 throw BESInternalError( err_msg, __FILE__, __LINE__ ) ;
00200 }
00201
00202 _connected = true ;
00203 }
00204
00205 int
00206 SSLClient::connect_to_server( )
00207 {
00208 int fd = -1 ;
00209 struct sockaddr_in addr ;
00210
00211 fd = socket( PF_INET, SOCK_STREAM, 0 ) ;
00212 if( fd < 0 ) return -1 ;
00213
00214 memset( &addr, 0, sizeof( addr ) ) ;
00215 addr.sin_family = AF_INET ;
00216 addr.sin_port = htons( _port ) ;
00217 if( isdigit( (int)*_host.c_str() ) )
00218 {
00219 addr.sin_addr.s_addr = inet_addr( _host.c_str() ) ;
00220 }
00221 else
00222 {
00223 struct hostent *hostEntry ;
00224 if( ( hostEntry = gethostbyname( _host.c_str() ) ) != 0 )
00225 {
00226 if ( hostEntry->h_length > sizeof(addr.sin_addr) )
00227 throw BESInternalError("Memory exception.", __FILE__, __LINE__);
00228 memcpy( &addr.sin_addr, hostEntry->h_addr, hostEntry->h_length ) ;
00229 }
00230 else
00231 {
00232 close( fd ) ;
00233 return -1 ;
00234 }
00235 }
00236 if( connect( fd, (struct sockaddr *)&addr, sizeof( addr ) ) < 0 )
00237 {
00238 close( fd ) ;
00239 return -1 ;
00240 }
00241
00242 return fd ;
00243 }
00244
00245 int
00246 SSLClient::verify_connection( )
00247 {
00248 X509 *server_cert = NULL ;
00249 char *str = NULL ;
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 return 1 ;
00260 }
00261
00262 int
00263 SSLClient::verify_server( int ok, X509_STORE_CTX *ctx )
00264 {
00265 if( ok )
00266 {
00267 BESDEBUG( "ppt", "VERIFIED " << endl )
00268 }
00269 else
00270 {
00271 char mybuf[256] ;
00272 X509 *err_cert ;
00273 int err ;
00274
00275 err_cert = X509_STORE_CTX_get_current_cert( ctx ) ;
00276 err = X509_STORE_CTX_get_error( ctx ) ;
00277 X509_NAME_oneline( X509_get_subject_name( err_cert ), mybuf, 256 ) ;
00278 BESDEBUG( "ppt", "FAILED for " << mybuf << endl )
00279 BESDEBUG( "ppt", " " << X509_verify_cert_error_string( err ) << endl )
00280 switch( ctx->error )
00281 {
00282 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
00283 {
00284 X509_NAME_oneline( X509_get_issuer_name( err_cert ), mybuf, 256 ) ;
00285 BESDEBUG( "ppt", " issuer = " << mybuf << endl )
00286 break ;
00287 }
00288
00289 case X509_V_ERR_CERT_NOT_YET_VALID:
00290 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
00291 {
00292 BESDEBUG( "ppt", " not yet valid!" << endl )
00293 break ;
00294 }
00295
00296 case X509_V_ERR_CERT_HAS_EXPIRED:
00297 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
00298 {
00299 BESDEBUG( "ppt", " expired!" << endl )
00300 break ;
00301 }
00302 }
00303 }
00304
00305 return 1 ;
00306 }
00307
00314 void
00315 SSLClient::dump( ostream &strm ) const
00316 {
00317 strm << BESIndent::LMarg << "SSLClient::dump - ("
00318 << (void *)this << ")" << endl ;
00319 BESIndent::Indent() ;
00320 strm << BESIndent::LMarg << "host: " << _host << endl ;
00321 strm << BESIndent::LMarg << "port: " << _port << endl ;
00322 strm << BESIndent::LMarg << "cert file: " << _cfile << endl ;
00323 strm << BESIndent::LMarg << "cert authority file: " << _cafile << endl ;
00324 strm << BESIndent::LMarg << "key file: " << _kfile << endl ;
00325 SSLConnection::dump( strm ) ;
00326 BESIndent::UnIndent() ;
00327 }
00328