SSLClient.cc

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

Generated on Fri Nov 30 12:06:49 2007 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1