1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
4 * Copyright 2002-2004 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* SSL module - OpenSSL version */
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>
35 #include "ssl_client.h"
40 static gboolean initialized
= FALSE
;
44 ssl_input_function func
;
51 int lasterr
; /* Necessary for SSL_get_error */
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
);
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
);
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 );
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
105 b_timeout_add( 1, ssl_starttls_real
, 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. */
126 conn
->func( conn
->data
, 1, NULL
, cond
);
127 if( source
>= 0 ) closesocket( source
);
134 goto ssl_connected_failure
;
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
);
161 SSL_shutdown( conn
->ssl
);
162 SSL_free( conn
->ssl
);
166 SSL_CTX_free( conn
->ssl_ctx
);
168 if( source
>= 0 ) closesocket( source
);
175 static gboolean
ssl_handshake( gpointer data
, gint source
, b_input_condition cond
)
177 struct scd
*conn
= data
;
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
);
197 conn
->inpa
= b_input_add( conn
->fd
, ssl_getdirection( conn
), ssl_handshake
, data
);
201 conn
->established
= TRUE
;
202 sock_make_blocking( conn
->fd
); /* For now... */
203 conn
->func( conn
->data
, 0, conn
, cond
);
207 int ssl_read( void *conn
, char *buf
, int len
)
211 if( !((struct scd
*)conn
)->established
)
213 ssl_errno
= SSL_NOHANDSHAKE
;
217 st
= SSL_read( ((struct scd
*)conn
)->ssl
, buf
, len
);
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
);
232 int ssl_write( void *conn
, const char *buf
, int len
)
236 if( !((struct scd
*)conn
)->established
)
238 ssl_errno
= SSL_NOHANDSHAKE
;
242 st
= SSL_write( ((struct scd
*)conn
)->ssl
, buf
, len
);
244 if( 0 && getenv( "BITLBEE_DEBUG" ) && st
> 0 ) write( 1, buf
, st
);
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
;
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
);
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;
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
);
314 return output_length
;