source: lib/ssl_openssl.c @ 25b05b7

Last change on this file since 25b05b7 was 78b8401, checked in by Wilmer van der Gaast <wilmer@…>, at 2011-12-19T17:22:37Z

Move conversion of status codes to status messages into SSL libs.

  • Property mode set to 100644
File size: 7.9 KB
RevLine 
[b7d3cc34]1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
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
33#include "proxy.h"
34#include "ssl_client.h"
35#include "sock.h"
36
[701acdd4]37int ssl_errno = 0;
38
[b7d3cc34]39static gboolean initialized = FALSE;
40
41struct scd
42{
[26fdfc5]43        ssl_input_function func;
[b7d3cc34]44        gpointer data;
45        int fd;
46        gboolean established;
[486ddb5]47        gboolean verify;
[b7d3cc34]48       
[26fdfc5]49        int inpa;
50        int lasterr;            /* Necessary for SSL_get_error */
[b7d3cc34]51        SSL *ssl;
52        SSL_CTX *ssl_ctx;
53};
54
[309cb9e]55static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
[f920d9e]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 );
[b7d3cc34]58
59
[9730d72]60void ssl_init( void )
[ba5add7]61{
62        initialized = TRUE;
[8e9e2b7]63        SSL_library_init();
64        // SSLeay_add_ssl_algorithms();
[ba5add7]65}
66
[26fdfc5]67void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
[b7d3cc34]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 );
[f920d9e]75                return NULL;
[b7d3cc34]76        }
77       
[8a2221a7]78        conn->func = func;
79        conn->data = data;
80        conn->inpa = -1;
81       
[f920d9e]82        return conn;
83}
84
[486ddb5]85void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
[f920d9e]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;
[486ddb5]93        conn->verify = verify;
[f920d9e]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       
[e046390]113        return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );
[f920d9e]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       
[486ddb5]121        /* Right now we don't have any verification functionality for openssl so we
122           fail in case verification has been requested by the user. */
123
124        if( conn->verify )
125        {
126                conn->func( conn->data, OPENSSL_VERIFY_ERROR, NULL, cond );
127                if( source >= 0 ) closesocket( source );
128                g_free( conn );
129
130                return FALSE;
131        }
132
[f920d9e]133        if( source == -1 )
134                goto ssl_connected_failure;
135       
[b7d3cc34]136        if( !initialized )
137        {
[ba5add7]138                ssl_init();
[b7d3cc34]139        }
140       
141        meth = TLSv1_client_method();
142        conn->ssl_ctx = SSL_CTX_new( meth );
143        if( conn->ssl_ctx == NULL )
[f920d9e]144                goto ssl_connected_failure;
[b7d3cc34]145       
146        conn->ssl = SSL_new( conn->ssl_ctx );
147        if( conn->ssl == NULL )
[f920d9e]148                goto ssl_connected_failure;
[b7d3cc34]149       
[309cb9e]150        /* We can do at least the handshake with non-blocking I/O */
[26fdfc5]151        sock_make_nonblocking( conn->fd );
[b7d3cc34]152        SSL_set_fd( conn->ssl, conn->fd );
153       
[26fdfc5]154        return ssl_handshake( data, source, cond );
[f920d9e]155
156ssl_connected_failure:
[486ddb5]157        conn->func( conn->data, 0, NULL, cond );
[f920d9e]158       
159        if( conn->ssl )
160        {
161                SSL_shutdown( conn->ssl );
162                SSL_free( conn->ssl );
163        }
164        if( conn->ssl_ctx )
165        {
166                SSL_CTX_free( conn->ssl_ctx );
167        }
168        if( source >= 0 ) closesocket( source );
169        g_free( conn );
170       
171        return FALSE;
172
[26fdfc5]173}       
174
[309cb9e]175static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond )
[26fdfc5]176{
177        struct scd *conn = data;
178        int st;
179       
180        if( ( st = SSL_connect( conn->ssl ) ) < 0 )
181        {
182                conn->lasterr = SSL_get_error( conn->ssl, st );
183                if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
[f920d9e]184                {
[486ddb5]185                        conn->func( conn->data, 0, NULL, cond );
[f920d9e]186                       
187                        SSL_shutdown( conn->ssl );
188                        SSL_free( conn->ssl );
189                        SSL_CTX_free( conn->ssl_ctx );
190                       
191                        if( source >= 0 ) closesocket( source );
192                        g_free( conn );
193                       
194                        return FALSE;
195                }
[26fdfc5]196               
[309cb9e]197                conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
198                return FALSE;
[26fdfc5]199        }
[b7d3cc34]200       
201        conn->established = TRUE;
[26fdfc5]202        sock_make_blocking( conn->fd );         /* For now... */
[486ddb5]203        conn->func( conn->data, 0, conn, cond );
[309cb9e]204        return FALSE;
[b7d3cc34]205}
206
207int ssl_read( void *conn, char *buf, int len )
208{
[26fdfc5]209        int st;
210       
[b7d3cc34]211        if( !((struct scd*)conn)->established )
[26fdfc5]212        {
213                ssl_errno = SSL_NOHANDSHAKE;
214                return -1;
215        }
216       
217        st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
[b7d3cc34]218       
[26fdfc5]219        ssl_errno = SSL_OK;
220        if( st <= 0 )
221        {
222                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
223                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
224                        ssl_errno = SSL_AGAIN;
225        }
226       
[327af51]227        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
[50b8978]228       
[26fdfc5]229        return st;
[b7d3cc34]230}
231
232int ssl_write( void *conn, const char *buf, int len )
233{
[26fdfc5]234        int st;
235       
[b7d3cc34]236        if( !((struct scd*)conn)->established )
[26fdfc5]237        {
238                ssl_errno = SSL_NOHANDSHAKE;
239                return -1;
240        }
241       
242        st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
[b7d3cc34]243       
[327af51]244        if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
[50b8978]245       
[26fdfc5]246        ssl_errno = SSL_OK;
247        if( st <= 0 )
248        {
249                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
250                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
251                        ssl_errno = SSL_AGAIN;
252        }
253       
254        return st;
[b7d3cc34]255}
256
[8a2221a7]257int ssl_pending( void *conn )
258{
259        return ( ((struct scd*)conn) && ((struct scd*)conn)->established ) ?
260               SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0;
261}
262
[b7d3cc34]263void ssl_disconnect( void *conn_ )
264{
265        struct scd *conn = conn_;
266       
[26fdfc5]267        if( conn->inpa != -1 )
[309cb9e]268                b_event_remove( conn->inpa );
[26fdfc5]269       
[b7d3cc34]270        if( conn->established )
271                SSL_shutdown( conn->ssl );
272       
273        closesocket( conn->fd );
274       
275        SSL_free( conn->ssl );
276        SSL_CTX_free( conn->ssl_ctx );
277        g_free( conn );
278}
279
280int ssl_getfd( void *conn )
281{
282        return( ((struct scd*)conn)->fd );
283}
[26fdfc5]284
[ba9edaa]285b_input_condition ssl_getdirection( void *conn )
[26fdfc5]286{
[e046390]287        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
[26fdfc5]288}
[523fb23]289
[78b8401]290char *ssl_verify_strerror( int code )
291{
292        return g_strdup( "SSL certificate verification not supported by BitlBee OpenSSL code." );
293}
294
[523fb23]295size_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)
296{
297        int output_length = 0;   
[50b8978]298        EVP_CIPHER_CTX ctx;
[523fb23]299       
300        *res = g_new0(unsigned char, 72);
301       
302        /* Don't set key or IV because we will modify the parameters */
303        EVP_CIPHER_CTX_init(&ctx);
304        EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, NULL, NULL, 1);
305        EVP_CIPHER_CTX_set_key_length(&ctx, key_len);
306        EVP_CIPHER_CTX_set_padding(&ctx, 0);
307        /* We finished modifying parameters so now we can set key and IV */
308        EVP_CipherInit_ex(&ctx, NULL, NULL, key, iv, 1);
309        EVP_CipherUpdate(&ctx, *res, &output_length, input, input_len);
310        EVP_CipherFinal_ex(&ctx, *res, &output_length);
311        EVP_CIPHER_CTX_cleanup(&ctx);   
[50b8978]312        //EVP_cleanup();
[523fb23]313       
314        return output_length;
315}
Note: See TracBrowser for help on using the repository browser.