OPeNDAP Hyrax Back End Server (BES) Updated for version 3.8.3
|
00001 // SSLClient.cc 00002 00003 // This file is part of bes, A C++ back-end server implementation framework 00004 // for the OPeNDAP Data Access Protocol. 00005 00006 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research 00007 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu> 00008 // 00009 // This library is free software; you can redistribute it and/or 00010 // modify it under the terms of the GNU Lesser General Public 00011 // License as published by the Free Software Foundation; either 00012 // version 2.1 of the License, or (at your option) any later version. 00013 // 00014 // This library is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 // Lesser General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Lesser General Public 00020 // License along with this library; if not, write to the Free Software 00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00022 // 00023 // You can contact University Corporation for Atmospheric Research at 00024 // 3080 Center Green Drive, Boulder, CO 80301 00025 00026 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005 00027 // Please read the full copyright statement in the file COPYRIGHT_UCAR. 00028 // 00029 // Authors: 00030 // pwest Patrick West <pwest@ucar.edu> 00031 // jgarcia Jose Garcia <jgarcia@ucar.edu> 00032 00033 #include "config.h" 00034 00035 #include <openssl/ssl.h> 00036 #include <openssl/err.h> 00037 #include <sys/socket.h> // for socket connect 00038 #include <netinet/in.h> // for inet_addr 00039 #include <arpa/inet.h> // for htons 00040 #include <netdb.h> // for gethostbyname 00041 #include <ctype.h> // for isdigit 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 server_cert = SSL_get_peer_certificate( _connection ) ; 00254 if( server_cert == NULL ) 00255 { 00256 cout << "server doesn't have a certificate" << endl ; 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