Changeset 486ddb5


Ignore:
Timestamp:
2011-12-19T14:50:58Z (12 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
78b8401
Parents:
5a48afd
Message:

Initial merge of tls_verify patch from AopicieR.

Files:
12 edited

Legend:

Unmodified
Added
Removed
  • conf.c

    r5a48afd r486ddb5  
    6767        conf->ft_listen = NULL;
    6868        conf->protocols = NULL;
     69        conf->cafile = NULL;
    6970        proxytype = 0;
    7071       
     
    340341                                conf->protocols = g_strsplit_set( ini->value, " \t,;", -1 );
    341342                        }
     343                        else if( g_strcasecmp( ini->key, "cafile" ) == 0 )
     344                        {
     345                                g_free( conf->cafile );
     346                                conf->cafile = g_strdup( ini->value );
     347                        }
    342348                        else
    343349                        {
  • conf.h

    r5a48afd r486ddb5  
    5454        char *ft_listen;
    5555        char **protocols;
     56        char *cafile;
    5657} conf_t;
    5758
  • lib/http_client.c

    r5a48afd r486ddb5  
    3333
    3434static gboolean http_connected( gpointer data, int source, b_input_condition cond );
    35 static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond );
     35static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond );
    3636static gboolean http_incoming_data( gpointer data, int source, b_input_condition cond );
    3737static void http_free( struct http_request *req );
     
    170170}
    171171
    172 static gboolean http_ssl_connected( gpointer data, void *source, b_input_condition cond )
    173 {
     172static gboolean http_ssl_connected( gpointer data, int returncode, void *source, b_input_condition cond )
     173{
     174        //The returncode is not used at the moment.
    174175        struct http_request *req = data;
    175176       
  • lib/ssl_bogus.c

    r5a48afd r486ddb5  
    5656}
    5757
    58 void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
     58void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
    5959{
    6060        return NULL;
  • lib/ssl_client.h

    r5a48afd r486ddb5  
    3737/* Some generic error codes. Especially SSL_AGAIN is important if you
    3838   want to do asynchronous I/O. */
     39#define NSS_VERIFY_ERROR -2
     40#define OPENSSL_VERIFY_ERROR -1
    3941#define SSL_OK            0
    4042#define SSL_NOHANDSHAKE   1
    4143#define SSL_AGAIN         2
     44#define VERIFY_CERT_ERROR 2
     45#define VERIFY_CERT_INVALID 4
     46#define VERIFY_CERT_REVOKED 8
     47#define VERIFY_CERT_SIGNER_NOT_FOUND 16
     48#define VERIFY_CERT_SIGNER_NOT_CA 32
     49#define VERIFY_CERT_INSECURE_ALGORITHM 64
     50#define VERIFY_CERT_NOT_ACTIVATED 128
     51#define VERIFY_CERT_EXPIRED 256
     52#define VERIFY_CERT_WRONG_HOSTNAME 512
    4253
    4354extern int ssl_errno;
    4455
    4556/* This is what your callback function should look like. */
    46 typedef gboolean (*ssl_input_function)(gpointer, void*, b_input_condition);
     57typedef gboolean (*ssl_input_function)(gpointer, int, void*, b_input_condition);
    4758
    4859
     
    5768/* Start an SSL session on an existing fd. Useful for STARTTLS functionality,
    5869   for example in Jabber. */
    59 G_MODULE_EXPORT void *ssl_starttls( int fd, ssl_input_function func, gpointer data );
     70G_MODULE_EXPORT void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data );
    6071
    6172/* Obviously you need special read/write functions to read data. */
  • lib/ssl_gnutls.c

    r5a48afd r486ddb5  
    2525
    2626#include <gnutls/gnutls.h>
     27#include <gnutls/x509.h>
    2728#include <gcrypt.h>
    2829#include <fcntl.h>
     
    3233#include "sock.h"
    3334#include "stdlib.h"
     35#include "bitlbee.h"
    3436
    3537int ssl_errno = 0;
     
    5456        gboolean established;
    5557        int inpa;
     58        char *hostname;
     59        gboolean verify;
    5660       
    5761        gnutls_session session;
     
    9296}
    9397
    94 void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
     98void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
    9599{
    96100        struct scd *conn = g_new0( struct scd, 1 );
     
    100104        conn->data = data;
    101105        conn->inpa = -1;
     106        conn->hostname = hostname;
     107       
     108        /* For now, SSL verification is globally enabled by setting the cafile
     109           setting in bitlbee.conf. Commented out by default because probably
     110           not everyone has this file in the same place and plenty of folks
     111           may not have the cert of their private Jabber server in it. */
     112        conn->verify = verify && global.conf->cafile;
    102113       
    103114        /* This function should be called via a (short) timeout instead of
     
    122133}
    123134
     135static int verify_certificate_callback( gnutls_session_t session )
     136{
     137        unsigned int status;
     138        const gnutls_datum_t *cert_list;
     139        unsigned int cert_list_size;
     140        int gnutlsret;
     141        int verifyret = 0;
     142        gnutls_x509_crt_t cert;
     143        const char *hostname;
     144       
     145        hostname = gnutls_session_get_ptr(session );
     146
     147        gnutlsret = gnutls_certificate_verify_peers2( session, &status );
     148        if( gnutlsret < 0 )
     149                return VERIFY_CERT_ERROR;
     150
     151        if( status & GNUTLS_CERT_INVALID )
     152                verifyret |= VERIFY_CERT_INVALID;
     153
     154        if( status & GNUTLS_CERT_REVOKED )
     155                verifyret |= VERIFY_CERT_REVOKED;
     156
     157        if( status & GNUTLS_CERT_SIGNER_NOT_FOUND )
     158                verifyret |= VERIFY_CERT_SIGNER_NOT_FOUND;
     159
     160        if( status & GNUTLS_CERT_SIGNER_NOT_CA )
     161                verifyret |= VERIFY_CERT_SIGNER_NOT_CA;
     162
     163        if( status & GNUTLS_CERT_INSECURE_ALGORITHM )
     164                verifyret |= VERIFY_CERT_INSECURE_ALGORITHM;
     165
     166        if( status & GNUTLS_CERT_NOT_ACTIVATED )
     167                verifyret |= VERIFY_CERT_NOT_ACTIVATED;
     168
     169        if( status & GNUTLS_CERT_EXPIRED )
     170                verifyret |= VERIFY_CERT_EXPIRED;
     171
     172        /* The following check is already performed inside
     173         * gnutls_certificate_verify_peers2, so we don't need it.
     174
     175         * if( gnutls_certificate_type_get( session ) != GNUTLS_CRT_X509 )
     176         * return GNUTLS_E_CERTIFICATE_ERROR;
     177         */
     178
     179        if( gnutls_x509_crt_init( &cert ) < 0 )
     180                return VERIFY_CERT_ERROR;
     181
     182        cert_list = gnutls_certificate_get_peers( session, &cert_list_size );
     183        if( cert_list == NULL || gnutls_x509_crt_import( cert, &cert_list[0], GNUTLS_X509_FMT_DER ) < 0 )
     184                return VERIFY_CERT_ERROR;
     185
     186        if( !gnutls_x509_crt_check_hostname( cert, hostname ) )
     187        {
     188                verifyret |= VERIFY_CERT_INVALID;
     189                verifyret |= VERIFY_CERT_WRONG_HOSTNAME;
     190        }
     191
     192        gnutls_x509_crt_deinit( cert );
     193
     194        return verifyret;
     195}
     196
    124197static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
    125198{
     
    128201        if( source == -1 )
    129202        {
    130                 conn->func( conn->data, NULL, cond );
     203                conn->func( conn->data, 0, NULL, cond );
    131204                g_free( conn );
    132205                return FALSE;
     
    136209       
    137210        gnutls_certificate_allocate_credentials( &conn->xcred );
     211        if( conn->verify && global.conf->cafile )
     212        {
     213                gnutls_certificate_set_x509_trust_file( conn->xcred, global.conf->cafile, GNUTLS_X509_FMT_PEM );
     214                gnutls_certificate_set_verify_flags( conn->xcred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT );
     215        }
     216
    138217        gnutls_init( &conn->session, GNUTLS_CLIENT );
     218        if( conn->verify )
     219                gnutls_session_set_ptr( conn->session, (void *) conn->hostname );
    139220#if GNUTLS_VERSION_NUMBER < 0x020c00
    140221        gnutls_transport_set_lowat( conn->session, 0 );
     
    152233{
    153234        struct scd *conn = data;
    154         int st;
     235        int st, stver;
    155236       
    156237        if( ( st = gnutls_handshake( conn->session ) ) < 0 )
     
    163244                else
    164245                {
    165                         conn->func( conn->data, NULL, cond );
     246                        conn->func( conn->data, 0, NULL, cond );
    166247                       
    167248                        gnutls_deinit( conn->session );
     
    174255        else
    175256        {
    176                 /* For now we can't handle non-blocking perfectly everywhere... */
    177                 sock_make_blocking( conn->fd );
     257                if( conn->verify && ( stver = verify_certificate_callback( conn->session ) ) != 0 )
     258                {
     259                        conn->func( conn->data, stver, NULL, cond );
     260
     261                        gnutls_deinit( conn->session );
     262                        gnutls_certificate_free_credentials( conn->xcred );
     263                        closesocket( conn->fd );
     264
     265                        g_free( conn );
     266                }
     267                else
     268                {
     269                        /* For now we can't handle non-blocking perfectly everywhere... */
     270                        sock_make_blocking( conn->fd );
    178271               
    179                 conn->established = TRUE;
    180                 conn->func( conn->data, conn, cond );
     272                        conn->established = TRUE;
     273                        conn->func( conn->data, 0, conn, cond );
     274                }
    181275        }
    182276       
  • lib/ssl_nss.c

    r5a48afd r486ddb5  
    5252        PRFileDesc *prfd;
    5353        gboolean established;
     54        gboolean verify;
    5455};
    5556
     
    132133}
    133134
    134 void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
     135void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
    135136{
    136137        struct scd *conn = g_new0( struct scd, 1 );
     
    139140        conn->func = func;
    140141        conn->data = data;
     142        conn->verify = verify;
    141143
    142144        /* This function should be called via a (short) timeout instead of
     
    157159{
    158160        struct scd *conn = data;
     161       
     162        /* Right now we don't have any verification functionality for nss so we
     163           fail in case verification has been requested by the user. */
     164
     165        if( conn->verify )
     166        {
     167                conn->func( conn->data, NSS_VERIFY_ERROR, NULL, cond );
     168                if( source >= 0 ) closesocket( source );
     169                g_free( conn );
     170
     171                return FALSE;
     172        }
    159173       
    160174        if( source == -1 )
     
    177191       
    178192        conn->established = TRUE;
    179         conn->func( conn->data, conn, cond );
     193        conn->func( conn->data, 0, conn, cond );
    180194        return FALSE;
    181195       
    182196        ssl_connected_failure:
    183197       
    184         conn->func( conn->data, NULL, cond );
     198        conn->func( conn->data, 0, NULL, cond );
    185199       
    186200        PR_Close( conn -> prfd );
  • lib/ssl_openssl.c

    r5a48afd r486ddb5  
    4545        int fd;
    4646        gboolean established;
     47        gboolean verify;
    4748       
    4849        int inpa;
     
    8283}
    8384
    84 void *ssl_starttls( int fd, ssl_input_function func, gpointer data )
     85void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
    8586{
    8687        struct scd *conn = g_new0( struct scd, 1 );
     
    9091        conn->data = data;
    9192        conn->inpa = -1;
     93        conn->verify = verify;
    9294       
    9395        /* This function should be called via a (short) timeout instead of
     
    117119        SSL_METHOD *meth;
    118120       
     121        /* Right now we don't have any verification functionality for openssl so we
     122           fail in case verification has been requested by the user. */
     123
     124        if( conn->verify )
     125        {
     126                conn->func( conn->data, OPENSSL_VERIFY_ERROR, NULL, cond );
     127                if( source >= 0 ) closesocket( source );
     128                g_free( conn );
     129
     130                return FALSE;
     131        }
     132
    119133        if( source == -1 )
    120134                goto ssl_connected_failure;
     
    141155
    142156ssl_connected_failure:
    143         conn->func( conn->data, NULL, cond );
     157        conn->func( conn->data, 0, NULL, cond );
    144158       
    145159        if( conn->ssl )
     
    169183                if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE )
    170184                {
    171                         conn->func( conn->data, NULL, cond );
     185                        conn->func( conn->data, 0, NULL, cond );
    172186                       
    173187                        SSL_shutdown( conn->ssl );
     
    187201        conn->established = TRUE;
    188202        sock_make_blocking( conn->fd );         /* For now... */
    189         conn->func( conn->data, conn, cond );
     203        conn->func( conn->data, 0, conn, cond );
    190204        return FALSE;
    191205}
  • protocols/jabber/io.c

    r5a48afd r486ddb5  
    276276}
    277277
    278 gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond )
     278gboolean jabber_connected_ssl( gpointer data, int returncode, void *source, b_input_condition cond )
    279279{
    280280        struct im_connection *ic = data;
     
    293293               
    294294                imcb_error( ic, "Could not connect to server" );
     295                if (returncode ==  OPENSSL_VERIFY_ERROR )
     296                {
     297                        imcb_error( ic, "This BitlBee server is built agains the OpenSSL library." );
     298                        imcb_error( ic, "Unfortunately certificate verification is only supported when built against GnuTLS for now." );
     299                        imc_logout( ic, FALSE );
     300                }
     301                else if (returncode ==  NSS_VERIFY_ERROR )
     302                {
     303                        imcb_error( ic, "This BitlBee server is built agains the NSS library." );
     304                        imcb_error( ic, "Unfortunately certificate verification is only supported when built against GnuTLS for now." );
     305                        imc_logout( ic, FALSE );
     306                }
     307                else if (returncode == VERIFY_CERT_ERROR )
     308                {
     309                        imcb_error( ic, "An error occured during the certificate verification." );
     310                        imc_logout( ic, FALSE );
     311                }
     312                else if (returncode  & VERIFY_CERT_INVALID)
     313                {
     314                        imcb_error( ic, "Unable to verify peer's certificate." );
     315                        if (returncode & VERIFY_CERT_REVOKED)
     316                                imcb_error( ic, "The certificate has been revoked." );
     317                        if (returncode & VERIFY_CERT_SIGNER_NOT_FOUND)
     318                                imcb_error( ic, "The certificate hasn't got a known issuer." );
     319                        if (returncode & VERIFY_CERT_SIGNER_NOT_CA)
     320                                imcb_error( ic, "The certificate's issuer is not a CA." );
     321                        if (returncode & VERIFY_CERT_INSECURE_ALGORITHM)
     322                                imcb_error( ic, "The certificate uses an insecure algorithm." );
     323                        if (returncode & VERIFY_CERT_NOT_ACTIVATED)
     324                                imcb_error( ic, "The certificate has not been activated." );
     325                        if (returncode & VERIFY_CERT_EXPIRED)
     326                                imcb_error( ic, "The certificate has expired." );
     327                        if (returncode & VERIFY_CERT_WRONG_HOSTNAME)
     328                                imcb_error( ic, "The hostname specified in the certificate doesn't match the server name." );
     329                        imc_logout( ic, FALSE );
     330                }
     331                else
    295332                imc_logout( ic, TRUE );
    296333                return FALSE;
     
    397434        struct im_connection *ic = data;
    398435        struct jabber_data *jd = ic->proto_data;
    399         char *xmlns;
     436        char *xmlns, *tlsname;
    400437       
    401438        xmlns = xt_find_attr( node, "xmlns" );
     
    423460       
    424461        jd->flags |= JFLAG_STARTTLS_DONE;
    425         jd->ssl = ssl_starttls( jd->fd, jabber_connected_ssl, ic );
     462
     463        /* If the user specified a server for the account, use this server as the
     464         * hostname in the certificate verification. Else we use the domain from
     465         * the username. */
     466        if( ic->acc->server && *ic->acc->server )
     467                tlsname = ic->acc->server;
     468        else
     469                tlsname = jd->server;
     470       
     471        jd->ssl = ssl_starttls( jd->fd, tlsname, set_getbool( &ic->acc->set, "tls_verify" ),
     472                                jabber_connected_ssl, ic );
    426473       
    427474        return XT_HANDLED;
  • protocols/jabber/jabber.c

    r5a48afd r486ddb5  
    8080       
    8181        s = set_add( &acc->set, "tls", "try", set_eval_tls, acc );
     82        s->flags |= ACC_SET_OFFLINE_ONLY;
     83       
     84        s = set_add( &acc->set, "tls_verify", "true", set_eval_bool, acc );
    8285        s->flags |= ACC_SET_OFFLINE_ONLY;
    8386       
  • protocols/jabber/jabber.h

    r5a48afd r486ddb5  
    307307int jabber_write( struct im_connection *ic, char *buf, int len );
    308308gboolean jabber_connected_plain( gpointer data, gint source, b_input_condition cond );
    309 gboolean jabber_connected_ssl( gpointer data, void *source, b_input_condition cond );
     309gboolean jabber_connected_ssl( gpointer data, int returncode, void *source, b_input_condition cond );
    310310gboolean jabber_start_stream( struct im_connection *ic );
    311311void jabber_end_stream( struct im_connection *ic );
  • protocols/skype/skype.c

    r5a48afd r486ddb5  
    11571157}
    11581158
    1159 gboolean skype_connected(gpointer data, void *source, b_input_condition cond)
     1159gboolean skype_connected(gpointer data, int returncode, void *source, b_input_condition cond)
    11601160{
    11611161        struct im_connection *ic = data;
Note: See TracChangeset for help on using the changeset viewer.