gloox 1.0.24
tlsgnutlsbase.cpp
1/*
2 Copyright (c) 2005-2019 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
24namespace 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 = static_cast<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( reinterpret_cast<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, static_cast<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( static_cast<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 bool encrypt(const std::string &data)
virtual bool handshake()
virtual void cleanup()
virtual const std::string channelBinding() const
virtual bool hasChannelBinding() const
GnuTLSBase(TLSHandler *th, const std::string &server=EmptyString)
virtual int decrypt(const std::string &data)
An abstract base class for TLS implementations.
Definition: tlsbase.h:32
An interface that allows for interacting with TLS implementations derived from TLSBase.
Definition: tlshandler.h:35
virtual void handleDecryptedData(const TLSBase *base, const std::string &data)=0
virtual void handleEncryptedData(const TLSBase *base, const std::string &data)=0
virtual void handleHandshakeResult(const TLSBase *base, bool success, CertInfo &certinfo)=0
The namespace for the gloox library.
Definition: adhoc.cpp:28
const std::string EmptyString
Definition: gloox.cpp:124