gloox  1.0
tlsgnutlsbase.cpp
1 /*
2  Copyright (c) 2005-2009 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 #include <cstdlib>
24 #include <cstring>
25 
26 namespace gloox
27 {
28 
29  GnuTLSBase::GnuTLSBase( TLSHandler* th, const std::string& server )
30  : TLSBase( th, server ), m_session( new gnutls_session_t ), m_buf( 0 ), m_bufsize( 17000 )
31  {
32  m_buf = (char*)calloc( m_bufsize + 1, sizeof( char ) );
33  }
34 
36  {
37  free( m_buf );
38  m_buf = 0;
39  cleanup();
40  delete m_session;
41 // FIXME: It segfaults if more then one account uses
42 // encryption at same time, so we comment it for now.
43 // Do we need to deinit at all?
44 // gnutls_global_deinit();
45  }
46 
47  bool GnuTLSBase::encrypt( const std::string& data )
48  {
49  if( !m_secure )
50  {
51  handshake();
52  return true;
53  }
54 
55  ssize_t ret = 0;
56  std::string::size_type sum = 0;
57  do
58  {
59  ret = gnutls_record_send( *m_session, data.c_str() + sum, data.length() - sum );
60  sum += ret;
61  }
62  while( ( ret == GNUTLS_E_AGAIN ) || ( ret == GNUTLS_E_INTERRUPTED ) || sum < data.length() );
63  return true;
64  }
65 
66  int GnuTLSBase::decrypt( const std::string& data )
67  {
68  m_recvBuffer += data;
69 
70  if( !m_secure )
71  {
72  handshake();
73  return static_cast<int>( data.length() );
74  }
75 
76  int sum = 0;
77  int ret = 0;
78  do
79  {
80  ret = static_cast<int>( gnutls_record_recv( *m_session, m_buf, m_bufsize ) );
81 
82  if( ret > 0 && m_handler )
83  {
84  m_handler->handleDecryptedData( this, std::string( m_buf, ret ) );
85  sum += ret;
86  }
87  }
88  while( ret > 0 );
89 
90  return sum;
91  }
92 
94  {
95  if( !m_mutex.trylock() )
96  return;
97 
98  TLSHandler* handler = m_handler;
99  m_handler = 0;
100  gnutls_bye( *m_session, GNUTLS_SHUT_RDWR );
101  gnutls_db_remove_session( *m_session );
102  gnutls_credentials_clear( *m_session );
103  if( m_secure )
104  gnutls_deinit( *m_session );
105 
106  m_secure = false;
107  m_valid = false;
108  delete m_session;
109  m_session = 0;
110  m_session = new gnutls_session_t;
111  m_handler = handler;
112 
113  m_mutex.unlock();
114  }
115 
117  {
118  if( !m_handler )
119  return false;
120 
121  int ret = gnutls_handshake( *m_session );
122  if( ret < 0 && gnutls_error_is_fatal( ret ) )
123  {
124  gnutls_perror( ret );
125  gnutls_db_remove_session( *m_session );
126  gnutls_deinit( *m_session );
127  m_valid = false;
128 
129  m_handler->handleHandshakeResult( this, false, m_certInfo );
130  return false;
131  }
132  else if( ret == GNUTLS_E_AGAIN )
133  {
134  return true;
135  }
136 
137  m_secure = true;
138 
139  getCertInfo();
140 
141  m_handler->handleHandshakeResult( this, true, m_certInfo );
142  return true;
143  }
144 
145  ssize_t GnuTLSBase::pullFunc( void* data, size_t len )
146  {
147  ssize_t cpy = ( len > m_recvBuffer.length() ) ? ( m_recvBuffer.length() ) : ( len );
148  if( cpy > 0 )
149  {
150  memcpy( data, (const void*)m_recvBuffer.c_str(), cpy );
151  m_recvBuffer.erase( 0, cpy );
152  return cpy;
153  }
154  else
155  {
156  errno = EAGAIN;
157  return GNUTLS_E_AGAIN;
158  }
159  }
160 
161  ssize_t GnuTLSBase::pullFunc( gnutls_transport_ptr_t ptr, void* data, size_t len )
162  {
163  return static_cast<GnuTLSBase*>( ptr )->pullFunc( data, len );
164  }
165 
166  ssize_t GnuTLSBase::pushFunc( const void* data, size_t len )
167  {
168  if( m_handler )
169  m_handler->handleEncryptedData( this, std::string( (const char*)data, len ) );
170 
171  return len;
172  }
173 
174  ssize_t GnuTLSBase::pushFunc( gnutls_transport_ptr_t ptr, const void* data, size_t len )
175  {
176  return static_cast<GnuTLSBase*>( ptr )->pushFunc( data, len );
177  }
178 
179 }
180 
181 #endif // HAVE_GNUTLS
GnuTLSBase(TLSHandler *th, const std::string &server=EmptyString)
virtual void handleEncryptedData(const TLSBase *base, const std::string &data)=0
virtual int decrypt(const std::string &data)
virtual void cleanup()
virtual bool handshake()
An abstract base class for TLS implementations.
Definition: tlsbase.h:31
virtual void handleDecryptedData(const TLSBase *base, const std::string &data)=0
virtual bool encrypt(const std::string &data)
An interface that allows for interacting with TLS implementations derived from TLSBase.
Definition: tlshandler.h:34
virtual void handleHandshakeResult(const TLSBase *base, bool success, CertInfo &certinfo)=0