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