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 "
00150 << _host << ":" << _port << " ... " << endl ) ;
00151 sock_fd = connect_to_server() ;
00152 if( sock_fd < 0 )
00153 {
00154 err_msg = "Failed to establish TCP connection" ;
00155 ok_2_continue = false ;
00156 }
00157 }
00158
00159 if( ok_2_continue )
00160 {
00161 BESDEBUG( "ppt", "OK" << endl ) ;
00162
00163 BESDEBUG( "ppt", "Establishing secure connection ... " << endl ) ;
00164 int ssl_ret = 0 ;
00165 _connection = SSL_new( context ) ;
00166 if( !_connection )
00167 {
00168 err_msg = "FAILED to create new connection\n" ;
00169 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00170 ok_2_continue = false ;
00171 }
00172 else if( ( ssl_ret = SSL_set_fd( _connection, sock_fd ) ) < 0 )
00173 {
00174 err_msg = "FAILED to set the socket descriptor\n" ;
00175 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00176 ok_2_continue = false ;
00177 }
00178 else if( ( ssl_ret = SSL_connect( _connection ) ) < 0 )
00179 {
00180 err_msg = "FAILED to create SSL connection\n" ;
00181 err_msg += ERR_error_string( SSL_get_error( _connection, ssl_ret ), NULL ) ;
00182 ok_2_continue = false ;
00183 }
00184 else if( verify_connection() < 0 )
00185 {
00186 err_msg = "FAILED to verify SSL connection\n" ;
00187 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00188 ok_2_continue = false ;
00189 }
00190 }
00191
00192 if( ok_2_continue )
00193 {
00194 BESDEBUG( "ppt", "OK" << endl ) ;
00195 }
00196 else
00197 {
00198 BESDEBUG( "ppt", "FAILED" << endl ) ;
00199 if( _context ) SSL_CTX_free( _context ) ; _context = NULL ;
00200 throw BESInternalError( err_msg, __FILE__, __LINE__ ) ;
00201 }
00202
00203 _connected = true ;
00204 }
00205
00206 int
00207 SSLClient::connect_to_server( )
00208 {
00209 int fd = -1 ;
00210 struct sockaddr_in addr ;
00211
00212 fd = socket( PF_INET, SOCK_STREAM, 0 ) ;
00213 if( fd < 0 ) return -1 ;
00214
00215 memset( &addr, 0, sizeof( addr ) ) ;
00216 addr.sin_family = AF_INET ;
00217 addr.sin_port = htons( _port ) ;
00218 if( isdigit( (int)*_host.c_str() ) )
00219 {
00220 addr.sin_addr.s_addr = inet_addr( _host.c_str() ) ;
00221 }
00222 else
00223 {
00224 struct hostent *hostEntry ;
00225 if( ( hostEntry = gethostbyname( _host.c_str() ) ) != 0 )
00226 {
00227 if ( hostEntry->h_length > sizeof(addr.sin_addr) )
00228 throw BESInternalError("Memory exception.", __FILE__, __LINE__);
00229 memcpy( &addr.sin_addr, hostEntry->h_addr, hostEntry->h_length ) ;
00230 }
00231 else
00232 {
00233 close( fd ) ;
00234 return -1 ;
00235 }
00236 }
00237 if( connect( fd, (struct sockaddr *)&addr, sizeof( addr ) ) < 0 )
00238 {
00239 close( fd ) ;
00240 return -1 ;
00241 }
00242
00243 return fd ;
00244 }
00245
00246 int
00247 SSLClient::verify_connection( )
00248 {
00249 X509 *server_cert = NULL ;
00250 char *str = NULL ;
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 return 1 ;
00261 }
00262
00263 int
00264 SSLClient::verify_server( int ok, X509_STORE_CTX *ctx )
00265 {
00266 if( ok )
00267 {
00268 BESDEBUG( "ppt", "VERIFIED " << endl ) ;
00269 }
00270 else
00271 {
00272 char mybuf[256] ;
00273 X509 *err_cert ;
00274 int err ;
00275
00276 err_cert = X509_STORE_CTX_get_current_cert( ctx ) ;
00277 err = X509_STORE_CTX_get_error( ctx ) ;
00278 X509_NAME_oneline( X509_get_subject_name( err_cert ), mybuf, 256 ) ;
00279 BESDEBUG( "ppt", "FAILED for " << mybuf << endl ) ;
00280 BESDEBUG( "ppt", " " << X509_verify_cert_error_string( err )
00281 << endl ) ;
00282 switch( ctx->error )
00283 {
00284 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
00285 {
00286 X509_NAME_oneline( X509_get_issuer_name( err_cert ), mybuf, 256 ) ;
00287 BESDEBUG( "ppt", " issuer = " << mybuf << endl ) ;
00288 break ;
00289 }
00290
00291 case X509_V_ERR_CERT_NOT_YET_VALID:
00292 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
00293 {
00294 BESDEBUG( "ppt", " not yet valid!" << endl ) ;
00295 break ;
00296 }
00297
00298 case X509_V_ERR_CERT_HAS_EXPIRED:
00299 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
00300 {
00301 BESDEBUG( "ppt", " expired!" << endl ) ;
00302 break ;
00303 }
00304 }
00305 }
00306
00307 return 1 ;
00308 }
00309
00316 void
00317 SSLClient::dump( ostream &strm ) const
00318 {
00319 strm << BESIndent::LMarg << "SSLClient::dump - ("
00320 << (void *)this << ")" << endl ;
00321 BESIndent::Indent() ;
00322 strm << BESIndent::LMarg << "host: " << _host << endl ;
00323 strm << BESIndent::LMarg << "port: " << _port << endl ;
00324 strm << BESIndent::LMarg << "cert file: " << _cfile << endl ;
00325 strm << BESIndent::LMarg << "cert authority file: " << _cafile << endl ;
00326 strm << BESIndent::LMarg << "key file: " << _kfile << endl ;
00327 SSLConnection::dump( strm ) ;
00328 BESIndent::UnIndent() ;
00329 }
00330