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 SSL_METHOD *method = NULL ;
00083 SSL_CTX *context = NULL ;
00084
00085 BESDEBUG( "ppt", "Creating method and context ... " << endl ) ;
00086 method = SSLv3_client_method() ;
00087 if( method )
00088 {
00089 context = SSL_CTX_new( method ) ;
00090 }
00091 if( !context )
00092 {
00093 string msg = "Failed to create SSL context\n" ;
00094 msg += ERR_error_string( ERR_get_error(), NULL ) ;
00095 throw BESInternalError( msg, __FILE__, __LINE__ ) ;
00096 }
00097 else
00098 {
00099 BESDEBUG( "ppt", "OK" << endl ) ;
00100 }
00101
00102 bool ok_2_continue = false ;
00103 string err_msg ;
00104 BESDEBUG( "ppt", "Setting certificate and key ... " << endl ) ;
00105 if( SSL_CTX_use_certificate_file( context, _cfile.c_str(), SSL_FILETYPE_PEM ) <= 0 )
00106 {
00107 err_msg = "FAILED to use certificate file " + _cfile + "\n" ;
00108 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00109 }
00110 else if( SSL_CTX_use_PrivateKey_file( context, _kfile.c_str(), SSL_FILETYPE_PEM ) <= 0 )
00111 {
00112 err_msg = "FAILED to use private key file " + _kfile + "\n" ;
00113 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00114 }
00115 else if( !SSL_CTX_check_private_key( context ) )
00116 {
00117 err_msg = "FAILED to authenticate private key\n" ;
00118 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00119 }
00120 else
00121 {
00122 ok_2_continue = true ;
00123 }
00124
00125 if( ok_2_continue )
00126 {
00127 BESDEBUG( "ppt", "OK" << endl ) ;
00128 BESDEBUG( "ppt", "Certificate setup ... " << endl ) ;
00129 SSL_CTX_set_verify( context, SSL_VERIFY_PEER, SSLClient::verify_server ) ;
00130 SSL_CTX_set_client_CA_list( context, SSL_load_client_CA_file( _cafile.c_str() ));
00131 if( ( !SSL_CTX_load_verify_locations( context, _cafile.c_str(), NULL )) ||
00132 ( !SSL_CTX_set_default_verify_paths( context ) ) )
00133 {
00134 err_msg = "Certificate setup failed\n" ;
00135 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00136 ok_2_continue = false ;
00137 }
00138 }
00139
00140 int sock_fd = -1 ;
00141 if( ok_2_continue )
00142 {
00143 BESDEBUG( "ppt", "OK" << endl ) ;
00144
00145 BESDEBUG( "ppt", "Establishing TCP connection to "
00146 << _host << ":" << _port << " ... " << endl ) ;
00147 sock_fd = connect_to_server() ;
00148 if( sock_fd < 0 )
00149 {
00150 err_msg = "Failed to establish TCP connection" ;
00151 ok_2_continue = false ;
00152 }
00153 }
00154
00155 if( ok_2_continue )
00156 {
00157 BESDEBUG( "ppt", "OK" << endl ) ;
00158
00159 BESDEBUG( "ppt", "Establishing secure connection ... " << endl ) ;
00160 int ssl_ret = 0 ;
00161 _connection = SSL_new( context ) ;
00162 if( !_connection )
00163 {
00164 err_msg = "FAILED to create new connection\n" ;
00165 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00166 ok_2_continue = false ;
00167 }
00168 else if( ( ssl_ret = SSL_set_fd( _connection, sock_fd ) ) < 0 )
00169 {
00170 err_msg = "FAILED to set the socket descriptor\n" ;
00171 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00172 ok_2_continue = false ;
00173 }
00174 else if( ( ssl_ret = SSL_connect( _connection ) ) < 0 )
00175 {
00176 err_msg = "FAILED to create SSL connection\n" ;
00177 err_msg += ERR_error_string( SSL_get_error( _connection, ssl_ret ), NULL ) ;
00178 ok_2_continue = false ;
00179 }
00180 else if( verify_connection() < 0 )
00181 {
00182 err_msg = "FAILED to verify SSL connection\n" ;
00183 err_msg += ERR_error_string( ERR_get_error(), NULL ) ;
00184 ok_2_continue = false ;
00185 }
00186 }
00187
00188 if( ok_2_continue )
00189 {
00190 BESDEBUG( "ppt", "OK" << endl ) ;
00191 }
00192 else
00193 {
00194 BESDEBUG( "ppt", "FAILED" << endl ) ;
00195 if( _context ) SSL_CTX_free( _context ) ; _context = NULL ;
00196 throw BESInternalError( err_msg, __FILE__, __LINE__ ) ;
00197 }
00198
00199 _connected = true ;
00200 }
00201
00202 int
00203 SSLClient::connect_to_server( )
00204 {
00205 int fd = -1 ;
00206 struct sockaddr_in addr ;
00207
00208 fd = socket( PF_INET, SOCK_STREAM, 0 ) ;
00209 if( fd < 0 ) return -1 ;
00210
00211 memset( &addr, 0, sizeof( addr ) ) ;
00212 addr.sin_family = AF_INET ;
00213 addr.sin_port = htons( _port ) ;
00214 if( isdigit( (int)*_host.c_str() ) )
00215 {
00216 addr.sin_addr.s_addr = inet_addr( _host.c_str() ) ;
00217 }
00218 else
00219 {
00220 struct hostent *hostEntry ;
00221 if( ( hostEntry = gethostbyname( _host.c_str() ) ) != 0 )
00222 {
00223 if ( hostEntry->h_length > sizeof(addr.sin_addr) )
00224 throw BESInternalError("Memory exception.", __FILE__, __LINE__);
00225 memcpy( &addr.sin_addr, hostEntry->h_addr, hostEntry->h_length ) ;
00226 }
00227 else
00228 {
00229 close( fd ) ;
00230 return -1 ;
00231 }
00232 }
00233 if( connect( fd, (struct sockaddr *)&addr, sizeof( addr ) ) < 0 )
00234 {
00235 close( fd ) ;
00236 return -1 ;
00237 }
00238
00239 return fd ;
00240 }
00241
00242 int
00243 SSLClient::verify_connection( )
00244 {
00245 X509 *server_cert = NULL ;
00246 char *str = NULL ;
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 return 1 ;
00257 }
00258
00259 int
00260 SSLClient::verify_server( int ok, X509_STORE_CTX *ctx )
00261 {
00262 if( ok )
00263 {
00264 BESDEBUG( "ppt", "VERIFIED " << endl ) ;
00265 }
00266 else
00267 {
00268 char mybuf[256] ;
00269 X509 *err_cert ;
00270 int err ;
00271
00272 err_cert = X509_STORE_CTX_get_current_cert( ctx ) ;
00273 err = X509_STORE_CTX_get_error( ctx ) ;
00274 X509_NAME_oneline( X509_get_subject_name( err_cert ), mybuf, 256 ) ;
00275 BESDEBUG( "ppt", "FAILED for " << mybuf << endl ) ;
00276 BESDEBUG( "ppt", " " << X509_verify_cert_error_string( err )
00277 << endl ) ;
00278 switch( ctx->error )
00279 {
00280 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
00281 {
00282 X509_NAME_oneline( X509_get_issuer_name( err_cert ), mybuf, 256 ) ;
00283 BESDEBUG( "ppt", " issuer = " << mybuf << endl ) ;
00284 break ;
00285 }
00286
00287 case X509_V_ERR_CERT_NOT_YET_VALID:
00288 case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
00289 {
00290 BESDEBUG( "ppt", " not yet valid!" << endl ) ;
00291 break ;
00292 }
00293
00294 case X509_V_ERR_CERT_HAS_EXPIRED:
00295 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
00296 {
00297 BESDEBUG( "ppt", " expired!" << endl ) ;
00298 break ;
00299 }
00300 }
00301 }
00302
00303 return 1 ;
00304 }
00305
00312 void
00313 SSLClient::dump( ostream &strm ) const
00314 {
00315 strm << BESIndent::LMarg << "SSLClient::dump - ("
00316 << (void *)this << ")" << endl ;
00317 BESIndent::Indent() ;
00318 strm << BESIndent::LMarg << "host: " << _host << endl ;
00319 strm << BESIndent::LMarg << "port: " << _port << endl ;
00320 strm << BESIndent::LMarg << "cert file: " << _cfile << endl ;
00321 strm << BESIndent::LMarg << "cert authority file: " << _cafile << endl ;
00322 strm << BESIndent::LMarg << "key file: " << _kfile << endl ;
00323 SSLConnection::dump( strm ) ;
00324 BESIndent::UnIndent() ;
00325 }
00326