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