source: protocols/ssl_openssl.c @ 7a685f1

Last change on this file since 7a685f1 was 19ac9c5, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-05-13T19:44:59Z

Timeouts are now persistent.

  • Property mode set to 100644
File size: 5.1 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       
48        int inpa;
49        int lasterr;            /* Necessary for SSL_get_error */
50        SSL *ssl;
51        SSL_CTX *ssl_ctx;
52};
53
54static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
55
56
57void *ssl_connect( char *host, int port, ssl_input_function func, gpointer data )
58{
59        struct scd *conn = g_new0( struct scd, 1 );
60        SSL_METHOD *meth;
61       
62        conn->fd = proxy_connect( host, port, ssl_connected, conn );
63        conn->func = func;
64        conn->data = data;
65       
66        if( conn->fd < 0 )
67        {
68                g_free( conn );
69                return( NULL );
70        }
71       
72        if( !initialized )
73        {
74                initialized = TRUE;
75                SSLeay_add_ssl_algorithms();
76        }
77       
78        meth = TLSv1_client_method();
79        conn->ssl_ctx = SSL_CTX_new( meth );
80        if( conn->ssl_ctx == NULL )
81        {
82                conn->fd = -1;
83                return( NULL );
84        }
85       
86        conn->ssl = SSL_new( conn->ssl_ctx );
87        if( conn->ssl == NULL )
88        {
89                conn->fd = -1;
90                return( NULL );
91        }
92       
93        return( conn );
94}
95
96static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
97
98static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
99{
100        struct scd *conn = data;
101       
102        if( source == -1 )
103                return ssl_handshake( data, -1, cond );
104       
105        /* We can do at least the handshake with non-blocking I/O */
106        sock_make_nonblocking( conn->fd );
107        SSL_set_fd( conn->ssl, conn->fd );
108       
109        return ssl_handshake( data, source, cond );
110}       
111
112static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond )
113{
114        struct scd *conn = data;
115        int st;
116       
117        if( ( st = SSL_connect( conn->ssl ) ) < 0 )
118        {
119                conn->lasterr = SSL_get_error( conn->ssl, st );
120                if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
121                        goto ssl_connected_failure;
122               
123                conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
124                return FALSE;
125        }
126       
127        conn->established = TRUE;
128        sock_make_blocking( conn->fd );         /* For now... */
129        conn->func( conn->data, conn, cond );
130        return FALSE;
131       
132ssl_connected_failure:
133        conn->func( conn->data, NULL, cond );
134       
135        if( conn->ssl )
136        {
137                SSL_shutdown( conn->ssl );
138                SSL_free( conn->ssl );
139        }
140        if( conn->ssl_ctx )
141        {
142                SSL_CTX_free( conn->ssl_ctx );
143        }
144        if( source >= 0 ) closesocket( source );
145        g_free( conn );
146       
147        return FALSE;
148}
149
150int ssl_read( void *conn, char *buf, int len )
151{
152        int st;
153       
154        if( !((struct scd*)conn)->established )
155        {
156                ssl_errno = SSL_NOHANDSHAKE;
157                return -1;
158        }
159       
160        st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
161       
162        ssl_errno = SSL_OK;
163        if( st <= 0 )
164        {
165                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
166                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
167                        ssl_errno = SSL_AGAIN;
168        }
169       
170        return st;
171}
172
173int ssl_write( void *conn, const char *buf, int len )
174{
175        int st;
176       
177        if( !((struct scd*)conn)->established )
178        {
179                ssl_errno = SSL_NOHANDSHAKE;
180                return -1;
181        }
182       
183        st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
184       
185        ssl_errno = SSL_OK;
186        if( st <= 0 )
187        {
188                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
189                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
190                        ssl_errno = SSL_AGAIN;
191        }
192       
193        return st;
194}
195
196void ssl_disconnect( void *conn_ )
197{
198        struct scd *conn = conn_;
199       
200        if( conn->inpa != -1 )
201                b_event_remove( conn->inpa );
202       
203        if( conn->established )
204                SSL_shutdown( conn->ssl );
205       
206        closesocket( conn->fd );
207       
208        SSL_free( conn->ssl );
209        SSL_CTX_free( conn->ssl_ctx );
210        g_free( conn );
211}
212
213int ssl_getfd( void *conn )
214{
215        return( ((struct scd*)conn)->fd );
216}
217
218b_input_condition ssl_getdirection( void *conn )
219{
220        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ );
221}
Note: See TracBrowser for help on using the repository browser.