gloox 1.0.27
tlsgnutlsbase.cpp
1/*
2 Copyright (c) 2005-2023 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 bool stop = false;
77 do
78 {
79 if( ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
80 stop = true;
81 else
82 stop = false;
83
84 ret = static_cast<int>( gnutls_record_recv( *m_session, m_buf, m_bufsize ) );
85 if( ret > 0 && m_handler )
86 {
87 m_handler->handleDecryptedData( this, std::string( m_buf, ret ) );
88 sum += ret;
89 }
90 if( stop )
91 break;
92 }
93 while( ret > 0 || ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED );
94
95 return sum;
96 }
97
99 {
100 if( !m_mutex.trylock() )
101 return;
102
103 TLSHandler* handler = m_handler;
104 m_handler = 0;
105 gnutls_bye( *m_session, GNUTLS_SHUT_RDWR );
106 gnutls_db_remove_session( *m_session );
107 gnutls_credentials_clear( *m_session );
108 if( m_session )
109 gnutls_deinit( *m_session );
110
111 delete m_session;
112
113 m_secure = false;
114 m_valid = false;
115 m_session = 0;
116 m_session = new gnutls_session_t;
117 m_handler = handler;
118
119 m_mutex.unlock();
120 }
121
123 {
124 if( !m_handler )
125 return false;
126
127 int ret = gnutls_handshake( *m_session );
128 if( ret < 0 && gnutls_error_is_fatal( ret ) )
129 {
130 gnutls_perror( ret );
131 gnutls_db_remove_session( *m_session );
132 m_valid = false;
133
134 m_handler->handleHandshakeResult( this, false, m_certInfo );
135 return false;
136 }
137 else if( ret == GNUTLS_E_AGAIN )
138 {
139 return true;
140 }
141
142 m_secure = true;
143
144 getCertInfo();
145
146 m_handler->handleHandshakeResult( this, true, m_certInfo );
147 return true;
148 }
149
151 {
152#ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
153 return true;
154#else
155 return false;
156#endif
157 }
158
159 const std::string GnuTLSBase::channelBinding() const
160 {
161#ifdef HAVE_GNUTLS_SESSION_CHANNEL_BINDING
162 gnutls_datum_t cb;
163 int rc;
164 rc = gnutls_session_channel_binding( *m_session,
165#ifdef GNUTLS_CB_TLS_EXPORTER
166 ( m_certInfo.protocol == "TLSv1.3" ) ? GNUTLS_CB_TLS_EXPORTER : GNUTLS_CB_TLS_UNIQUE,
167#else
168 GNUTLS_CB_TLS_UNIQUE,
169#endif
170 &cb );
171 if( !rc )
172 return std::string( reinterpret_cast<char*>( cb.data ), cb.size );
173 else
174#endif
175 return EmptyString;
176 }
177
178 ssize_t GnuTLSBase::pullFunc( void* data, size_t len )
179 {
180 ssize_t cpy = ( len > m_recvBuffer.length() ) ? ( m_recvBuffer.length() ) : ( len );
181 if( cpy > 0 )
182 {
183 memcpy( data, static_cast<const void*>( m_recvBuffer.c_str() ), cpy );
184 m_recvBuffer.erase( 0, cpy );
185 return cpy;
186 }
187 else
188 {
189 errno = EAGAIN;
190 return GNUTLS_E_AGAIN;
191 }
192 }
193
194 ssize_t GnuTLSBase::pullFunc( gnutls_transport_ptr_t ptr, void* data, size_t len )
195 {
196 return static_cast<GnuTLSBase*>( ptr )->pullFunc( data, len );
197 }
198
199 ssize_t GnuTLSBase::pushFunc( const void* data, size_t len )
200 {
201 if( m_handler )
202 m_handler->handleEncryptedData( this, std::string( static_cast<const char*>( data ), len ) );
203
204 return len;
205 }
206
207 ssize_t GnuTLSBase::pushFunc( gnutls_transport_ptr_t ptr, const void* data, size_t len )
208 {
209 return static_cast<GnuTLSBase*>( ptr )->pushFunc( data, len );
210 }
211
212 void GnuTLSBase::getCommonCertInfo()
213 {
214 const char* info;
215 info = gnutls_compression_get_name( gnutls_compression_get( *m_session ) );
216 if( info )
217 m_certInfo.compression = info;
218
219 info = gnutls_mac_get_name( gnutls_mac_get( *m_session ) );
220 if( info )
221 m_certInfo.mac = info;
222
223 info = gnutls_cipher_get_name( gnutls_cipher_get( *m_session ) );
224 if( info )
225 m_certInfo.cipher = info;
226
227 switch( gnutls_protocol_get_version( *m_session ) )
228 {
229 // case GNUTLS_SSL3:
230 // m_certInfo.protocol = SSL3;
231 // break;
232 case GNUTLS_TLS1_0:
233 m_certInfo.protocol = "TLSv1";
234 break;
235 case GNUTLS_TLS1_1:
236 m_certInfo.protocol = "TLSv1.1";
237 break;
238 case GNUTLS_TLS1_2:
239 m_certInfo.protocol = "TLSv1.2";
240 break;
241 case GNUTLS_TLS1_3:
242 m_certInfo.protocol = "TLSv1.3";
243 break;
244 case GNUTLS_DTLS1_0:
245 m_certInfo.protocol = "DTLSv1";
246 break;
247 case GNUTLS_DTLS1_2:
248 m_certInfo.protocol = "DTLSv1.2";
249 break;
250 default:
251 m_certInfo.protocol = "Unknown protocol";
252 break;
253 }
254 }
255
256}
257
258#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
std::string cipher
Definition gloox.h:1002
std::string mac
Definition gloox.h:1003
std::string protocol
Definition gloox.h:1001
std::string compression
Definition gloox.h:1004