gloox  1.0.1
tlsgnutlsbase.cpp
1 /*
2  Copyright (c) 2005-2012 by Jakob Schroeter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 
14 
15 #include "tlsgnutlsbase.h"
16 
17 #ifdef HAVE_GNUTLS
18 
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <string.h>
22 
23 namespace gloox
24 {
25 
26  GnuTLSBase::GnuTLSBase( TLSHandler* th, const std::string& server )
27  : TLSBase( th, server ), m_session( new gnutls_session_t ), m_buf( 0 ), m_bufsize( 17000 )
28  {
29  m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
30  }
31 
33  {
34  free( m_buf );
35  m_buf = 0;
36  cleanup();
37  delete m_session;
38 // FIXME: It segfaults if more then one account uses
39 // encryption at same time, so we comment it for now.
40 // Do we need to deinit at all?
41 // gnutls_global_deinit();
42  }
43 
44  bool GnuTLSBase::encrypt( const std::string& data )
45  {
46  if( !m_secure )
47  {
48  handshake();
49  return true;
50  }
51 
52  ssize_t ret = 0;
53  std::string::size_type sum = 0;
54  do
55  {
56  ret = gnutls_record_send( *m_session, data.c_str() + sum, data.length() - sum );
57  sum += ret;
58  }
59  while( ( ret == GNUTLS_E_AGAIN ) || ( ret == GNUTLS_E_INTERRUPTED ) || sum < data.length() );
60  return true;
61  }
62 
63  int GnuTLSBase::decrypt( const std::string& data )
64  {
65  m_recvBuffer += data;
66 
67  if( !m_secure )
68  {
69  handshake();
70  return static_cast<int>( data.length() );
71  }
72 
73  int sum = 0;
74  int ret = 0;
75  do
76  {
77  ret = static_cast<int>( gnutls_record_recv( *m_session, m_buf, m_bufsize ) );
78 
79  if( ret > 0 && m_handler )
80  {
81  m_handler->handleDecryptedData( this, std::string( m_buf, ret ) );
82  sum += ret;
83  }
84  }
85  while( ret > 0 );
86 
87  return sum;
88  }
89 
91  {
92  if( !m_mutex.trylock() )
93  return;
94 
95  TLSHandler* handler = m_handler;
96  m_handler = 0;
97  gnutls_bye( *m_session, GNUTLS_SHUT_RDWR );
98  gnutls_db_remove_session( *m_session );
99  gnutls_credentials_clear( *m_session );
100  if( m_session )
101  gnutls_deinit( *m_session );
102 
103  delete m_session;
104 
105  m_secure = false;
106  m_valid = false;
107  m_session = 0;
108  m_session = new gnutls_session_t;
109  m_handler = handler;
110 
111  m_mutex.unlock();
112  }
113 
115  {
116  if( !m_handler )
117  return false;
118 
119  int ret = gnutls_handshake( *m_session );
120  if( ret < 0 && gnutls_error_is_fatal( ret ) )
121  {
122  gnutls_perror( ret );
123  gnutls_db_remove_session( *m_session );
124  gnutls_deinit( *m_session );
125  m_valid = false;
126 
127  m_handler->handleHandshakeResult( this, false, m_certInfo );
128  return false;
129  }
130  else if( ret == GNUTLS_E_AGAIN )
131  {
132  return true;
133  }
134 
135  m_secure = true;
136 
137  getCertInfo();
138 
139  m_handler->handleHandshakeResult( this, true, m_certInfo );
140  return true;
141  }
142 
143  ssize_t GnuTLSBase::pullFunc( void* data, size_t len )
144  {
145  ssize_t cpy = ( len > m_recvBuffer.length() ) ? ( m_recvBuffer.length() ) : ( len );
146  if( cpy > 0 )
147  {
148  memcpy( data, (const void*)m_recvBuffer.c_str(), cpy );
149  m_recvBuffer.erase( 0, cpy );
150  return cpy;
151  }
152  else
153  {
154  errno = EAGAIN;
155  return GNUTLS_E_AGAIN;
156  }
157  }
158 
159  ssize_t GnuTLSBase::pullFunc( gnutls_transport_ptr_t ptr, void* data, size_t len )
160  {
161  return static_cast<GnuTLSBase*>( ptr )->pullFunc( data, len );
162  }
163 
164  ssize_t GnuTLSBase::pushFunc( const void* data, size_t len )
165  {
166  if( m_handler )
167  m_handler->handleEncryptedData( this, std::string( (const char*)data, len ) );
168 
169  return len;
170  }
171 
172  ssize_t GnuTLSBase::pushFunc( gnutls_transport_ptr_t ptr, const void* data, size_t len )
173  {
174  return static_cast<GnuTLSBase*>( ptr )->pushFunc( data, len );
175  }
176 
177 }
178 
179 #endif // HAVE_GNUTLS