Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/ssl_gnutls.c

    r632f3d4 r9b67285  
    22  * BitlBee -- An IRC to other IM-networks gateway                     *
    33  *                                                                    *
    4   * Copyright 2002-2011 Wilmer van der Gaast and others                *
     4  * Copyright 2002-2012 Wilmer van der Gaast and others                *
    55  \********************************************************************/
    66
     
    3838
    3939static gboolean initialized = FALSE;
    40 gnutls_certificate_credentials xcred;
     40gnutls_certificate_credentials_t xcred;
    4141
    4242#include <limits.h>
     
    6060        gboolean verify;
    6161       
    62         gnutls_session session;
     62        gnutls_session_t session;
    6363};
     64
     65static GHashTable *session_cache;
    6466
    6567static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
     
    8587                gnutls_certificate_set_x509_trust_file( xcred, global.conf->cafile, GNUTLS_X509_FMT_PEM );
    8688               
    87                 /* Not needed in GnuTLS 2.11+ but we support older versions for now. */
    88                 gnutls_certificate_set_verify_flags( xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT );
     89                /* Not needed in GnuTLS 2.11+ (enabled by default there) so
     90                   don't do it (resets possible other defaults). */
     91                if( !gnutls_check_version( "2.11" ) )
     92                        gnutls_certificate_set_verify_flags( xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT );
    8993        }
    9094        initialized = TRUE;
     
    9599        */
    96100       
     101        session_cache = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, g_free );
     102       
    97103        atexit( ssl_deinit );
    98104}
     
    102108        gnutls_global_deinit();
    103109        gnutls_certificate_free_credentials( xcred );
     110        g_hash_table_destroy( session_cache );
     111        session_cache = NULL;
    104112}
    105113
     
    108116        struct scd *conn = g_new0( struct scd, 1 );
    109117       
    110         conn->fd = proxy_connect( host, port, ssl_connected, conn );
    111118        conn->func = func;
    112119        conn->data = data;
     
    114121        conn->hostname = g_strdup( host );
    115122        conn->verify = verify && global.conf->cafile;
     123        conn->fd = proxy_connect( host, port, ssl_connected, conn );
    116124       
    117125        if( conn->fd < 0 )
     
    132140        conn->data = data;
    133141        conn->inpa = -1;
    134         conn->hostname = hostname;
     142        conn->hostname = g_strdup( hostname );
    135143       
    136144        /* For now, SSL verification is globally enabled by setting the cafile
     
    169177        int verifyret = 0;
    170178        gnutls_x509_crt_t cert;
    171         const char *hostname;
    172        
    173         hostname = gnutls_session_get_ptr( session );
     179        struct scd *conn;
     180       
     181        conn = gnutls_session_get_ptr( session );
    174182
    175183        gnutlsret = gnutls_certificate_verify_peers2( session, &status );
     
    209217                return VERIFY_CERT_ERROR;
    210218
    211         if( !gnutls_x509_crt_check_hostname( cert, hostname ) )
     219        if( !gnutls_x509_crt_check_hostname( cert, conn->hostname ) )
    212220        {
    213221                verifyret |= VERIFY_CERT_INVALID;
     
    218226
    219227        return verifyret;
     228}
     229
     230struct ssl_session
     231{
     232        size_t size;
     233        char data[];
     234};
     235
     236static void ssl_cache_add( struct scd *conn )
     237{
     238        size_t data_size;
     239        struct ssl_session *data;
     240        char *hostname;
     241       
     242        if( !conn->hostname ||
     243            gnutls_session_get_data( conn->session, NULL, &data_size ) != 0 )
     244                return;
     245       
     246        data = g_malloc( sizeof( struct ssl_session ) + data_size );
     247        if( gnutls_session_get_data( conn->session, data->data, &data->size ) != 0 )
     248        {
     249                g_free( data );
     250                return;
     251        }
     252       
     253        hostname = g_strdup( conn->hostname );
     254        g_hash_table_insert( session_cache, hostname, data );
     255}
     256
     257static void ssl_cache_resume( struct scd *conn )
     258{
     259        struct ssl_session *data;
     260       
     261        if( conn->hostname &&
     262            ( data = g_hash_table_lookup( session_cache, conn->hostname ) ) )
     263        {
     264                gnutls_session_set_data( conn->session, data->data, data->size );
     265                g_hash_table_remove( session_cache, conn->hostname );
     266        }
    220267}
    221268
     
    265312       
    266313        gnutls_init( &conn->session, GNUTLS_CLIENT );
    267         if( conn->verify )
    268                 gnutls_session_set_ptr( conn->session, (void *) conn->hostname );
     314        gnutls_session_set_ptr( conn->session, (void *) conn );
    269315#if GNUTLS_VERSION_NUMBER < 0x020c00
    270316        gnutls_transport_set_lowat( conn->session, 0 );
     
    272318        gnutls_set_default_priority( conn->session );
    273319        gnutls_credentials_set( conn->session, GNUTLS_CRD_CERTIFICATE, xcred );
     320        if( conn->hostname && !isdigit( conn->hostname[0] ) )
     321                gnutls_server_name_set( conn->session, GNUTLS_NAME_DNS,
     322                                        conn->hostname, strlen( conn->hostname ) );
    274323       
    275324        sock_make_nonblocking( conn->fd );
    276         gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) GNUTLS_STUPID_CAST conn->fd );
     325        gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr_t) GNUTLS_STUPID_CAST conn->fd );
     326       
     327        ssl_cache_resume( conn );
    277328       
    278329        return ssl_handshake( data, source, cond );
     
    316367                        /* For now we can't handle non-blocking perfectly everywhere... */
    317368                        sock_make_blocking( conn->fd );
    318                
     369                       
     370                        ssl_cache_add( conn );
    319371                        conn->established = TRUE;
    320372                        conn->func( conn->data, 0, conn, cond );
     
    400452        if( conn->session )
    401453                gnutls_deinit( conn->session );
     454        g_free( conn->hostname );
    402455        g_free( conn );
    403456}
Note: See TracChangeset for help on using the changeset viewer.