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

Generated on Sat Jan 19 04:05:37 2008 for OPeNDAP Back End Server (BES) by  doxygen 1.5.4