source: lib/ssl_openssl.c @ c564e25

Last change on this file since c564e25 was def3650, checked in by Wilmer van der Gaast <wilmer@…>, at 2012-12-24T13:28:02Z

In the OpenSSL module, keep only one global SSL context instead of recreating
one for every connection.

  • Property mode set to 100644
File size: 7.8 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
[def3650]4  * Copyright 2002-2012 Wilmer van der Gaast and others                *
[b7d3cc34]5  \********************************************************************/
6
[26fdfc5]7/* SSL module - OpenSSL version                                         */
[b7d3cc34]8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#include <openssl/crypto.h>
27#include <openssl/rand.h>
28#include <openssl/x509.h>
29#include <openssl/pem.h>
30#include <openssl/ssl.h>
31#include <openssl/err.h>
32
[59c03bd]33#include "bitlbee.h"
[b7d3cc34]34#include "proxy.h"
35#include "ssl_client.h"
36#include "sock.h"
37
[701acdd4]38int ssl_errno = 0;
39
[b7d3cc34]40static gboolean initialized = FALSE;
41
42struct scd
43{
[26fdfc5]44        ssl_input_function func;
[b7d3cc34]45        gpointer data;
46        int fd;
47        gboolean established;
[486ddb5]48        gboolean verify;
[3f661849]49        char *hostname;
[b7d3cc34]50       
[26fdfc5]51        int inpa;
52        int lasterr;            /* Necessary for SSL_get_error */
[b7d3cc34]53        SSL *ssl;
54};
55
[def3650]56static SSL_CTX *ssl_ctx;
57
[3f661849]58static void ssl_conn_free( struct scd *conn );
[309cb9e]59static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
[f920d9e]60static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
61static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
[b7d3cc34]62
63
[9730d72]64void ssl_init( void )
[ba5add7]65{
[def3650]66        const SSL_METHOD *meth;
67       
[8e9e2b7]68        SSL_library_init();
[def3650]69       
70        meth = TLSv1_client_method();
71        ssl_ctx = SSL_CTX_new( meth );
72       
73        initialized = TRUE;
[ba5add7]74}
75
[a72dc2b]76void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
[b7d3cc34]77{
78        struct scd *conn = g_new0( struct scd, 1 );
79       
80        conn->fd = proxy_connect( host, port, ssl_connected, conn );
81        if( conn->fd < 0 )
82        {
[3f661849]83                ssl_conn_free( conn );
[f920d9e]84                return NULL;
[b7d3cc34]85        }
86       
[8a2221a7]87        conn->func = func;
88        conn->data = data;
89        conn->inpa = -1;
[3f661849]90        conn->hostname = g_strdup( host );
[8a2221a7]91       
[f920d9e]92        return conn;
93}
94
[486ddb5]95void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
[f920d9e]96{
97        struct scd *conn = g_new0( struct scd, 1 );
98       
99        conn->fd = fd;
100        conn->func = func;
101        conn->data = data;
102        conn->inpa = -1;
[200e151]103        conn->verify = verify && global.conf->cafile;
[3f661849]104        conn->hostname = g_strdup( hostname );
[f920d9e]105       
106        /* This function should be called via a (short) timeout instead of
107           directly from here, because these SSL calls are *supposed* to be
108           *completely* asynchronous and not ready yet when this function
109           (or *_connect, for examle) returns. Also, errors are reported via
110           the callback function, not via this function's return value.
111           
112           In short, doing things like this makes the rest of the code a lot
113           simpler. */
114       
115        b_timeout_add( 1, ssl_starttls_real, conn );
116       
117        return conn;
118}
119
120static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
121{
122        struct scd *conn = data;
123       
[e046390]124        return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );
[f920d9e]125}
126
127static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
128{
129        struct scd *conn = data;
130       
[486ddb5]131        if( conn->verify )
132        {
[3f661849]133                /* Right now we don't have any verification functionality for OpenSSL. */
[200e151]134                conn->func( conn->data, 1, NULL, cond );
[486ddb5]135                if( source >= 0 ) closesocket( source );
[3f661849]136                ssl_conn_free( conn );
[486ddb5]137
138                return FALSE;
139        }
140
[f920d9e]141        if( source == -1 )
142                goto ssl_connected_failure;
143       
[b7d3cc34]144        if( !initialized )
145        {
[ba5add7]146                ssl_init();
[b7d3cc34]147        }
148       
[def3650]149       
150        if( ssl_ctx == NULL )
[f920d9e]151                goto ssl_connected_failure;
[b7d3cc34]152       
[def3650]153        conn->ssl = SSL_new( ssl_ctx );
[b7d3cc34]154        if( conn->ssl == NULL )
[f920d9e]155                goto ssl_connected_failure;
[b7d3cc34]156       
[309cb9e]157        /* We can do at least the handshake with non-blocking I/O */
[26fdfc5]158        sock_make_nonblocking( conn->fd );
[b7d3cc34]159        SSL_set_fd( conn->ssl, conn->fd );
160       
[3f661849]161        if( conn->hostname && !isdigit( conn->hostname[0] ) )
162                SSL_set_tlsext_host_name( conn->ssl, conn->hostname );
163       
[26fdfc5]164        return ssl_handshake( data, source, cond );
[f920d9e]165
166ssl_connected_failure:
[486ddb5]167        conn->func( conn->data, 0, NULL, cond );
[3f661849]168        ssl_disconnect( conn );
[f920d9e]169        return FALSE;
170
[26fdfc5]171}       
172
[309cb9e]173static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond )
[26fdfc5]174{
175        struct scd *conn = data;
176        int st;
177       
178        if( ( st = SSL_connect( conn->ssl ) ) < 0 )
179        {
180                conn->lasterr = SSL_get_error( conn->ssl, st );
181                if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
[f920d9e]182                {
[486ddb5]183                        conn->func( conn->data, 0, NULL, cond );
[3f661849]184                        ssl_disconnect( conn );
[f920d9e]185                        return FALSE;
186                }
[26fdfc5]187               
[309cb9e]188                conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
189                return FALSE;
[26fdfc5]190        }
[b7d3cc34]191       
192        conn->established = TRUE;
[26fdfc5]193        sock_make_blocking( conn->fd );         /* For now... */
[486ddb5]194        conn->func( conn->data, 0, conn, cond );
[309cb9e]195        return FALSE;
[b7d3cc34]196}
197
198int ssl_read( void *conn, char *buf, int len )
199{
[26fdfc5]200        int st;
201       
[b7d3cc34]202        if( !((struct scd*)conn)->established )
[26fdfc5]203        {
204                ssl_errno = SSL_NOHANDSHAKE;
205                return -1;
206        }
207       
208        st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
[b7d3cc34]209       
[26fdfc5]210        ssl_errno = SSL_OK;
211        if( st <= 0 )
212        {
213                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
214                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
215                        ssl_errno = SSL_AGAIN;
216        }
217       
[327af51]218        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
[50b8978]219       
[26fdfc5]220        return st;
[b7d3cc34]221}
222
223int ssl_write( void *conn, const char *buf, int len )
224{
[26fdfc5]225        int st;
226       
[b7d3cc34]227        if( !((struct scd*)conn)->established )
[26fdfc5]228        {
229                ssl_errno = SSL_NOHANDSHAKE;
230                return -1;
231        }
232       
233        st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
[b7d3cc34]234       
[327af51]235        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
[50b8978]236       
[26fdfc5]237        ssl_errno = SSL_OK;
238        if( st <= 0 )
239        {
240                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
241                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
242                        ssl_errno = SSL_AGAIN;
243        }
244       
245        return st;
[b7d3cc34]246}
247
[8a2221a7]248int ssl_pending( void *conn )
249{
250        return ( ((struct scd*)conn) && ((struct scd*)conn)->established ) ?
251               SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0;
252}
253
[3f661849]254static void ssl_conn_free( struct scd *conn )
255{
256        SSL_free( conn->ssl );
257        g_free( conn->hostname );
258        g_free( conn );
259       
260}
261
[b7d3cc34]262void ssl_disconnect( void *conn_ )
263{
264        struct scd *conn = conn_;
265       
[26fdfc5]266        if( conn->inpa != -1 )
[309cb9e]267                b_event_remove( conn->inpa );
[26fdfc5]268       
[b7d3cc34]269        if( conn->established )
270                SSL_shutdown( conn->ssl );
271       
272        closesocket( conn->fd );
273       
[3f661849]274        ssl_conn_free( conn );
[b7d3cc34]275}
276
277int ssl_getfd( void *conn )
278{
279        return( ((struct scd*)conn)->fd );
280}
[26fdfc5]281
[ba9edaa]282b_input_condition ssl_getdirection( void *conn )
[26fdfc5]283{
[e046390]284        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
[26fdfc5]285}
[523fb23]286
[78b8401]287char *ssl_verify_strerror( int code )
288{
289        return g_strdup( "SSL certificate verification not supported by BitlBee OpenSSL code." );
290}
291
[523fb23]292size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len, const unsigned char *input, size_t input_len, const unsigned char *iv, unsigned char **res)
293{
294        int output_length = 0;   
[50b8978]295        EVP_CIPHER_CTX ctx;
[523fb23]296       
297        *res = g_new0(unsigned char, 72);
298       
299        /* Don't set key or IV because we will modify the parameters */
300        EVP_CIPHER_CTX_init(&ctx);
301        EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1);
302        EVP_CIPHER_CTX_set_key_length(&ctx, key_len);
303        EVP_CIPHER_CTX_set_padding(&ctx, 0);
304        /* We finished modifying parameters so now we can set key and IV */
305        EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1);
306        EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len);
307        EVP_CipherFinal_ex(&ctx, *res, &output_length);
308        EVP_CIPHER_CTX_cleanup(&ctx);   
[50b8978]309        //EVP_cleanup();
[523fb23]310       
311        return output_length;
312}
Note: See TracBrowser for help on using the repository browser.