ulxr_ssl_connection.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                 ulxr_ssl_connection.cpp  -  ssl connection
00003                              -------------------
00004     begin                : Mon May 3 2004
00005     copyright            : (C) 2002-2007 by Ewald Arnold
00006     email                : ulxmlrpcpp@ewald-arnold.de
00007 
00008     $Id: ulxr_ssl_connection.cpp 1063 2007-08-19 11:46:20Z ewald-arnold $
00009 
00010  ***************************************************************************/
00011 
00012 /**************************************************************************
00013  *
00014  * This program is free software; you can redistribute it and/or modify
00015  * it under the terms of the GNU Lesser General Public License as
00016  * published by the Free Software Foundation; either version 2 of the License,
00017  * or (at your option) any later version.
00018  *
00019  * This program is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU Lesser General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027  *
00028  ***************************************************************************/
00029 
00030 // #define ULXR_SHOW_TRACE
00031 // #define ULXR_DEBUG_OUTPUT
00032 // #define ULXR_SHOW_READ
00033 // #define ULXR_SHOW_WRITE
00034 
00035 #define ULXR_NEED_EXPORTS
00036 #include <ulxmlrpcpp/ulxmlrpcpp.h>  // always first header
00037 
00038 #ifdef ULXR_INCLUDE_SSL_STUFF
00039 
00040 #include <openssl/err.h>
00041 #include <ulxmlrpcpp/ulxr_ssl_connection.h>
00042 #include <ulxmlrpcpp/ulxr_except.h>
00043 
00044 
00045 static int s_server_session_id_context      = 1;
00046 static int s_server_auth_session_id_context = 2;
00047 
00048 namespace ulxr {
00049 
00050 
00051 bool SSLConnection::ssl_initialized = false;
00052 
00053 
00054 static int password_cb(char *buf,int num, int /*rwflag*/, void *userdata)
00055 {
00056   ULXR_TRACE(ULXR_PCHAR("password_cb"));
00057   SSLConnection *conn = (SSLConnection *)userdata;
00058   std::string pass = conn->getPassword();
00059 
00060   if(num < (int)pass.length()+1)
00061     return 0;
00062 
00063   strcpy(buf, pass.c_str());
00064   return(strlen(buf));
00065 }
00066 
00067 
00068 ULXR_API_IMPL0 SSLConnection::SSLConnection(bool I_am_server, const CppString &domain, unsigned port)
00069  : TcpIpConnection(I_am_server, domain, port)
00070 {
00071   ULXR_TRACE(ULXR_PCHAR("SSLConnection"));
00072   init();
00073 }
00074 
00075 
00076 ULXR_API_IMPL0 SSLConnection::SSLConnection(bool I_am_server, long adr, unsigned port)
00077  : TcpIpConnection(I_am_server, adr, port)
00078 {
00079   ULXR_TRACE(ULXR_PCHAR("SSLConnection"));
00080   init();
00081 }
00082 
00083 
00084 ULXR_API_IMPL(void)
00085   SSLConnection::setCryptographyData (const std::string &in_password,
00086                                       const std::string &in_certfile,
00087                                       const std::string &in_keyfile)
00088 {
00089   password = in_password;
00090   keyfile = in_keyfile;
00091   certfile = in_certfile;
00092 }
00093 
00094 
00095 ULXR_API_IMPL(void) SSLConnection::initializeCTX()
00096 {
00097   ULXR_TRACE(ULXR_PCHAR("initializeCTX"));
00098   SSL_METHOD *meth = SSLv23_method();
00099   ssl_ctx = SSL_CTX_new (meth);
00100   if (!ssl_ctx)
00101   {
00102     ERR_print_errors_fp(stderr);
00103     exit(2);
00104   }
00105 
00106   SSL_CTX_set_default_passwd_cb(ssl_ctx, password_cb);
00107   SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, this);
00108 
00109   ssl = 0;
00110 
00111   if (isServerMode())
00112   {
00113     if (0 >= SSL_CTX_set_session_id_context(ssl_ctx,
00114       (const unsigned char *)&s_server_session_id_context,
00115       sizeof s_server_session_id_context))
00116     {
00117       ERR_print_errors_fp(stderr);
00118       exit(2);
00119     }
00120   }
00121 }
00122 
00123 
00124 ULXR_API_IMPL(void) SSLConnection::init()
00125 {
00126   ULXR_TRACE(ULXR_PCHAR("init"));
00127   session = 0;
00128 
00129   if (!ssl_initialized)
00130   {
00131     SSL_library_init();
00132     SSLeay_add_ssl_algorithms();
00133     SSL_load_error_strings();
00134     ssl_initialized = true;
00135   }
00136 
00137   initializeCTX();
00138 }
00139 
00140 
00141 ULXR_API_IMPL0 SSLConnection::~SSLConnection()
00142 {
00143   ULXR_TRACE(ULXR_PCHAR("~SSLConnection"));
00144   if (ssl_ctx != 0)
00145     SSL_CTX_free(ssl_ctx);
00146   ssl_ctx = 0;
00147 
00148   ULXR_TRACE(ULXR_PCHAR("~SSLConnection 2"));
00149 
00150   if (0 != session)
00151     SSL_SESSION_free(session);
00152   session = 0;
00153 }
00154 
00155 
00156 ULXR_API_IMPL(void) SSLConnection::close()
00157 {
00158   ULXR_TRACE(ULXR_PCHAR("close"));
00159 
00160   if (!isServerMode()) // clients keep session
00161   {
00162     if (0 != session)
00163       SSL_SESSION_free(session);
00164 
00165     session = SSL_get1_session(ssl);
00166   }
00167 
00168   ULXR_TRACE(ULXR_PCHAR("close 2"));
00169 
00170   TcpIpConnection::close();
00171   if (ssl != 0)
00172     SSL_free(ssl);
00173   ssl = 0;
00174 }
00175 
00176 
00177 ULXR_API_IMPL(ssize_t) SSLConnection::low_level_write(char const *buff, long len)
00178 {
00179   ULXR_TRACE(ULXR_PCHAR("low_level_write"));
00180   ssize_t ret;
00181 
00182   if (isConnecting())
00183     return TcpIpConnection::low_level_write(buff, len);
00184 
00185   while (true)
00186   {
00187     ULXR_TRACE(ULXR_PCHAR("low_level_write 2"));
00188     ret = SSL_write(ssl, buff, len);
00189     ULXR_TRACE(ULXR_PCHAR("low_level_write 3 ") << ret);
00190 
00191     if (ret >= 0)
00192       break;
00193 
00194     ULXR_TRACE(ULXR_PCHAR("low_level_write 4"));
00195     switch (SSL_get_error(ssl, ret))
00196     {
00197       case SSL_ERROR_NONE:
00198         ULXR_TRACE(ULXR_PCHAR("SSL_ERROR_NONE"));
00199         break;
00200 
00201       case SSL_ERROR_WANT_WRITE:
00202         ULXR_TRACE(ULXR_PCHAR("SSL_ERROR_WANT_WRITE"));
00203         continue;
00204 
00205       default:
00206         ULXR_TRACE(ULXR_PCHAR("default"));
00207         throw ConnectionException(SystemError,
00208                                   ulxr_i18n(ULXR_PCHAR("Could not perform SSL_write() call: ")), 500);
00209     }
00210   }
00211   ULXR_TRACE(ULXR_PCHAR("/low_level_write ") << ret);
00212   return ret;
00213 }
00214 
00215 
00216 ULXR_API_IMPL(bool) SSLConnection::hasPendingInput() const
00217 {
00218   ULXR_TRACE(ULXR_PCHAR("hasPendingInput "));
00219 
00220   if (isConnecting())
00221     return TcpIpConnection::hasPendingInput();
00222 
00223   int avail = SSL_pending(ssl);
00224   ULXR_TRACE(ULXR_PCHAR("hasPendingInput ") << avail);
00225   return avail != 0;
00226 }
00227 
00228 
00229 ULXR_API_IMPL(ssize_t) SSLConnection::low_level_read(char *buff, long len)
00230 {
00231   ULXR_TRACE(ULXR_PCHAR("low_level_read"));
00232   ssize_t ret;
00233 
00234   if (isConnecting())
00235     return TcpIpConnection::low_level_read(buff, len);
00236 
00237   while (true)
00238   {
00239     ULXR_TRACE(ULXR_PCHAR("low_level_read 2"));
00240     ret = SSL_read(ssl, buff, len);
00241     ULXR_TRACE(ULXR_PCHAR("low_level_read 3 ") << ret);
00242 
00243     if (ret >= 0)
00244       break;
00245 
00246     ULXR_TRACE(ULXR_PCHAR("low_level_read 4"));
00247     switch (SSL_get_error(ssl, ret))
00248     {
00249       case SSL_ERROR_NONE:
00250         ULXR_TRACE(ULXR_PCHAR("SSL_ERROR_NONE"));
00251         break;
00252 
00253       case SSL_ERROR_WANT_READ:
00254         ULXR_TRACE(ULXR_PCHAR("SSL_ERROR_WANT_READ"));
00255         continue;
00256 
00257       default:
00258         ULXR_TRACE(ULXR_PCHAR("default"));
00259         throw ConnectionException(SystemError,
00260                                   ulxr_i18n(ULXR_PCHAR("Could not perform SSL_read() call: ")), 500);
00261     }
00262   }
00263   ULXR_TRACE(ULXR_PCHAR("/low_level_read ") << ret);
00264   return ret;
00265 }
00266 
00267 
00268 TcpIpConnection *ULXR_API_IMPL0 SSLConnection::makeClone()
00269 {
00270   return new SSLConnection(*this); // shallow copy !!
00271 }
00272 
00273 
00274 ULXR_API_IMPL(void) SSLConnection::createSSL()
00275 {
00276   ULXR_TRACE(ULXR_PCHAR("createSSL"));
00277   ssl = SSL_new (ssl_ctx);
00278   if (ssl == 0)
00279     throw ConnectionException(SystemError,
00280                           ulxr_i18n(ULXR_PCHAR("problem creating SSL conext object")), 500);
00281 
00282   int err = SSL_set_fd (ssl, getHandle());
00283   if (err == 0)
00284     throw ConnectionException(SystemError,
00285                           ulxr_i18n(ULXR_PCHAR("problem set file descriptor for SSL")), 500);
00286 
00287   if (isServerMode())
00288   {
00289     if (0 >= SSL_set_session_id_context(ssl,
00290       (const unsigned char *)&s_server_auth_session_id_context,
00291       sizeof(s_server_auth_session_id_context)))
00292     {
00293       ERR_print_errors_fp(stderr);
00294       exit(2);
00295     }
00296   }
00297 }
00298 
00299 
00300 ULXR_API_IMPL(void) SSLConnection::open()
00301 {
00302   ULXR_TRACE(ULXR_PCHAR("open"));
00303 
00304   TcpIpConnection::open();
00305 
00306   doConnect();  // CONNECT in non-SSL mode!
00307 
00308   int err;
00309   createSSL();
00310 
00311   if (0 != session)
00312   {
00313     ULXR_TRACE(ULXR_PCHAR("SSL_set_session"));
00314     SSL_set_session(ssl, session);
00315   }
00316 
00317   err = SSL_connect (ssl);
00318   if (err == 0)
00319     throw ConnectionException(SystemError,
00320                           ulxr_i18n(ULXR_PCHAR("problem starting SSL connection (client mode)")), 500);
00321 }
00322 
00323 
00324 ULXR_API_IMPL(bool) SSLConnection::accept(int in_timeout)
00325 {
00326   ULXR_TRACE(ULXR_PCHAR("accept"));
00327 
00328   if (SSL_CTX_use_certificate_file(ssl_ctx, certfile.c_str(), SSL_FILETYPE_PEM) <= 0) {
00329 //    ERR_print_errors_fp(stderr);
00330     throw ConnectionException(SystemError,
00331                           ulxr_i18n(ULXR_PCHAR("problem setting up certificate")), 500);
00332   }
00333 
00334   if (SSL_CTX_use_PrivateKey_file(ssl_ctx, keyfile.c_str(), SSL_FILETYPE_PEM) <= 0)
00335   {
00336 //    ERR_print_errors_fp(stderr);
00337     throw ConnectionException(SystemError,
00338                           ulxr_i18n(ULXR_PCHAR("problem setting up private key")), 500);
00339   }
00340 
00341 
00342   if (!TcpIpConnection::accept(in_timeout))
00343     return false;
00344 
00345   createSSL();
00346   int err = SSL_accept (ssl);
00347   if (err == 0)
00348     throw ConnectionException(SystemError,
00349                           ulxr_i18n(ULXR_PCHAR("problem starting SSL connection (server mode)")), 500);
00350 
00351   /* Get the cipher - opt */
00352   ULXR_TRACE(ULXR_PCHAR("SSL connection using ") << ULXR_GET_STRING(SSL_get_cipher (ssl)));
00353   return true;
00354 }
00355 
00356 
00357 ULXR_API_IMPL(CppString) SSLConnection::getInterfaceName()
00358 {
00359   ULXR_TRACE(ULXR_PCHAR("getInterfaceName"));
00360   return ULXR_PCHAR("ssl");
00361 }
00362 
00363 
00364 ULXR_API_IMPL(void) SSLConnection::cut()
00365 {
00366   ULXR_TRACE(ULXR_PCHAR("cut"));
00367   TcpIpConnection::cut();
00368   initializeCTX();
00369 }
00370 
00371 
00372 ULXR_API_IMPL(std::string) SSLConnection::getPassword() const
00373 {
00374   return password;
00375 }
00376 
00377 
00378 ULXR_API_IMPL(SSL *) SSLConnection::getSslObject() const
00379 {
00380   return ssl;
00381 }
00382 
00383 
00384 ULXR_API_IMPL(SSL_CTX *) SSLConnection::getSslContextObject() const
00385 {
00386   return ssl_ctx;
00387 }
00388 
00389 
00390 ULXR_API_IMPL(SSL_SESSION *) SSLConnection::getSslSessionObject() const
00391 {
00392   return session;
00393 }
00394 
00395 
00396 }  // namespace ulxr
00397 
00398 #endif // ULXR_INCLUDE_SSL_STUFF

Generated on Sun Aug 19 20:08:57 2007 for ulxmlrpcpp by  doxygen 1.5.1