1 // Copyright 2009 The Archiveopteryx Developers <info@aox.org>
2
3 #include "tlsthread.h"
4
5 #include "file.h"
6 #include "estring.h"
7 #include "allocator.h"
8 #include "configuration.h"
9
10 #include <unistd.h>
11
12 #include <pthread.h>
13
14 #include <openssl/ssl.h>
15 #include <openssl/err.h>
16
17
18 static const int bs = 32768;
19
20
21 class TlsThreadData
22 : public Garbage
23 {
24 public:
TlsThreadData()25 TlsThreadData()
26 : Garbage(),
27 ssl( 0 ),
28 ctrb( 0 ),
29 ctrbo( 0 ), ctrbs( 0 ),
30 ctwb( 0 ),
31 ctwbo( 0 ), ctwbs( 0 ),
32 ctfd( -1 ),
33 encrb( 0 ),
34 encrbo( 0 ), encrbs( 0 ),
35 encwb( 0 ),
36 encwbo( 0 ), encwbs( 0 ),
37 encfd( -1 ),
38 networkBio( 0 ), sslBio( 0 ), thread( 0 ),
39 broken( false )
40 {}
41
42 SSL * ssl;
43
44 // clear-text read buffer, ie. data coming from aox
45 char * ctrb;
46 // the offset at which cleartext data starts
47 int ctrbo;
48 // and the buffer size (if ...o=...s, the buffer contains no data)
49 int ctrbs;
50 // clear-text write buffer, ie. data going to aox
51 char * ctwb;
52 int ctwbo;
53 int ctwbs;
54 // the cleartext fd, ie. the fd for talking to aox
55 int ctfd;
56 // encrypted read buffer, ie. data coming from the peer
57 char * encrb;
58 int encrbo;
59 int encrbs;
60 // encrypted write buffer, ie. data going to the peer
61 char * encwb;
62 int encwbo;
63 int encwbs;
64 int encfd;
65
66 // where we read/write encrypted data
67 BIO * networkBio;
68 // where openssl reads/writes ditto
69 BIO * sslBio;
70
71 pthread_t thread;
72 bool broken;
73 };
74
75
trampoline(void * t)76 static void * trampoline( void * t )
77 {
78 ((TlsThread*)t)->start();
79 return 0;
80 }
81
82
83 static SSL_CTX * ctx = 0;
84
85
86 /*! Perform any OpenSSL initialisation needed to enable us to create
87 TlsThreads later.
88 */
89
setup()90 void TlsThread::setup()
91 {
92 SSL_load_error_strings();
93 SSL_library_init();
94
95 ctx = ::SSL_CTX_new( SSLv23_server_method() );
96 long options = SSL_OP_ALL
97 // also try to pick the same ciphers suites more often
98 | SSL_OP_CIPHER_SERVER_PREFERENCE
99 // and don't use SSLv2, even if the client wants to
100 | SSL_OP_NO_SSLv2
101 // and not v3 either
102 | SSL_OP_NO_SSLv3
103 ;
104 SSL_CTX_set_options( ctx, options );
105
106 SSL_CTX_set_cipher_list( ctx, "kEDH:HIGH:!aNULL:!MD5" );
107
108 EString keyFile( Configuration::text( Configuration::TlsCertFile ) );
109 if ( keyFile.isEmpty() ) {
110 keyFile = Configuration::compiledIn( Configuration::LibDir );
111 keyFile.append( "/automatic-key.pem" );
112 }
113 keyFile = File::chrooted( keyFile );
114 if ( !SSL_CTX_use_certificate_chain_file( ctx, keyFile.cstr() ) ||
115 !SSL_CTX_use_RSAPrivateKey_file( ctx, keyFile.cstr(),
116 SSL_FILETYPE_PEM ) )
117 log( "OpenSSL needs both the certificate and "
118 "private key in this file: " + keyFile,
119 Log::Disaster );
120 // we go on anyway; the disaster will take down the server in
121 // a hurry.
122
123 // we don't ask for a client cert
124 SSL_CTX_set_verify( ctx, SSL_VERIFY_NONE, NULL );
125 }
126
127
128 /*! \class TlsThread tlsthread.h
129 Creates and manages a thread for TLS processing using openssl
130 */
131
132
133
134 /*! Constructs a TlsThread. If \a asClient is supplied and true (the
135 default is false), the thread acts as client (and initiates a TLS
136 handshake). If not, it acts as a server (and expects the other end
137 to initiate the handshake).
138 */
139
TlsThread(bool asClient)140 TlsThread::TlsThread( bool asClient )
141 : d( new TlsThreadData )
142 {
143 if ( !ctx )
144 setup();
145
146 d->ssl = ::SSL_new( ctx );
147 if ( asClient )
148 SSL_set_connect_state( d->ssl );
149 else
150 SSL_set_accept_state( d->ssl );
151
152 if ( !BIO_new_bio_pair( &d->sslBio, bs, &d->networkBio, bs ) ) {
153 // an error. hm?
154 }
155 ::SSL_set_bio( d->ssl, d->sslBio, d->sslBio );
156
157 d->ctrb = (char*)Allocator::alloc( bs, 0 );
158 d->ctwb = (char*)Allocator::alloc( bs, 0 );
159 d->encrb = (char*)Allocator::alloc( bs, 0 );
160 d->encwb = (char*)Allocator::alloc( bs, 0 );
161
162 int r = pthread_create( &d->thread, 0, trampoline, (void*)this );
163 if ( r ) {
164 log( "pthread_create returned nonzero (" + fn( r ) + ")" );
165 d->broken = true;
166 ::SSL_free( d->ssl );
167 d->ssl = 0;
168 }
169 }
170
171
172 /*! Destroys the object and frees any allocated resources. Except we
173 probably should do this in Connection::react() or
174 Connection::close() or something.
175 */
176
~TlsThread()177 TlsThread::~TlsThread()
178 {
179 ::SSL_free( d->ssl );
180 d->ssl = 0;
181 }
182
183
184 /*! Starts negotiating and does everything after that. This is run in
185 the separate thread.
186
187 */
188
start()189 void TlsThread::start()
190 {
191 bool crct = false;
192 bool crenc = false;
193 bool cwct = false;
194 bool cwenc = false;
195 bool ctgone = false;
196 bool encgone = false;
197 bool finish = false;
198 while ( !finish && !d->broken ) {
199 // are our read buffers empty, and select said we can read? if
200 // so, try to read
201 if ( crct ) {
202 d->ctrbs = ::read( d->ctfd, d->ctrb, bs );
203 if ( d->ctrbs <= 0 ) {
204 ctgone = true;
205 d->ctrbs = 0;
206 }
207 }
208 if ( crenc ) {
209 d->encrbs = ::read( d->encfd, d->encrb, bs );
210 if ( d->encrbs <= 0 ) {
211 encgone = true;
212 d->encrbs = 0;
213 }
214 }
215 if ( ctgone && encgone ) {
216 // if both file descriptors are gone, there's nothing left
217 // to do. but maybe we try anyway.
218 finish = true;
219 }
220 if ( ctgone && d->encwbs == 0 ) {
221 // if the cleartext one is gone and we have nothing to
222 // write to enc, finish
223 finish = true;
224 }
225 if ( encgone && d->ctwbs == 0 ) {
226 // if the encfd is gone and we have nothing to write to ct,
227 // finish
228 finish = true;
229 }
230
231 // is there something in our write buffers, and select() told
232 // us we can write it?
233 if ( cwct ) {
234 int r = ::write( d->ctfd,
235 d->ctwb + d->ctwbo,
236 d->ctwbs - d->ctwbo );
237 if ( r <= 0 ) {
238 // select said we could, but we couldn't. parachute time.
239 finish = true;
240 }
241 else {
242 d->ctwbo += r;
243 if ( d->ctwbo == d->ctwbs ) {
244 d->ctwbs = 0;
245 d->ctwbo = 0;
246 }
247 }
248 }
249 if ( cwenc ) {
250 int r = ::write( d->encfd,
251 d->encwb + d->encwbo,
252 d->encwbs - d->encwbo );
253 if ( r <= 0 ) {
254 finish = true;
255 }
256 else {
257 d->encwbo += r;
258 if ( d->encwbo == d->encwbs ) {
259 d->encwbs = 0;
260 d->encwbo = 0;
261 }
262 }
263 }
264
265 // we've served file descriptors. now for glorious openssl.
266 if ( d->encrbs > 0 && d->encrbo < d->encrbs ) {
267 int r = BIO_write( d->networkBio,
268 d->encrb + d->encrbo,
269 d->encrbs - d->encrbo );
270 if ( r > 0 )
271 d->encrbo += r;
272 if ( d->encrbo >= d->encrbs ) {
273 d->encrbo = 0;
274 d->encrbs = 0;
275 }
276 }
277 if ( d->ctrbs > 0 && d->ctrbo < d->ctrbs ) {
278 int r = SSL_write( d->ssl,
279 d->ctrb + d->ctrbo,
280 d->ctrbs - d->ctrbo );
281 if ( r > 0 )
282 d->ctrbo += r;
283 else if ( r < 0 && !finish )
284 finish = sslErrorSeriousness( r );
285 if ( d->ctrbo >= d->ctrbs ) {
286 d->ctrbo = 0;
287 d->ctrbs = 0;
288 }
289 }
290 if ( d->ctwbs == 0 ) {
291 d->ctwbs = SSL_read( d->ssl, d->ctwb, bs );
292 if ( d->ctwbs < 0 ) {
293 if ( !finish )
294 finish = sslErrorSeriousness( d->ctwbs );
295 d->ctwbs = 0;
296 }
297 }
298 if ( d->encwbs == 0 ) {
299 d->encwbs = BIO_read( d->networkBio, d->encwb, bs );
300 if ( d->encwbs < 0 )
301 d->encwbs = 0;
302 }
303
304 if ( !finish && !d->broken ) {
305 bool any = false;
306 fd_set r, w;
307 FD_ZERO( &r );
308 FD_ZERO( &w );
309 if ( d->ctfd >= 0 ) {
310 if ( d->ctrbs == 0 ) {
311 FD_SET( d->ctfd, &r );
312 any = true;
313 }
314 if ( d->ctwbs ) {
315 any = true;
316 FD_SET( d->ctfd, &w );
317 }
318 }
319 if ( d->encfd >= 0 ) {
320 if ( d->encrbs == 0 ) {
321 any = true;
322 FD_SET( d->encfd, &r );
323 }
324 if ( d->encwbs ) {
325 any = true;
326 FD_SET( d->encfd, &w );
327 }
328 }
329 int maxfd = -1;
330 if ( maxfd < d->ctfd )
331 maxfd = d->ctfd;
332 if ( maxfd < d->encfd )
333 maxfd = d->encfd;
334 struct timeval tv;
335 if ( maxfd < 0 ) {
336 // if we don't have any fds yet, we wait for exactly 0.05s.
337 tv.tv_sec = 0;
338 tv.tv_usec = 50000; // 0.05s
339 }
340 else if ( any ) {
341 // if we think there's something to do, we wait for a
342 // few seconds. not very long, just in case openssl is
343 // acting behind our back.
344 tv.tv_sec = 4;
345 tv.tv_usec = 0;
346 }
347 else {
348 // we aren't going to read, we can't write. no point
349 // in prolonging the agony.
350 finish = true;
351 tv.tv_sec = 0;
352 tv.tv_usec = 0;
353 }
354
355 int n = finish ? 0 : select( maxfd+1, &r, &w, 0, &tv );
356 if ( n < 0 && errno != EINTR )
357 finish = true;
358
359 if ( n >= 0 ) {
360 crct = FD_ISSET( d->ctfd, &r );
361 cwct = FD_ISSET( d->ctfd, &w );
362 crenc = FD_ISSET( d->encfd, &r );
363 cwenc = FD_ISSET( d->encfd, &w );
364 } else {
365 crct = cwct = crenc = cwenc = false;
366 }
367
368 }
369 }
370
371 ::close( d->encfd );
372 ::close( d->ctfd );
373 SSL_free( d->ssl );
374 d->ssl = 0;
375 pthread_exit( 0 );
376 }
377
378
379 /*! Returns true if the openssl result status \a r is a serious error,
380 and false otherwise.
381 */
382
sslErrorSeriousness(int r)383 bool TlsThread::sslErrorSeriousness( int r ) {
384 int e = SSL_get_error( d->ssl, r );
385 switch( e ) {
386 case SSL_ERROR_NONE:
387 case SSL_ERROR_WANT_READ:
388 case SSL_ERROR_WANT_WRITE:
389 case SSL_ERROR_WANT_ACCEPT:
390 case SSL_ERROR_WANT_CONNECT:
391 case SSL_ERROR_WANT_X509_LOOKUP:
392 return false;
393 break;
394
395 case SSL_ERROR_ZERO_RETURN:
396 // not an error, client closed cleanly
397 return true;
398 break;
399
400 case SSL_ERROR_SSL:
401 case SSL_ERROR_SYSCALL:
402 //ERR_print_errors_fp( stdout );
403 return true;
404 break;
405 }
406 return true;
407 }
408
409
410 /*! Records that \a fd should be used for cleartext communication with
411 the main aox thread. The TLS thread will close \a fd when it's done.
412 */
413
setServerFD(int fd)414 void TlsThread::setServerFD( int fd )
415 {
416 d->ctfd = fd;
417 }
418
419
420 /*! Records that \a fd should be used for encrypted communication with
421 the client. The TLS thread will close \a fd when it's done.
422 */
423
setClientFD(int fd)424 void TlsThread::setClientFD( int fd )
425 {
426 d->encfd = fd;
427 }
428
429
430 /*! Returns true if this TlsThread is broken somehow, and false if
431 it's in working order.
432 */
433
broken() const434 bool TlsThread::broken() const
435 {
436 return d->broken;
437 }
438
439
440 /*! Causes this TlsThread object to stop doing anything, in a great
441 hurry and without any attempt at talking to the client.
442 */
443
close()444 void TlsThread::close()
445 {
446 d->broken = true;
447 ::close( d->encfd );
448 ::close( d->ctfd );
449 pthread_cancel( d->thread );
450 pthread_join( d->thread, 0 );
451 }
452