source: lib/ssl_openssl.c @ 164352e

Last change on this file since 164352e was 200e151, checked in by Wilmer van der Gaast <wilmer@…>, at 2011-12-23T22:40:17Z

tls_verify correction: Don't fail cert verification in non-GnuTLS modules
unless "cafile" setting is enabled.

  • Property mode set to 100644
File size: 7.8 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* SSL module - OpenSSL version                                         */
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
33#include "proxy.h"
34#include "ssl_client.h"
35#include "sock.h"
36
37int ssl_errno = 0;
38
39static gboolean initialized = FALSE;
40
41struct scd
42{
43        ssl_input_function func;
44        gpointer data;
45        int fd;
46        gboolean established;
47        gboolean verify;
48       
49        int inpa;
50        int lasterr;            /* Necessary for SSL_get_error */
51        SSL *ssl;
52        SSL_CTX *ssl_ctx;
53};
54
55static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
56static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
57static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
58
59
60void ssl_init( void )
61{
62        initialized = TRUE;
63        SSL_library_init();
64        // SSLeay_add_ssl_algorithms();
65}
66
67void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
68{
69        struct scd *conn = g_new0( struct scd, 1 );
70       
71        conn->fd = proxy_connect( host, port, ssl_connected, conn );
72        if( conn->fd < 0 )
73        {
74                g_free( conn );
75                return NULL;
76        }
77       
78        conn->func = func;
79        conn->data = data;
80        conn->inpa = -1;
81       
82        return conn;
83}
84
85void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
86{
87        struct scd *conn = g_new0( struct scd, 1 );
88       
89        conn->fd = fd;
90        conn->func = func;
91        conn->data = data;
92        conn->inpa = -1;
93        conn->verify = verify && global.conf->cafile;
94       
95        /* This function should be called via a (short) timeout instead of
96           directly from here, because these SSL calls are *supposed* to be
97           *completely* asynchronous and not ready yet when this function
98           (or *_connect, for examle) returns. Also, errors are reported via
99           the callback function, not via this function's return value.
100           
101           In short, doing things like this makes the rest of the code a lot
102           simpler. */
103       
104        b_timeout_add( 1, ssl_starttls_real, conn );
105       
106        return conn;
107}
108
109static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
110{
111        struct scd *conn = data;
112       
113        return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );
114}
115
116static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
117{
118        struct scd *conn = data;
119        SSL_METHOD *meth;
120       
121        /* Right now we don't have any verification functionality for OpenSSL. */
122
123        if( conn->verify )
124        {
125                conn->func( conn->data, 1, NULL, cond );
126                if( source >= 0 ) closesocket( source );
127                g_free( conn );
128
129                return FALSE;
130        }
131
132        if( source == -1 )
133                goto ssl_connected_failure;
134       
135        if( !initialized )
136        {
137                ssl_init();
138        }
139       
140        meth = TLSv1_client_method();
141        conn->ssl_ctx = SSL_CTX_new( meth );
142        if( conn->ssl_ctx == NULL )
143                goto ssl_connected_failure;
144       
145        conn->ssl = SSL_new( conn->ssl_ctx );
146        if( conn->ssl == NULL )
147                goto ssl_connected_failure;
148       
149        /* We can do at least the handshake with non-blocking I/O */
150        sock_make_nonblocking( conn->fd );
151        SSL_set_fd( conn->ssl, conn->fd );
152       
153        return ssl_handshake( data, source, cond );
154
155ssl_connected_failure:
156        conn->func( conn->data, 0, NULL, cond );
157       
158        if( conn->ssl )
159        {
160                SSL_shutdown( conn->ssl );
161                SSL_free( conn->ssl );
162        }
163        if( conn->ssl_ctx )
164        {
165                SSL_CTX_free( conn->ssl_ctx );
166        }
167        if( source >= 0 ) closesocket( source );
168        g_free( conn );
169       
170        return FALSE;
171
172}       
173
174static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond )
175{
176        struct scd *conn = data;
177        int st;
178       
179        if( ( st = SSL_connect( conn->ssl ) ) < 0 )
180        {
181                conn->lasterr = SSL_get_error( conn->ssl, st );
182                if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
183                {
184                        conn->func( conn->data, 0, NULL, cond );
185                       
186                        SSL_shutdown( conn->ssl );
187                        SSL_free( conn->ssl );
188                        SSL_CTX_free( conn->ssl_ctx );
189                       
190                        if( source >= 0 ) closesocket( source );
191                        g_free( conn );
192                       
193                        return FALSE;
194                }
195               
196                conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
197                return FALSE;
198        }
199       
200        conn->established = TRUE;
201        sock_make_blocking( conn->fd );         /* For now... */
202        conn->func( conn->data, 0, conn, cond );
203        return FALSE;
204}
205
206int ssl_read( void *conn, char *buf, int len )
207{
208        int st;
209       
210        if( !((struct scd*)conn)->established )
211        {
212                ssl_errno = SSL_NOHANDSHAKE;
213                return -1;
214        }
215       
216        st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
217       
218        ssl_errno = SSL_OK;
219        if( st <= 0 )
220        {
221                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
222                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
223                        ssl_errno = SSL_AGAIN;
224        }
225       
226        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
227       
228        return st;
229}
230
231int ssl_write( void *conn, const char *buf, int len )
232{
233        int st;
234       
235        if( !((struct scd*)conn)->established )
236        {
237                ssl_errno = SSL_NOHANDSHAKE;
238                return -1;
239        }
240       
241        st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
242       
243        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
244       
245        ssl_errno = SSL_OK;
246        if( st <= 0 )
247        {
248                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
249                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
250                        ssl_errno = SSL_AGAIN;
251        }
252       
253        return st;
254}
255
256int ssl_pending( void *conn )
257{
258        return ( ((struct scd*)conn) && ((struct scd*)conn)->established ) ?
259               SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0;
260}
261
262void ssl_disconnect( void *conn_ )
263{
264        struct scd *conn = conn_;
265       
266        if( conn->inpa != -1 )
267                b_event_remove( conn->inpa );
268       
269        if( conn->established )
270                SSL_shutdown( conn->ssl );
271       
272        closesocket( conn->fd );
273       
274        SSL_free( conn->ssl );
275        SSL_CTX_free( conn->ssl_ctx );
276        g_free( conn );
277}
278
279int ssl_getfd( void *conn )
280{
281        return( ((struct scd*)conn)->fd );
282}
283
284b_input_condition ssl_getdirection( void *conn )
285{
286        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
287}
288
289char *ssl_verify_strerror( int code )
290{
291        return g_strdup( "SSL certificate verification not supported by BitlBee OpenSSL code." );
292}
293
294size_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)
295{
296        int output_length = 0;   
297        EVP_CIPHER_CTX ctx;
298       
299        *res = g_new0(unsigned char, 72);
300       
301        /* Don't set key or IV because we will modify the parameters */
302        EVP_CIPHER_CTX_init(&ctx);
303        EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1);
304        EVP_CIPHER_CTX_set_key_length(&ctx, key_len);
305        EVP_CIPHER_CTX_set_padding(&ctx, 0);
306        /* We finished modifying parameters so now we can set key and IV */
307        EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1);
308        EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len);
309        EVP_CipherFinal_ex(&ctx, *res, &output_length);
310        EVP_CIPHER_CTX_cleanup(&ctx);   
311        //EVP_cleanup();
312       
313        return output_length;
314}
Note: See TracBrowser for help on using the repository browser.