Changeset 68709f5 for lib/ssl_nss.c


Ignore:
Timestamp:
2012-08-19T15:33:55Z (12 years ago)
Author:
Wilmer van der Gaast <wilmer@…>
Branches:
master
Children:
7281ad1
Parents:
6ee51a9
Message:

NSS module fixes from mcepl in #714. This removes des.c since it's no
longer necessary.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/ssl_nss.c

    r6ee51a9 r68709f5  
    4040#include <secerr.h>
    4141#include <sslerr.h>
     42#include <assert.h>
     43#include <unistd.h>
    4244
    4345int ssl_errno = 0;
     
    4547static gboolean initialized = FALSE;
    4648
    47 struct scd
    48 {
     49#define SSLDEBUG 0
     50
     51struct scd {
    4952        ssl_input_function func;
    5053        gpointer data;
    5154        int fd;
     55        char *hostname;
    5256        PRFileDesc *prfd;
    5357        gboolean established;
     
    5559};
    5660
    57 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond );
    58 static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond );
    59 
    60 
    61 static SECStatus nss_auth_cert (void *arg, PRFileDesc *socket, PRBool checksig, PRBool isserver)
     61static gboolean ssl_connected(gpointer data, gint source,
     62                              b_input_condition cond);
     63static gboolean ssl_starttls_real(gpointer data, gint source,
     64                                  b_input_condition cond);
     65
     66static SECStatus nss_auth_cert(void *arg, PRFileDesc * socket, PRBool checksig,
     67                               PRBool isserver)
    6268{
    6369        return SECSuccess;
    6470}
    6571
    66 static SECStatus nss_bad_cert (void *arg, PRFileDesc *socket)
     72static SECStatus nss_bad_cert(void *arg, PRFileDesc * socket)
    6773{
    6874        PRErrorCode err;
    6975
    70         if(!arg) return SECFailure;
    71 
    72         *(PRErrorCode *)arg = err = PORT_GetError();
    73 
    74         switch(err) {
     76        if (!arg)
     77                return SECFailure;
     78
     79        *(PRErrorCode *) arg = err = PORT_GetError();
     80
     81        switch (err) {
    7582        case SEC_ERROR_INVALID_AVA:
    7683        case SEC_ERROR_INVALID_TIME:
     
    94101}
    95102
    96 
    97 void ssl_init( void )
    98 {
    99         PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
     103void ssl_init(void)
     104{
     105        PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
     106        // https://www.mozilla.org/projects/security/pki/nss/ref/ssl/sslfnc.html#1234224
     107        // This NSS function is not intended for use with SSL, which
     108        // requires that the certificate and key database files be
     109        // opened. Relates to whole non-verification of servers for now.
    100110        NSS_NoDB_Init(NULL);
    101111        NSS_SetDomesticPolicy();
     
    103113}
    104114
    105 void *ssl_connect( char *host, int port, gboolean verify, ssl_input_function func, gpointer data )
    106 {
    107         struct scd *conn = g_new0( struct scd, 1 );
    108        
    109         conn->fd = proxy_connect( host, port, ssl_connected, conn );
     115void *ssl_connect(char *host, int port, gboolean verify,
     116                  ssl_input_function func, gpointer data)
     117{
     118        struct scd *conn = g_new0(struct scd, 1);
     119
     120        conn->fd = proxy_connect(host, port, ssl_connected, conn);
    110121        conn->func = func;
    111122        conn->data = data;
    112        
    113         if( conn->fd < 0 )
    114         {
    115                 g_free( conn );
    116                 return( NULL );
    117         }
    118        
    119         if( !initialized )
    120         {
     123        conn->hostname = g_strdup(host);
     124
     125        if (conn->fd < 0) {
     126                g_free(conn->hostname);
     127                g_free(conn);
     128                return (NULL);
     129        }
     130
     131        if (!initialized) {
    121132                ssl_init();
    122133        }
    123134
    124        
    125         return( conn );
    126 }
    127 
    128 static gboolean ssl_starttls_real( gpointer data, gint source, b_input_condition cond )
     135        return (conn);
     136}
     137
     138static gboolean ssl_starttls_real(gpointer data, gint source,
     139                                  b_input_condition cond)
    129140{
    130141        struct scd *conn = data;
    131142
    132         return ssl_connected( conn, conn->fd, B_EV_IO_WRITE );
    133 }
    134 
    135 void *ssl_starttls( int fd, char *hostname, gboolean verify, ssl_input_function func, gpointer data )
    136 {
    137         struct scd *conn = g_new0( struct scd, 1 );
     143        return ssl_connected(conn, conn->fd, B_EV_IO_WRITE);
     144}
     145
     146void *ssl_starttls(int fd, char *hostname, gboolean verify,
     147                   ssl_input_function func, gpointer data)
     148{
     149        struct scd *conn = g_new0(struct scd, 1);
    138150
    139151        conn->fd = fd;
    140152        conn->func = func;
    141153        conn->data = data;
     154        conn->hostname = hostname;
     155
     156        /* For now, SSL verification is globally enabled by setting the cafile
     157           setting in bitlbee.conf. Commented out by default because probably
     158           not everyone has this file in the same place and plenty of folks
     159           may not have the cert of their private Jabber server in it. */
    142160        conn->verify = verify && global.conf->cafile;
    143161
     
    151169           simpler. */
    152170
    153         b_timeout_add( 1, ssl_starttls_real, conn );
     171        b_timeout_add(1, ssl_starttls_real, conn);
    154172
    155173        return conn;
    156174}
    157175
    158 static gboolean ssl_connected( gpointer data, gint source, b_input_condition cond )
     176static gboolean ssl_connected(gpointer data, gint source,
     177                              b_input_condition cond)
    159178{
    160179        struct scd *conn = data;
    161        
     180
    162181        /* Right now we don't have any verification functionality for NSS. */
    163182
    164         if( conn->verify )
    165         {
    166                 conn->func( conn->data, 1, NULL, cond );
    167                 if( source >= 0 ) closesocket( source );
    168                 g_free( conn );
     183        if (conn->verify) {
     184                conn->func(conn->data, 1, NULL, cond);
     185                if (source >= 0)
     186                        closesocket(source);
     187                g_free(conn->hostname);
     188                g_free(conn);
    169189
    170190                return FALSE;
    171191        }
    172        
    173         if( source == -1 )
     192
     193        if (source == -1)
    174194                goto ssl_connected_failure;
    175        
     195
    176196        /* Until we find out how to handle non-blocking I/O with NSS... */
    177         sock_make_blocking( conn->fd );
    178        
     197        sock_make_blocking(conn->fd);
     198
    179199        conn->prfd = SSL_ImportFD(NULL, PR_ImportTCPSocket(source));
     200        if (!conn->prfd)
     201                goto ssl_connected_failure;
    180202        SSL_OptionSet(conn->prfd, SSL_SECURITY, PR_TRUE);
    181203        SSL_OptionSet(conn->prfd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
    182         SSL_BadCertHook(conn->prfd, (SSLBadCertHandler)nss_bad_cert, NULL);
    183         SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate)nss_auth_cert, (void *)CERT_GetDefaultCertDB());
     204        SSL_BadCertHook(conn->prfd, (SSLBadCertHandler) nss_bad_cert, NULL);
     205        SSL_AuthCertificateHook(conn->prfd, (SSLAuthCertificate) nss_auth_cert,
     206                                (void *)CERT_GetDefaultCertDB());
     207        SSL_SetURL(conn->prfd, conn->hostname);
    184208        SSL_ResetHandshake(conn->prfd, PR_FALSE);
    185209
     
    187211                goto ssl_connected_failure;
    188212        }
    189        
    190        
     213
    191214        conn->established = TRUE;
    192         conn->func( conn->data, 0, conn, cond );
     215        conn->func(conn->data, 0, conn, cond);
    193216        return FALSE;
    194        
    195         ssl_connected_failure:
    196        
    197         conn->func( conn->data, 0, NULL, cond );
    198        
    199         PR_Close( conn -> prfd );
    200         if( source >= 0 ) closesocket( source );
    201         g_free( conn );
    202        
     217
     218 ssl_connected_failure:
     219
     220        conn->func(conn->data, 0, NULL, cond);
     221
     222        if (conn->prfd)
     223                PR_Close(conn->prfd);
     224        if (source >= 0)
     225                closesocket(source);
     226        g_free(conn->hostname);
     227        g_free(conn);
     228
    203229        return FALSE;
    204230}
    205231
    206 int ssl_read( void *conn, char *buf, int len )
    207 {
    208         if( !((struct scd*)conn)->established )
    209                 return( 0 );
    210        
    211         return( PR_Read( ((struct scd*)conn)->prfd, buf, len ) );
    212 }
    213 
    214 int ssl_write( void *conn, const char *buf, int len )
    215 {
    216         if( !((struct scd*)conn)->established )
    217                 return( 0 );
    218        
    219         return( PR_Write ( ((struct scd*)conn)->prfd, buf, len ) );
    220 }
    221 
    222 int ssl_pending( void *conn )
    223 {
    224         struct scd *c = (struct scd *) conn;
    225 
    226         if( c == NULL ) {
     232int ssl_read(void *conn, char *buf, int len)
     233{
     234        int st;
     235        PRErrorCode PR_err;
     236
     237        if (!((struct scd *)conn)->established) {
     238                ssl_errno = SSL_NOHANDSHAKE;
     239                return -1;
     240        }
     241
     242        st = PR_Read(((struct scd *)conn)->prfd, buf, len);
     243        PR_err = PR_GetError();
     244
     245        ssl_errno = SSL_OK;
     246        if (PR_err == PR_WOULD_BLOCK_ERROR)
     247                ssl_errno = SSL_AGAIN;
     248
     249        if (SSLDEBUG && getenv("BITLBEE_DEBUG") && st > 0)
     250                len = write(STDERR_FILENO, buf, st);
     251
     252        return st;
     253}
     254
     255int ssl_write(void *conn, const char *buf, int len)
     256{
     257        int st;
     258        PRErrorCode PR_err;
     259
     260        if (!((struct scd *)conn)->established) {
     261                ssl_errno = SSL_NOHANDSHAKE;
     262                return -1;
     263        }
     264        st = PR_Write(((struct scd *)conn)->prfd, buf, len);
     265        PR_err = PR_GetError();
     266
     267        ssl_errno = SSL_OK;
     268        if (PR_err == PR_WOULD_BLOCK_ERROR)
     269                ssl_errno = SSL_AGAIN;
     270
     271        if (SSLDEBUG && getenv("BITLBEE_DEBUG") && st > 0)
     272                len = write(2, buf, st);
     273
     274        return st;
     275}
     276
     277int ssl_pending(void *conn)
     278{
     279        struct scd *c = (struct scd *)conn;
     280
     281        if (c == NULL) {
    227282                return 0;
    228283        }
    229284
    230         return ( c->established && SSL_DataPending( c->prfd ) > 0 );
    231 }
    232 
    233 void ssl_disconnect( void *conn_ )
     285        return (c->established && SSL_DataPending(c->prfd) > 0);
     286}
     287
     288void ssl_disconnect(void *conn_)
    234289{
    235290        struct scd *conn = conn_;
    236        
    237         PR_Close( conn->prfd );
    238         closesocket( conn->fd );
    239        
    240         g_free( conn );
    241 }
    242 
    243 int ssl_getfd( void *conn )
    244 {
    245         return( ((struct scd*)conn)->fd );
    246 }
    247 
    248 b_input_condition ssl_getdirection( void *conn )
     291
     292        // When we swich to NSS_Init, we should have here
     293        // NSS_Shutdown();
     294
     295        if (conn->prfd)
     296                PR_Close(conn->prfd);
     297
     298        g_free(conn->hostname);
     299        g_free(conn);
     300}
     301
     302int ssl_getfd(void *conn)
     303{
     304        return (((struct scd *)conn)->fd);
     305}
     306
     307b_input_condition ssl_getdirection(void *conn)
    249308{
    250309        /* Just in case someone calls us, let's return the most likely case: */
     
    252311}
    253312
    254 char *ssl_verify_strerror( int code )
    255 {
    256         return g_strdup( "SSL certificate verification not supported by BitlBee NSS code." );
    257 }
     313char *ssl_verify_strerror(int code)
     314{
     315        return
     316            g_strdup
     317            ("SSL certificate verification not supported by BitlBee NSS code.");
     318}
     319
     320size_t ssl_des3_encrypt(const unsigned char *key, size_t key_len,
     321                        const unsigned char *input, size_t input_len,
     322                        const unsigned char *iv, unsigned char **res)
     323{
     324#define CIPHER_MECH CKM_DES3_CBC
     325#define MAX_OUTPUT_LEN 72
     326
     327        int len1;
     328        unsigned int len2;
     329
     330        PK11Context *ctx = NULL;
     331        PK11SlotInfo *slot = NULL;
     332        SECItem keyItem;
     333        SECItem ivItem;
     334        SECItem *secParam = NULL;
     335        PK11SymKey *symKey = NULL;
     336
     337        size_t rc;
     338        SECStatus rv;
     339
     340        if (!initialized) {
     341                ssl_init();
     342        }
     343
     344        keyItem.data = (unsigned char *)key;
     345        keyItem.len = key_len;
     346
     347        slot = PK11_GetBestSlot(CIPHER_MECH, NULL);
     348        if (slot == NULL) {
     349                fprintf(stderr, "PK11_GetBestSlot failed (err %d)\n",
     350                        PR_GetError());
     351                rc = 0;
     352                goto out;
     353        }
     354
     355        symKey =
     356            PK11_ImportSymKey(slot, CIPHER_MECH, PK11_OriginUnwrap, CKA_ENCRYPT,
     357                              &keyItem, NULL);
     358        if (symKey == NULL) {
     359                fprintf(stderr, "PK11_ImportSymKey failed (err %d)\n",
     360                        PR_GetError());
     361                rc = 0;
     362                goto out;
     363        }
     364
     365        ivItem.data = (unsigned char *)iv;
     366        /* See msn_soap_passport_sso_handle_response in protocols/msn/soap.c */
     367        ivItem.len = 8;
     368
     369        secParam = PK11_ParamFromIV(CIPHER_MECH, &ivItem);
     370        if (secParam == NULL) {
     371                fprintf(stderr, "PK11_ParamFromIV failed (err %d)\n",
     372                        PR_GetError());
     373                rc = 0;
     374                goto out;
     375        }
     376
     377        ctx =
     378            PK11_CreateContextBySymKey(CIPHER_MECH, CKA_ENCRYPT, symKey,
     379                                       secParam);
     380        if (ctx == NULL) {
     381                fprintf(stderr, "PK11_CreateContextBySymKey failed (err %d)\n",
     382                        PR_GetError());
     383                rc = 0;
     384                goto out;
     385        }
     386
     387        *res = g_new0(unsigned char, MAX_OUTPUT_LEN);
     388
     389        rv = PK11_CipherOp(ctx, *res, &len1, MAX_OUTPUT_LEN,
     390                           (unsigned char *)input, input_len);
     391        if (rv != SECSuccess) {
     392                fprintf(stderr, "PK11_CipherOp failed (err %d)\n",
     393                        PR_GetError());
     394                rc = 0;
     395                goto out;
     396        }
     397
     398        assert(len1 <= MAX_OUTPUT_LEN);
     399
     400        rv = PK11_DigestFinal(ctx, *res + len1, &len2,
     401                              (unsigned int)MAX_OUTPUT_LEN - len1);
     402        if (rv != SECSuccess) {
     403                fprintf(stderr, "PK11_DigestFinal failed (err %d)\n",
     404                        PR_GetError());
     405                rc = 0;
     406                goto out;
     407        }
     408
     409        rc = len1 + len2;
     410
     411 out:
     412        if (ctx)
     413                PK11_DestroyContext(ctx, PR_TRUE);
     414        if (symKey)
     415                PK11_FreeSymKey(symKey);
     416        if (secParam)
     417                SECITEM_FreeItem(secParam, PR_TRUE);
     418        if (slot)
     419                PK11_FreeSlot(slot);
     420
     421        return rc;
     422}
Note: See TracChangeset for help on using the changeset viewer.