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