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