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