00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "tlsgnutlsbase.h"
00016
00017 #ifdef HAVE_GNUTLS
00018
00019 #include <errno.h>
00020
00021 #include <cstdlib>
00022 #include <cstring>
00023
00024 namespace gloox
00025 {
00026
00027 GnuTLSBase::GnuTLSBase( TLSHandler *th, const std::string& server )
00028 : TLSBase( th, server ), m_session( new gnutls_session_t ), m_buf( 0 ), m_bufsize( 17000 )
00029 {
00030 m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
00031 }
00032
00033 GnuTLSBase::~GnuTLSBase()
00034 {
00035 free( m_buf );
00036 m_buf = 0;
00037 cleanup();
00038 delete m_session;
00039 gnutls_global_deinit();
00040 }
00041
00042 bool GnuTLSBase::encrypt( const std::string& data )
00043 {
00044 if( !m_secure )
00045 {
00046 handshake();
00047 return true;
00048 }
00049
00050 int ret = 0;
00051 std::string::size_type sum = 0;
00052 do
00053 {
00054 ret = gnutls_record_send( *m_session, data.c_str() + sum, data.length() - sum );
00055 sum += ret;
00056 }
00057 while( ( ret == GNUTLS_E_AGAIN ) || ( ret == GNUTLS_E_INTERRUPTED ) || sum < data.length() );
00058 return true;
00059 }
00060
00061 int GnuTLSBase::decrypt( const std::string& data )
00062 {
00063 m_recvBuffer += data;
00064
00065 if( !m_secure )
00066 {
00067 handshake();
00068 return data.length();
00069 }
00070
00071 int sum = 0;
00072 int ret = 0;
00073 do
00074 {
00075 ret = gnutls_record_recv( *m_session, m_buf, m_bufsize );
00076
00077 if( ret > 0 && m_handler )
00078 {
00079 m_handler->handleDecryptedData( this, std::string( m_buf, ret ) );
00080 sum += ret;
00081 }
00082 }
00083 while( ret > 0 );
00084
00085 return sum;
00086 }
00087
00088 void GnuTLSBase::cleanup()
00089 {
00090 TLSHandler* handler = m_handler;
00091 m_handler = 0;
00092 gnutls_bye( *m_session, GNUTLS_SHUT_RDWR );
00093 gnutls_db_remove_session( *m_session );
00094 gnutls_credentials_clear( *m_session );
00095 if( m_secure )
00096 gnutls_deinit( *m_session );
00097
00098 m_secure = false;
00099 m_valid = false;
00100 delete m_session;
00101 m_session = 0;
00102 m_session = new gnutls_session_t;
00103 m_handler = handler;
00104 }
00105
00106 bool GnuTLSBase::handshake()
00107 {
00108 if( !m_handler )
00109 return false;
00110
00111 int ret = gnutls_handshake( *m_session );
00112 if( ret < 0 && gnutls_error_is_fatal( ret ) )
00113 {
00114 gnutls_perror( ret );
00115 gnutls_db_remove_session( *m_session );
00116 gnutls_deinit( *m_session );
00117 m_valid = false;
00118
00119 m_handler->handleHandshakeResult( this, false, m_certInfo );
00120 return false;
00121 }
00122 else if( ret == GNUTLS_E_AGAIN )
00123 {
00124 return true;
00125 }
00126
00127 m_secure = true;
00128
00129 getCertInfo();
00130
00131 m_handler->handleHandshakeResult( this, true, m_certInfo );
00132 return true;
00133 }
00134
00135 ssize_t GnuTLSBase::pullFunc( void *data, size_t len )
00136 {
00137 ssize_t cpy = ( len > m_recvBuffer.length() ) ? ( m_recvBuffer.length() ) : ( len );
00138 if( cpy > 0 )
00139 {
00140 memcpy( data, (const void*)m_recvBuffer.c_str(), cpy );
00141 m_recvBuffer.erase( 0, cpy );
00142 return cpy;
00143 }
00144 else
00145 {
00146 errno = EAGAIN;
00147 return GNUTLS_E_AGAIN;
00148 }
00149 }
00150
00151 ssize_t GnuTLSBase::pullFunc( gnutls_transport_ptr_t ptr, void *data, size_t len )
00152 {
00153 return static_cast<GnuTLSBase*>( ptr )->pullFunc( data, len );
00154 }
00155
00156 ssize_t GnuTLSBase::pushFunc( const void *data, size_t len )
00157 {
00158 if( m_handler )
00159 m_handler->handleEncryptedData( this, std::string( (const char*)data, len ) );
00160
00161 return len;
00162 }
00163
00164 ssize_t GnuTLSBase::pushFunc( gnutls_transport_ptr_t ptr, const void *data, size_t len )
00165 {
00166 return static_cast<GnuTLSBase*>( ptr )->pushFunc( data, len );
00167 }
00168
00169 }
00170
00171 #endif // HAVE_GNUTLS