gloox 1.0
|
00001 /* 00002 Copyright (c) 2005-2009 by Jakob Schroeter <js@camaya.net> 00003 This file is part of the gloox library. http://camaya.net/gloox 00004 00005 This software is distributed under a license. The full license 00006 agreement can be found in the file LICENSE in this distribution. 00007 This software may not be copied, modified, sold or distributed 00008 other than expressed in the named license agreement. 00009 00010 This software is distributed without any warranty. 00011 */ 00012 00013 00014 00015 #include "tlsgnutlsbase.h" 00016 00017 #ifdef HAVE_GNUTLS 00018 00019 #include <errno.h> 00020 #include <stdlib.h> 00021 #include <string.h> 00022 00023 #include <cstdlib> 00024 #include <cstring> 00025 00026 namespace gloox 00027 { 00028 00029 GnuTLSBase::GnuTLSBase( TLSHandler* th, const std::string& server ) 00030 : TLSBase( th, server ), m_session( new gnutls_session_t ), m_buf( 0 ), m_bufsize( 17000 ) 00031 { 00032 m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) ); 00033 } 00034 00035 GnuTLSBase::~GnuTLSBase() 00036 { 00037 free( m_buf ); 00038 m_buf = 0; 00039 cleanup(); 00040 delete m_session; 00041 // FIXME: It segfaults if more then one account uses 00042 // encryption at same time, so we comment it for now. 00043 // Do we need to deinit at all? 00044 // gnutls_global_deinit(); 00045 } 00046 00047 bool GnuTLSBase::encrypt( const std::string& data ) 00048 { 00049 if( !m_secure ) 00050 { 00051 handshake(); 00052 return true; 00053 } 00054 00055 ssize_t ret = 0; 00056 std::string::size_type sum = 0; 00057 do 00058 { 00059 ret = gnutls_record_send( *m_session, data.c_str() + sum, data.length() - sum ); 00060 sum += ret; 00061 } 00062 while( ( ret == GNUTLS_E_AGAIN ) || ( ret == GNUTLS_E_INTERRUPTED ) || sum < data.length() ); 00063 return true; 00064 } 00065 00066 int GnuTLSBase::decrypt( const std::string& data ) 00067 { 00068 m_recvBuffer += data; 00069 00070 if( !m_secure ) 00071 { 00072 handshake(); 00073 return static_cast<int>( data.length() ); 00074 } 00075 00076 int sum = 0; 00077 int ret = 0; 00078 do 00079 { 00080 ret = static_cast<int>( gnutls_record_recv( *m_session, m_buf, m_bufsize ) ); 00081 00082 if( ret > 0 && m_handler ) 00083 { 00084 m_handler->handleDecryptedData( this, std::string( m_buf, ret ) ); 00085 sum += ret; 00086 } 00087 } 00088 while( ret > 0 ); 00089 00090 return sum; 00091 } 00092 00093 void GnuTLSBase::cleanup() 00094 { 00095 if( !m_mutex.trylock() ) 00096 return; 00097 00098 TLSHandler* handler = m_handler; 00099 m_handler = 0; 00100 gnutls_bye( *m_session, GNUTLS_SHUT_RDWR ); 00101 gnutls_db_remove_session( *m_session ); 00102 gnutls_credentials_clear( *m_session ); 00103 if( m_secure ) 00104 gnutls_deinit( *m_session ); 00105 00106 m_secure = false; 00107 m_valid = false; 00108 delete m_session; 00109 m_session = 0; 00110 m_session = new gnutls_session_t; 00111 m_handler = handler; 00112 00113 m_mutex.unlock(); 00114 } 00115 00116 bool GnuTLSBase::handshake() 00117 { 00118 if( !m_handler ) 00119 return false; 00120 00121 int ret = gnutls_handshake( *m_session ); 00122 if( ret < 0 && gnutls_error_is_fatal( ret ) ) 00123 { 00124 gnutls_perror( ret ); 00125 gnutls_db_remove_session( *m_session ); 00126 gnutls_deinit( *m_session ); 00127 m_valid = false; 00128 00129 m_handler->handleHandshakeResult( this, false, m_certInfo ); 00130 return false; 00131 } 00132 else if( ret == GNUTLS_E_AGAIN ) 00133 { 00134 return true; 00135 } 00136 00137 m_secure = true; 00138 00139 getCertInfo(); 00140 00141 m_handler->handleHandshakeResult( this, true, m_certInfo ); 00142 return true; 00143 } 00144 00145 ssize_t GnuTLSBase::pullFunc( void* data, size_t len ) 00146 { 00147 ssize_t cpy = ( len > m_recvBuffer.length() ) ? ( m_recvBuffer.length() ) : ( len ); 00148 if( cpy > 0 ) 00149 { 00150 memcpy( data, (const void*)m_recvBuffer.c_str(), cpy ); 00151 m_recvBuffer.erase( 0, cpy ); 00152 return cpy; 00153 } 00154 else 00155 { 00156 errno = EAGAIN; 00157 return GNUTLS_E_AGAIN; 00158 } 00159 } 00160 00161 ssize_t GnuTLSBase::pullFunc( gnutls_transport_ptr_t ptr, void* data, size_t len ) 00162 { 00163 return static_cast<GnuTLSBase*>( ptr )->pullFunc( data, len ); 00164 } 00165 00166 ssize_t GnuTLSBase::pushFunc( const void* data, size_t len ) 00167 { 00168 if( m_handler ) 00169 m_handler->handleEncryptedData( this, std::string( (const char*)data, len ) ); 00170 00171 return len; 00172 } 00173 00174 ssize_t GnuTLSBase::pushFunc( gnutls_transport_ptr_t ptr, const void* data, size_t len ) 00175 { 00176 return static_cast<GnuTLSBase*>( ptr )->pushFunc( data, len ); 00177 } 00178 00179 } 00180 00181 #endif // HAVE_GNUTLS