source: protocols/ssl_openssl.c @ 309cb9e

Last change on this file since 309cb9e was 309cb9e, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-05-13T14:20:32Z

OpenSSL support.

  • Property mode set to 100644
File size: 5.2 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( conn->inpa != -1 )
118        {
119                b_event_remove( conn->inpa );
120                conn->inpa = -1;
121        }
122       
123        if( ( st = SSL_connect( conn->ssl ) ) < 0 )
124        {
125                conn->lasterr = SSL_get_error( conn->ssl, st );
126                if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
127                        goto ssl_connected_failure;
128               
129                conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
130                return FALSE;
131        }
132       
133        conn->established = TRUE;
134        sock_make_blocking( conn->fd );         /* For now... */
135        conn->func( conn->data, conn, cond );
136        return FALSE;
137       
138ssl_connected_failure:
139        conn->func( conn->data, NULL, cond );
140       
141        if( conn->ssl )
142        {
143                SSL_shutdown( conn->ssl );
144                SSL_free( conn->ssl );
145        }
146        if( conn->ssl_ctx )
147        {
148                SSL_CTX_free( conn->ssl_ctx );
149        }
150        if( source >= 0 ) closesocket( source );
151        g_free( conn );
152       
153        return FALSE;
154}
155
156int ssl_read( void *conn, char *buf, int len )
157{
158        int st;
159       
160        if( !((struct scd*)conn)->established )
161        {
162                ssl_errno = SSL_NOHANDSHAKE;
163                return -1;
164        }
165       
166        st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
167       
168        ssl_errno = SSL_OK;
169        if( st <= 0 )
170        {
171                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
172                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
173                        ssl_errno = SSL_AGAIN;
174        }
175       
176        return st;
177}
178
179int ssl_write( void *conn, const char *buf, int len )
180{
181        int st;
182       
183        if( !((struct scd*)conn)->established )
184        {
185                ssl_errno = SSL_NOHANDSHAKE;
186                return -1;
187        }
188       
189        st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
190       
191        ssl_errno = SSL_OK;
192        if( st <= 0 )
193        {
194                ((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st );
195                if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE )
196                        ssl_errno = SSL_AGAIN;
197        }
198       
199        return st;
200}
201
202void ssl_disconnect( void *conn_ )
203{
204        struct scd *conn = conn_;
205       
206        if( conn->inpa != -1 )
207                b_event_remove( conn->inpa );
208       
209        if( conn->established )
210                SSL_shutdown( conn->ssl );
211       
212        closesocket( conn->fd );
213       
214        SSL_free( conn->ssl );
215        SSL_CTX_free( conn->ssl_ctx );
216        g_free( conn );
217}
218
219int ssl_getfd( void *conn )
220{
221        return( ((struct scd*)conn)->fd );
222}
223
224b_input_condition ssl_getdirection( void *conn )
225{
226        return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ );
227}
Note: See TracBrowser for help on using the repository browser.