source: branches/encryption/libtransmission/handshake.c @ 2936

Last change on this file since 2936 was 2936, checked in by charles, 15 years ago

not ready for use yet -- this is a periodic checkin so I don't lose my changes. Outgoing connections work for plaintext, encrypted, and encrypted connections that prefer plaintext. Incoming connections don't work yet. Handshakes aren't wired in to the rest of the peer code yet.

  • Property svn:keywords set to Date Rev Author Id
File size: 25.3 KB
Line 
1/*
2 * This file Copyright (C) 2007 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id:$
11 */
12
13#include <assert.h>
14#include <inttypes.h>
15#include <limits.h> /* UCHAR_MAX */
16#include <string.h>
17#include <arpa/inet.h>
18
19#include <openssl/bn.h>
20#include <openssl/dh.h>
21//#include <openssl/rc4.h>
22//#include <openssl/sha.h>
23
24#include <event.h>
25
26#include "transmission.h"
27#include "encryption.h"
28#include "handshake.h"
29#include "peer-connection.h"
30#include "utils.h"
31
32/***
33****
34***/
35
36#define HANDSHAKE_NAME          "\023BitTorrent protocol"
37#define HANDSHAKE_NAME_LEN      20
38#define HANDSHAKE_FLAGS_LEN     8
39#define HANDSHAKE_SIZE          68
40
41/* these macros test and set the bit indicating extended messaging support */
42#ifdef DISABLE_EXTMSGS
43#define HANDSHAKE_HAS_EXTMSGS( bits ) ( 0 )
44#define HANDSHAKE_SET_EXTMSGS( bits ) ( (void)0 )
45#else
46#define HANDSHAKE_HAS_EXTMSGS( bits ) ( (bits)[5] & 0x10 )
47#define HANDSHAKE_SET_EXTMSGS( bits ) ( (bits)[5] |= 0x10 )
48#endif
49
50/* these macros test and set the bit indicating azureus protocol support */
51#ifdef DISABLE_AZPROTO
52#define HANDSHAKE_HAS_AZPROTO( bits ) ( 0 )
53#define HANDSHAKE_SET_AZPROTO( bits ) ( (void)0 )
54#else
55#define HANDSHAKE_HAS_AZPROTO( bits ) ( (bits)[0] & 0x80 )
56#define HANDSHAKE_SET_AZPROTO( bits ) ( (bits)[0] |= 0x80 )
57#endif
58
59/* http://www.azureuswiki.com/index.php/Extension_negotiation_protocol
60   these macros are to be used if both extended messaging and the
61   azureus protocol is supported, they indicate which protocol is preferred */
62#define HANDSHAKE_GET_EXTPREF( reserved )      ( (reserved)[5] & 0x03 )
63#define HANDSHAKE_SET_EXTPREF( reserved, val ) ( (reserved)[5] |= 0x03 & (val) )
64#define HANDSHAKE_EXTPREF_LTEP_FORCE   ( 0x0 )
65#define HANDSHAKE_EXTPREF_LTEP_PREFER  ( 0x1 )
66#define HANDSHAKE_EXTPREF_AZMP_PREFER  ( 0x2 )
67#define HANDSHAKE_EXTPREF_AZMP_FORCE   ( 0x3 )
68
69extern const char* getPeerId( void ) ;
70
71
72#define KEY_LEN 96
73#define PRIME_LEN 96
74#define VC_LENGTH 8
75
76
77typedef struct tr_handshake
78{
79    tr_peerConnection * connection;
80    tr_encryption * encryption;
81    struct tr_handle * handle;
82    uint8_t myPublicKey[96];
83    uint8_t mySecret[96];
84    uint8_t state;
85    uint8_t encryptionPreference;
86    uint8_t * resync;
87    uint16_t PadC_len;
88    uint16_t PadD_len;
89    uint8_t pad_b_buf[512 + 8];
90    int     pad_b_len;
91    int ia_len;
92    int resync_len;
93    int pad_d_len;
94    int crypto_select;
95    DH * dh;
96    uint8_t myReq1[SHA_DIGEST_LENGTH];
97    handshakeDoneCB doneCB;
98    void * doneUserData;
99}
100tr_handshake;
101
102static void
103fireDoneCB( tr_handshake * handshake, int isConnected );
104
105/**
106***
107**/
108
109enum /*ccc*/
110{
111    /* incoming */
112    AWAITING_HANDSHAKE,
113    AWAITING_YA,
114    SENDING_YB,
115    AWAITING_PAD_A,
116    AWAITING_CRYPTO_PROVIDE,
117    AWAITING_PAD_C,
118    AWAITING_IA,
119
120    /* outgoing */
121    SENDING_YA,
122    AWAITING_YB,
123    SENDING_CRYPTO_PROVIDE,
124    AWAITING_VC,
125    AWAITING_CRYPTO_SELECT,
126    AWAITING_PAD_D,
127    //AWAITING_PLAINTEXT_RESPONSE,
128   
129    SENDING_PLAINTEXT_HANDSHAKE
130};
131
132/**
133***
134**/
135
136static const char* getStateName( short state )
137{
138    const char * str = "f00!";
139    switch( state ) {
140        case AWAITING_HANDSHAKE:      str = "awaiting handshake"; break;
141        case AWAITING_YA:             str = "awaiting ya"; break;
142        case SENDING_YB:              str = "sending yb"; break;
143        case AWAITING_PAD_A:          str = "awaiting pad a"; break;
144        case AWAITING_CRYPTO_PROVIDE: str = "awaiting crypto_provide"; break;
145        case AWAITING_PAD_C:          str = "awaiting pad c"; break;
146        case AWAITING_IA:             str = "awaiting ia"; break;
147        case SENDING_YA:              str = "sending ya"; break;
148        case AWAITING_YB:             str = "awaiting yb"; break;
149        case SENDING_CRYPTO_PROVIDE:  str = "sending crypto provide"; break;
150        case AWAITING_VC:             str = "awaiting vc"; break;
151        case AWAITING_CRYPTO_SELECT:  str = "awaiting crypto select"; break;
152        case AWAITING_PAD_D:          str = "awaiting pad d"; break;
153        case SENDING_PLAINTEXT_HANDSHAKE: str = "sending plaintext handshake"; break;
154    }
155    return str;
156}
157
158static void
159setState( tr_handshake * handshake, short state )
160{
161    fprintf( stderr, "setting handshake %p to state [%s]\n", handshake, getStateName(state) );
162    handshake->state = state;
163}
164
165static void
166setReadState( tr_handshake * handshake, int state )
167{
168    setState( handshake, state );
169    tr_peerConnectionSetIOMode( handshake->connection, EV_READ );
170}
171
172static void
173sendPublicKey( tr_handshake * handshake )
174{
175    int i;
176    int len;
177    const uint8_t * public_key;
178    struct evbuffer * outbuf = evbuffer_new( );
179    uint8_t pad[512];
180
181    /* add our public key (Ya) */
182    public_key = tr_encryptionGetMyPublicKey( handshake->encryption, &len );
183    assert( len == KEY_LEN );
184    assert( public_key != NULL );
185    evbuffer_add( outbuf, public_key, len );
186
187    /* add some bullshit padding */
188    len = tr_rand( 512 );
189    for( i=0; i<len; ++i )
190        pad[i] = tr_rand( UCHAR_MAX );
191    evbuffer_add( outbuf, pad, len );
192
193    /* send it */
194    setState( handshake, SENDING_YA );
195    tr_peerConnectionWriteBuf( handshake->connection, outbuf );
196
197    /* cleanup */
198    evbuffer_free( outbuf );
199}
200
201static void
202buildHandshakeMessage( tr_handshake * handshake, uint8_t * buf )
203{
204    uint8_t *walk = buf;
205    const uint8_t * torrentHash = tr_encryptionGetTorrentHash( handshake->encryption );
206
207    memcpy( walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
208    walk += HANDSHAKE_NAME_LEN;
209    memset( walk, 0, HANDSHAKE_FLAGS_LEN );
210    HANDSHAKE_SET_EXTMSGS( walk );
211    HANDSHAKE_SET_AZPROTO( walk );
212    HANDSHAKE_SET_EXTPREF( walk, HANDSHAKE_EXTPREF_LTEP_PREFER );
213    walk += HANDSHAKE_FLAGS_LEN;
214    memcpy( walk, torrentHash, SHA_DIGEST_LENGTH );
215    walk += SHA_DIGEST_LENGTH;
216    memcpy( walk, getPeerId(), TR_ID_LEN );
217    walk += TR_ID_LEN;
218    assert( walk-buf == HANDSHAKE_SIZE );
219}
220
221static void
222sendPlaintextHandshake( tr_handshake * handshake )
223{
224    uint8_t buf[HANDSHAKE_SIZE];
225    buildHandshakeMessage( handshake, buf );
226    setState( handshake, SENDING_PLAINTEXT_HANDSHAKE );
227    tr_peerConnectionWrite( handshake->connection, buf, HANDSHAKE_SIZE );
228}
229
230static void
231sendHandshake( tr_handshake * handshake )
232{
233    if( ( handshake->encryptionPreference == HANDSHAKE_ENCRYPTION_PREFERRED ) ||
234        ( handshake->encryptionPreference == HANDSHAKE_ENCRYPTION_REQUIRED ) )
235    {
236        sendPublicKey( handshake );
237    }
238    else
239    {
240        sendPlaintextHandshake( handshake );
241    }
242}
243
244/**
245***
246**/
247
248static int
249readYa( tr_handshake * handshake, struct evbuffer  * inbuf )
250{
251    uint8_t ya[KEY_LEN];
252    uint8_t *walk, outbuf[KEY_LEN + 512];
253    const uint8_t *myKey, *secret;
254    int len;
255
256    if( EVBUFFER_LENGTH( inbuf ) < KEY_LEN )
257        return READ_MORE;
258
259    /* read the incoming peer's public key */
260    evbuffer_remove( inbuf, ya, KEY_LEN );
261    secret = tr_encryptionComputeSecret( handshake->encryption, ya );
262    memcpy( handshake->mySecret, secret, KEY_LEN );
263    tr_sha1( handshake->myReq1, "req1", 4, secret, KEY_LEN, NULL );
264
265    /* send our public key to the peer */
266    walk = outbuf;
267    myKey = tr_encryptionGetMyPublicKey( handshake->encryption, &len );
268    memcpy( walk, myKey, len );
269    len = tr_rand( 512 );
270    while( len-- )
271        *walk++ = tr_rand( UCHAR_MAX );
272    setState( handshake, SENDING_YB );
273    tr_peerConnectionWrite( handshake->connection, outbuf, walk-outbuf );
274
275    return READ_DONE;
276}
277
278static int
279readPadA( tr_handshake * handshake, struct evbuffer * inbuf )
280{
281    uint8_t * pch;
282
283    /**
284    *** Resynchronizing on HASH('req1',S)
285    **/
286
287    pch = memchr( EVBUFFER_DATA(inbuf),
288                  handshake->myReq1[0],
289                  EVBUFFER_LENGTH(inbuf) );
290    if( pch == NULL ) {
291        evbuffer_drain( inbuf, EVBUFFER_LENGTH(inbuf) );
292        return READ_MORE;
293    }
294    evbuffer_drain( inbuf, pch-EVBUFFER_DATA(inbuf) );
295    if( EVBUFFER_LENGTH(inbuf) < SHA_DIGEST_LENGTH )
296        return READ_MORE;
297    if( memcmp( EVBUFFER_DATA(inbuf), handshake->myReq1, SHA_DIGEST_LENGTH ) ) {
298        evbuffer_drain( inbuf, 1 );
299        return READ_AGAIN;
300    }
301
302    setState( handshake, AWAITING_CRYPTO_PROVIDE );
303    return READ_AGAIN;
304}
305
306static int
307readCryptoProvide( tr_handshake * handshake, struct evbuffer * inbuf )
308{
309    /* HASH('req2', SKEY) xor HASH('req3', S), ENCRYPT(VC, crypto_provide, len(PadC)) */
310
311    int i;
312    uint8_t vc_in[VC_LENGTH];
313    uint8_t req2[SHA_DIGEST_LENGTH];
314    uint8_t req3[SHA_DIGEST_LENGTH];
315    uint8_t obfuscatedTorrentHash[SHA_DIGEST_LENGTH];
316    uint16_t padc_len = 0;
317    uint32_t crypto_provide = 0;
318    const size_t needlen = SHA_DIGEST_LENGTH + VC_LENGTH + sizeof(crypto_provide) + sizeof(padc_len);
319    tr_torrent * tor = NULL;
320
321    if( EVBUFFER_LENGTH(inbuf) < needlen )
322        return READ_MORE;
323
324    /* TODO: confirm they sent HASH('req1',S) here? */
325    evbuffer_drain( inbuf, SHA_DIGEST_LENGTH );
326
327    /* This next piece is HASH('req2', SKEY) xor HASH('req3', S) ...
328     * we can get the first half of that (the obufscatedTorrentHash)
329     * by building the latter and xor'ing it with what the peer sent us */
330    fprintf( stderr, "reading obfuscated torrent hash...\n" );
331    evbuffer_remove( inbuf, req2, SHA_DIGEST_LENGTH );
332    tr_sha1( req3, "req3", 4, handshake->mySecret, KEY_LEN, NULL );
333    for( i=0; i<SHA_DIGEST_LENGTH; ++i )
334        obfuscatedTorrentHash[i] = req2[i] ^ req3[i];
335    tor = tr_torrentFindFromObfuscatedHash( handshake->handle, obfuscatedTorrentHash );
336    assert( tor != NULL );
337    fprintf( stderr, "found the torrent; it's [%s]\n", tor->info.name );
338    tr_peerConnectionSetTorrent( handshake->connection, tor );
339
340    /* next part: ENCRYPT(VC, crypto_provide, len(PadC), */
341
342    tr_encryptionDecryptInit( handshake->encryption );
343
344    evbuffer_remove( inbuf, vc_in, VC_LENGTH );
345    tr_encryptionDecrypt( handshake->encryption, VC_LENGTH, vc_in, vc_in );
346    fprintf( stderr, "read vc -> %d %d %d %d %d %d %d %d\n",
347        (int)vc_in[0], (int)vc_in[1], (int)vc_in[2], (int)vc_in[3],
348        (int)vc_in[4], (int)vc_in[5], (int)vc_in[6], (int)vc_in[7] );
349
350    evbuffer_remove( inbuf, &crypto_provide, sizeof(crypto_provide) );
351    tr_encryptionDecrypt( handshake->encryption, sizeof(crypto_provide),
352                          &crypto_provide, &crypto_provide );
353    crypto_provide = ntohl( crypto_provide );
354    fprintf( stderr, "crypto_provide is %d\n", (int)crypto_provide );
355
356    evbuffer_remove( inbuf, &padc_len, sizeof(padc_len) );
357    tr_encryptionDecrypt( handshake->encryption, sizeof(padc_len), &padc_len, &padc_len );
358    padc_len = ntohs( padc_len );
359    fprintf( stderr, "padc is %d\n", (int)padc_len );
360    handshake->PadC_len = padc_len;
361    setState( handshake, AWAITING_PAD_C );
362    return READ_AGAIN;
363}
364
365static int
366readPadC( tr_handshake * handshake, struct evbuffer * inbuf )
367{
368    uint16_t ia_len;
369    const size_t needlen = handshake->PadC_len + sizeof(uint16_t);
370
371    if( EVBUFFER_LENGTH(inbuf) < needlen )
372        return READ_MORE;
373
374    evbuffer_drain( inbuf, needlen );
375
376    evbuffer_remove( inbuf, &ia_len, sizeof(ia_len) );
377    ia_len = ntohs( ia_len );
378    fprintf( stderr, "ia_len is %d\n", (int)ia_len );
379    handshake->ia_len = ia_len;
380    setState( handshake, AWAITING_IA );
381    return READ_AGAIN;
382}
383
384static int
385readIA( tr_handshake * handshake, struct evbuffer * inbuf )
386{
387    const size_t needlen = handshake->ia_len;
388    uint8_t * ia;
389
390    if( EVBUFFER_LENGTH(inbuf) < needlen )
391        return READ_MORE;
392
393    ia = tr_new( uint8_t, handshake->ia_len );
394    evbuffer_remove( inbuf, ia, handshake->ia_len );
395    tr_encryptionDecrypt( handshake->encryption, handshake->ia_len, ia, ia );
396    fprintf( stderr, "got their payload ia: [%*.*s]\n", (int)needlen, (int)needlen, ia );
397
398    handshake->state = -1;
399    abort( );
400}
401
402/**
403***
404**/
405
406static int
407readYb( tr_handshake * handshake, struct evbuffer * inbuf )
408{
409    int isEncrypted;
410    const uint8_t * secret;
411    const size_t needlen = KEY_LEN;
412    uint8_t yb[KEY_LEN];
413    struct evbuffer * outbuf;
414
415    if( EVBUFFER_LENGTH(inbuf) < needlen )
416        return READ_MORE;
417
418    isEncrypted = memcmp( EVBUFFER_DATA(inbuf), HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
419    fprintf( stderr, "got a %s handshake\n", (isEncrypted ? "encrypted" : "plaintext") );
420    if( !isEncrypted ) {
421        setState( handshake, AWAITING_HANDSHAKE );
422        return READ_AGAIN;
423    }
424
425    /* compute the secret */
426    evbuffer_remove( inbuf, yb, KEY_LEN );
427    secret = tr_encryptionComputeSecret( handshake->encryption, yb );
428    memcpy( handshake->mySecret, secret, KEY_LEN );
429
430    /* now send these: HASH('req1', S), HASH('req2', SKEY) xor HASH('req3', S),
431     * ENCRYPT(VC, crypto_provide, len(PadC), PadC, len(IA)), ENCRYPT(IA) */
432    outbuf = evbuffer_new( );
433
434    /* HASH('req1', S) */
435    {
436        uint8_t req1[SHA_DIGEST_LENGTH];
437        tr_sha1( req1, "req1", 4, secret, KEY_LEN, NULL );
438        evbuffer_add( outbuf, req1, SHA_DIGEST_LENGTH );
439    }
440
441    /* HASH('req2', SKEY) xor HASH('req3', S) */
442    {
443        int i;
444        uint8_t req2[SHA_DIGEST_LENGTH];
445        uint8_t req3[SHA_DIGEST_LENGTH];
446        uint8_t buf[SHA_DIGEST_LENGTH];
447        tr_sha1( req2, "req2", 4, tr_encryptionGetTorrentHash(handshake->encryption), SHA_DIGEST_LENGTH, NULL );
448        tr_sha1( req3, "req3", 4, secret, KEY_LEN, NULL );
449        for( i=0; i<SHA_DIGEST_LENGTH; ++i )
450            buf[i] = req2[i] ^ req3[i];
451        evbuffer_add( outbuf, buf, SHA_DIGEST_LENGTH );
452    }
453     
454    /* ENCRYPT(VC, crypto_provide, len(PadC), PadC */
455    {
456        uint8_t vc[VC_LENGTH] = { 0, 0, 0, 0, 0, 0, 0, 0 };
457        uint8_t pad[512];
458        uint16_t i, len;
459        uint32_t crypto_provide;
460
461        tr_encryptionEncryptInit( handshake->encryption );
462       
463        /* vc */ 
464        tr_encryptionEncrypt( handshake->encryption, VC_LENGTH, vc, vc );
465        evbuffer_add( outbuf, vc, VC_LENGTH );
466
467        /* crypto_provide */
468        crypto_provide = 0;
469        if( handshake->encryptionPreference != HANDSHAKE_PLAINTEXT_REQUIRED )
470            crypto_provide |= (1<<0);
471        if( handshake->encryptionPreference != HANDSHAKE_ENCRYPTION_REQUIRED )
472            crypto_provide |= (1<<1);
473        assert( 1<=crypto_provide && crypto_provide<=3 );
474        crypto_provide = htonl( crypto_provide );
475        tr_encryptionEncrypt( handshake->encryption, sizeof(crypto_provide), &crypto_provide, &crypto_provide );
476fprintf( stderr, "crypto_provide is [%d]\n", crypto_provide );
477        evbuffer_add( outbuf, &crypto_provide, sizeof(crypto_provide) );
478
479        /* len(padc) */
480        i = len = tr_rand( 512 );
481        i = htons( i );
482        tr_encryptionEncrypt( handshake->encryption, sizeof(i), &i, &i );
483        evbuffer_add( outbuf, &i, sizeof(i) );
484
485        /* padc */
486        for( i=0; i<len; ++i ) pad[i] = tr_rand( UCHAR_MAX );
487        evbuffer_add( outbuf, pad, len );
488    }
489
490    /* ENCRYPT len(IA)), ENCRYPT(IA) */
491    {
492        uint16_t i;
493        uint8_t msg[HANDSHAKE_SIZE];
494        buildHandshakeMessage( handshake, msg );
495
496        i = htons( HANDSHAKE_SIZE );
497        tr_encryptionEncrypt( handshake->encryption, sizeof(uint16_t), &i, &i );
498        evbuffer_add( outbuf, &i, sizeof(uint16_t) );
499
500        tr_encryptionEncrypt( handshake->encryption, HANDSHAKE_SIZE, msg, msg );
501        evbuffer_add( outbuf, msg, HANDSHAKE_SIZE );
502    }
503
504    /* send it */
505    tr_encryptionDecryptInit( handshake->encryption );
506    setState( handshake, SENDING_CRYPTO_PROVIDE );
507    tr_peerConnectionWriteBuf( handshake->connection, outbuf );
508
509    /* cleanup */
510    evbuffer_free( outbuf );
511    return READ_DONE;
512}
513
514static int
515readVC( tr_handshake * handshake, struct evbuffer * inbuf )
516{
517    const uint8_t key[VC_LENGTH] = { 0, 0, 0, 0, 0, 0, 0, 0 };
518    const int key_len = VC_LENGTH;
519    uint8_t tmp[VC_LENGTH];
520
521    /* note: this works w/o having to `unwind' the buffer if
522     * we read too much, but it is pretty brute-force.
523     * it would be nice to make this cleaner. */
524    for( ;; )
525    {
526        if( EVBUFFER_LENGTH(inbuf) < VC_LENGTH )
527            return READ_MORE;
528
529        memcpy( tmp, EVBUFFER_DATA(inbuf), key_len );
530        tr_encryptionDecryptInit( handshake->encryption );
531        tr_encryptionDecrypt( handshake->encryption, key_len, tmp, tmp );
532        if( !memcmp( tmp, key, key_len ) )
533            break;
534
535        evbuffer_drain( inbuf, 1 );
536    }
537
538    evbuffer_drain( inbuf, key_len );
539    setState( handshake, AWAITING_CRYPTO_SELECT );
540    return READ_AGAIN;
541}
542
543//ccc
544static int
545readCryptoSelect( tr_handshake * handshake, struct evbuffer * inbuf )
546{
547    uint32_t crypto_select;
548    uint16_t pad_d_len;
549    const size_t needlen = sizeof(uint32_t) + sizeof(uint16_t);
550
551    if( EVBUFFER_LENGTH(inbuf) < needlen )
552        return READ_MORE;
553
554 //   tr_encryptionDecryptInit( handshake->encryption );
555
556    evbuffer_remove( inbuf, &crypto_select, sizeof(uint32_t) );
557    tr_encryptionDecrypt( handshake->encryption, sizeof(uint32_t), &crypto_select, &crypto_select );
558    fprintf( stderr, "crypto select 1 is %d\n", crypto_select );
559    crypto_select = ntohl( crypto_select );
560    handshake->crypto_select = crypto_select;
561    assert( crypto_select==1 || crypto_select==2 );
562    fprintf( stderr, "crypto select 2 is %d\n", crypto_select );
563
564    evbuffer_remove( inbuf, &pad_d_len, sizeof(uint16_t) );
565    tr_encryptionDecrypt( handshake->encryption, sizeof(uint16_t), &pad_d_len, &pad_d_len );
566    pad_d_len = ntohs( pad_d_len );
567    fprintf( stderr, "pad_d_len is %d\n", (int)pad_d_len );
568    assert( pad_d_len <= 512 );
569    handshake->pad_d_len = pad_d_len;
570
571    setState( handshake, AWAITING_PAD_D );
572    return READ_AGAIN;
573}
574
575static int
576readPadD( tr_handshake * handshake, struct evbuffer * inbuf )
577{
578    const size_t needlen = handshake->pad_d_len;
579    uint8_t * buf;
580
581fprintf( stderr, "pad d: need %d, got %d\n", (int)needlen, (int)EVBUFFER_LENGTH(inbuf) );
582    if( EVBUFFER_LENGTH(inbuf) < needlen )
583        return READ_MORE;
584
585    buf = tr_new( uint8_t, needlen );
586    evbuffer_remove( inbuf, buf, needlen );
587    tr_encryptionDecrypt( handshake->encryption, needlen, buf, buf );
588    tr_free( buf );
589
590    setState( handshake, AWAITING_HANDSHAKE );
591    return READ_AGAIN;
592}
593
594/*ccc*/
595static int
596readHandshake( tr_handshake * handshake, struct evbuffer * inbuf )
597{
598    int i;
599    int ltep = 0;
600    int azmp = 0;
601    int encrypted;
602    uint8_t pstrlen;
603    uint8_t * pstr;
604    uint8_t reserved[8];
605    uint8_t hash[SHA_DIGEST_LENGTH];
606    uint8_t peer_id[20];
607
608fprintf( stderr, "handshake payload: need %d, got %d\n", (int)HANDSHAKE_SIZE, (int)EVBUFFER_LENGTH(inbuf) );
609
610    if( EVBUFFER_LENGTH(inbuf) < HANDSHAKE_SIZE )
611        return READ_MORE;
612
613    /* pstrlen */
614    evbuffer_remove( inbuf, &pstrlen, 1 );
615    fprintf( stderr, "pstrlen 1 is %d [%c]\n", (int)pstrlen, pstrlen );
616    encrypted = pstrlen != 19;
617    if( encrypted ) {
618        fprintf( stderr, "clearly it's encrypted...\n" );
619        //tr_encryptionDecryptInit( handshake->encryption );
620        tr_encryptionDecrypt( handshake->encryption, 1, &pstrlen, &pstrlen );
621    }
622    fprintf( stderr, "pstrlen is %d [%c]\n", (int)pstrlen, pstrlen );
623    //assert( pstrlen == 19 );
624
625    /* pstr (BitTorrent) */
626    pstr = tr_new( uint8_t, pstrlen+1 );
627    evbuffer_remove( inbuf, pstr, pstrlen );
628    if( encrypted )
629        tr_encryptionDecrypt( handshake->encryption, pstrlen, pstr, pstr );
630    pstr[pstrlen] = '\0';
631    fprintf( stderr, "pstrlen is [%s]\n", pstr );
632    assert( !strcmp( (char*)pstr, "BitTorrent protocol" ) );
633
634    /* reserved bytes */
635    evbuffer_remove( inbuf, reserved, sizeof(reserved) );
636    if( encrypted )
637        tr_encryptionDecrypt( handshake->encryption, sizeof(reserved), reserved, reserved );
638
639    /* torrent hash */
640    evbuffer_remove( inbuf, hash, sizeof(hash) );
641    if( encrypted )
642        tr_encryptionDecrypt( handshake->encryption, sizeof(hash), hash, hash );
643    assert( !memcmp( hash, tr_peerConnectionGetTorrent(handshake->connection)->info.hash, SHA_DIGEST_LENGTH ) );
644
645
646    /* peer id */
647    evbuffer_remove( inbuf, peer_id, sizeof(peer_id) );
648    if( encrypted )
649        tr_encryptionDecrypt( handshake->encryption, sizeof(peer_id), peer_id, peer_id );
650    fprintf( stderr, "peer_id: " );
651    for( i=0; i<20; ++i ) fprintf( stderr, "[%c]", peer_id[i] );
652    fprintf( stderr, "\n" );
653    tr_peerConnectionSetPeersId( handshake->connection, peer_id );
654
655    /**
656    ***
657    **/
658
659    ltep = HANDSHAKE_HAS_EXTMSGS( reserved ) ? 1 : 0;
660    azmp = HANDSHAKE_HAS_AZPROTO( reserved ) ? 1 : 0;
661    if( ltep && azmp ) {
662        switch( HANDSHAKE_GET_EXTPREF( reserved ) ) {
663            case HANDSHAKE_EXTPREF_LTEP_FORCE:
664            case HANDSHAKE_EXTPREF_LTEP_PREFER:
665                azmp = 0;
666                break;
667            case HANDSHAKE_EXTPREF_AZMP_FORCE:
668            case HANDSHAKE_EXTPREF_AZMP_PREFER:
669                ltep = 0;
670                break;
671        }
672    }
673    assert( !ltep || !azmp );
674         if( ltep ) { i = LT_EXTENSIONS_LTEP; fprintf(stderr,"using ltep\n" ); }
675    else if( azmp ) { i = LT_EXTENSIONS_AZMP; fprintf(stderr,"using azmp\n" ); }
676    else            { i = LT_EXTENSIONS_NONE; fprintf(stderr,"using no extensions\n" ); }
677    tr_peerConnectionSetExtension( handshake->connection, i );
678
679
680    if( !tr_peerConnectionIsIncoming( handshake->connection ) && ( i != LT_EXTENSIONS_AZMP ) ) {
681        fireDoneCB( handshake, TRUE );
682        return READ_DONE;
683    }
684
685   
686    assert( 0 && "FIXME" );
687    return 0;
688}
689
690/**
691***
692**/
693
694static ReadState
695canRead( struct bufferevent * evin, void * arg )
696{
697    tr_handshake * handshake = (tr_handshake *) arg;
698    struct evbuffer * inbuf = EVBUFFER_INPUT ( evin );
699    ReadState ret;
700    fprintf( stderr, "handling canRead; state is [%s]\n", getStateName(handshake->state) );
701
702    switch( handshake->state )
703    {
704        case AWAITING_HANDSHAKE:       ret = readHandshake    ( handshake, inbuf ); break;
705        case AWAITING_YA:              ret = readYa           ( handshake, inbuf ); break;
706        case AWAITING_PAD_A:           ret = readPadA         ( handshake, inbuf ); break;
707        case AWAITING_CRYPTO_PROVIDE:  ret = readCryptoProvide( handshake, inbuf ); break;
708        case AWAITING_PAD_C:           ret = readPadC         ( handshake, inbuf ); break;
709        case AWAITING_IA:              ret = readIA           ( handshake, inbuf ); break;
710
711        case AWAITING_YB:              ret = readYb           ( handshake, inbuf ); break;
712        case AWAITING_VC:              ret = readVC           ( handshake, inbuf ); break;
713        case AWAITING_CRYPTO_SELECT:   ret = readCryptoSelect ( handshake, inbuf ); break;
714        case AWAITING_PAD_D:           ret = readPadD         ( handshake, inbuf ); break;
715
716        default: assert( 0 );
717    }
718
719    return ret;
720}
721
722static void
723didWrite( struct bufferevent * evin UNUSED, void * arg )
724{
725    tr_handshake * handshake = (tr_handshake *) arg;
726    int state = -1;
727
728fprintf( stderr, "handshake %p got a didWrite event\n", handshake );
729
730    switch( handshake->state )
731    {
732        case SENDING_YA:                   state = AWAITING_YB; break;
733        case SENDING_YB:                   state = AWAITING_PAD_A; break;
734        case SENDING_CRYPTO_PROVIDE:       state = AWAITING_VC; break;
735    }
736
737    assert( state != -1 );
738    setState( handshake, state );
739    tr_peerConnectionReadOrWait( handshake->connection );
740}
741
742static void
743tr_handshakeFree( tr_handshake * handshake )
744{
745    /* FIXME */
746    tr_free( handshake );
747}
748
749static void
750fireDoneCB( tr_handshake * handshake, int isConnected )
751{
752    (*handshake->doneCB)(handshake->connection, isConnected, handshake->doneUserData);
753    tr_handshakeFree( handshake );
754}
755
756static void
757gotError( struct bufferevent * evbuf UNUSED, short what UNUSED, void * arg )
758{
759    tr_handshake * handshake = (tr_handshake *) arg;
760
761
762    /* if the error happened while we were sending a public key, we might
763     * have encountered a peer that doesn't do encryption... reconnect and
764     * try a plaintext handshake */
765    if(    ( handshake->state == SENDING_YA )
766        && ( handshake->encryptionPreference != HANDSHAKE_ENCRYPTION_REQUIRED )
767        && ( !tr_peerConnectionReconnect( handshake->connection ) ) )
768    {
769        handshake->encryptionPreference = HANDSHAKE_PLAINTEXT_REQUIRED;
770        sendPlaintextHandshake( handshake );
771    }
772    else fireDoneCB( handshake, FALSE );
773}
774
775/**
776***
777**/
778
779static tr_handshake*
780tr_handshakeNew( tr_peerConnection  * connection,
781                 int                  encryptionPreference,
782                 handshakeDoneCB      doneCB,
783                 void               * doneUserData )
784{
785    tr_handshake * handshake;
786
787static int count = 0;
788if( count++ ) return NULL;
789
790    handshake = tr_new0( tr_handshake, 1 );
791    handshake->connection = connection;
792    handshake->encryption = tr_peerConnectionGetEncryption( connection );
793    handshake->encryptionPreference = encryptionPreference;
794    handshake->doneCB = doneCB;
795    handshake->doneUserData = doneUserData;
796
797    tr_peerConnectionSetIOFuncs( connection, canRead, didWrite, gotError, handshake );
798
799    if( tr_peerConnectionIsIncoming( connection ) )
800    {
801        setReadState( handshake, AWAITING_HANDSHAKE );
802    }
803    else
804    {
805        sendHandshake( handshake );
806    }
807
808    return handshake;
809}
810
811void
812tr_handshakeAdd( struct tr_peerConnection * connection,
813                 int                        encryptionPreference,
814                 handshakeDoneCB            doneCB,   
815                 void                     * doneUserData )
816{
817    tr_handshakeNew( connection, encryptionPreference, doneCB, doneUserData );
818}
Note: See TracBrowser for help on using the repository browser.