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

Generated on Wed May 12 09:53:08 2010 for OPeNDAP Hyrax Back End Server (BES) by  doxygen 1.4.7