SSLServer.cc

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

Generated on Tue Mar 4 23:13:37 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.1