Scan media entities as well, not just url entities. This should expand more
[bitlbee.git] / lib / ssl_openssl.c
blobc1aa6b1b42f0ff8b2128a76ed0fffb60a7c95e63
1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
3 * *
4 * Copyright 2002-2004 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* SSL module - OpenSSL version */
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.
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.
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
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>
33 #include "bitlbee.h"
34 #include "proxy.h"
35 #include "ssl_client.h"
36 #include "sock.h"
38 int ssl_errno = 0;
40 static gboolean initialized = FALSE;
42 struct scd
44 ssl_input_function func;
45 gpointer data;
46 int fd;
47 gboolean established;
48 gboolean verify;
50 int inpa;
51 int lasterr; /* Necessary for SSL_get_error */
52 SSL *ssl;
53 SSL_CTX *ssl_ctx;
56 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
57 static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
58 static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond );
61 void ssl_init( void )
63 initialized = TRUE;
64 SSL_library_init();
65 // SSLeay_add_ssl_algorithms();
68 void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
70 struct scd *conn = g_new0( struct scd, 1 );
72 conn->fd = proxy_connect( host, port, ssl_connected, conn );
73 if( conn->fd < 0 )
75 g_free( conn );
76 return NULL;
79 conn->func = func;
80 conn->data = data;
81 conn->inpa = -1;
83 return conn;
86 void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
88 struct scd *conn = g_new0( struct scd, 1 );
90 conn->fd = fd;
91 conn->func = func;
92 conn->data = data;
93 conn->inpa = -1;
94 conn->verify = verify && global.conf->cafile;
96 /* This function should be called via a (short) timeout instead of
97 directly from here, because these SSL calls are *supposed* to be
98 *completely* asynchronous and not ready yet when this function
99 (or *_connect, for examle) returns. Also, errors are reported via
100 the callback function, not via this function's return value.
102 In short, doing things like this makes the rest of the code a lot
103 simpler. */
105 b_timeout_add( 1, ssl_starttls_real, conn );
107 return conn;
110 static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
112 struct scd *conn = data;
114 return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );
117 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
119 struct scd *conn = data;
120 const SSL_METHOD *meth;
122 /* Right now we don't have any verification functionality for OpenSSL. */
124 if( conn->verify )
126 conn->func( conn->data, 1, NULL, cond );
127 if( source >= 0 ) closesocket( source );
128 g_free( conn );
130 return FALSE;
133 if( source == -1 )
134 goto ssl_connected_failure;
136 if( !initialized )
138 ssl_init();
141 meth = TLSv1_client_method();
142 conn->ssl_ctx = SSL_CTX_new( meth );
143 if( conn->ssl_ctx == NULL )
144 goto ssl_connected_failure;
146 conn->ssl = SSL_new( conn->ssl_ctx );
147 if( conn->ssl == NULL )
148 goto ssl_connected_failure;
150 /* We can do at least the handshake with non-blocking I/O */
151 sock_make_nonblocking( conn->fd );
152 SSL_set_fd( conn->ssl, conn->fd );
154 return ssl_handshake( data, source, cond );
156 ssl_connected_failure:
157 conn->func( conn->data, 0, NULL, cond );
159 if( conn->ssl )
161 SSL_shutdown( conn->ssl );
162 SSL_free( conn->ssl );
164 if( conn->ssl_ctx )
166 SSL_CTX_free( conn->ssl_ctx );
168 if( source >= 0 ) closesocket( source );
169 g_free( conn );
171 return FALSE;
175 static gboolean ssl_handshake( gpointer data, gint source, b_input_condition cond )
177 struct scd *conn = data;
178 int st;
180 if( ( st = SSL_connect( conn->ssl ) ) < 0 )
182 conn->lasterr = SSL_get_error( conn->ssl, st );
183 if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
185 conn->func( conn->data, 0, NULL, cond );
187 SSL_shutdown( conn->ssl );
188 SSL_free( conn->ssl );
189 SSL_CTX_free( conn->ssl_ctx );
191 if( source >= 0 ) closesocket( source );
192 g_free( conn );
194 return FALSE;
197 conn->inpa = b_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data );
198 return FALSE;
201 conn->established = TRUE;
202 sock_make_blocking( conn->fd ); /* For now... */
203 conn->func( conn->data, 0, conn, cond );
204 return FALSE;
207 int ssl_read( void *conn, char *buf, int len )
209 int st;
211 if( !((struct scd*)conn)->established )
213 ssl_errno = SSL_NOHANDSHAKE;
214 return -1;
217 st = SSL_read( ((struct scd*)conn)->ssl, buf, len );
219 ssl_errno = SSL_OK;
220 if( st <= 0 )
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;
227 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
229 return st;
232 int ssl_write( void *conn, const char *buf, int len )
234 int st;
236 if( !((struct scd*)conn)->established )
238 ssl_errno = SSL_NOHANDSHAKE;
239 return -1;
242 st = SSL_write( ((struct scd*)conn)->ssl, buf, len );
244 if( 0 && getenv( "BITLBEE_DEBUG" ) && st > 0 ) write( 1, buf, st );
246 ssl_errno = SSL_OK;
247 if( st <= 0 )
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;
254 return st;
257 int ssl_pending( void *conn )
259 return ( ((struct scd*)conn) && ((struct scd*)conn)->established ) ?
260 SSL_pending( ((struct scd*)conn)->ssl ) > 0 : 0;
263 void ssl_disconnect( void *conn_ )
265 struct scd *conn = conn_;
267 if( conn->inpa != -1 )
268 b_event_remove( conn->inpa );
270 if( conn->established )
271 SSL_shutdown( conn->ssl );
273 closesocket( conn->fd );
275 SSL_free( conn->ssl );
276 SSL_CTX_free( conn->ssl_ctx );
277 g_free( conn );
280 int ssl_getfd( void *conn )
282 return( ((struct scd*)conn)->fd );
285 b_input_condition ssl_getdirection( void *conn )
287 return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? B_EV_IO_WRITE : B_EV_IO_READ );
290 char *ssl_verify_strerror( int code )
292 return g_strdup( "SSL certificate verification not supported by BitlBee OpenSSL code." );
295 size_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)
297 int output_length = 0;
298 EVP_CIPHER_CTX ctx;
300 *res = g_new0(unsigned char, 72);
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);
312 //EVP_cleanup();
314 return output_length;