2014-11-08 09:55:29 -05:00
/*
* libretroshare / src / chat : distantchat . cc
*
* Services for RetroShare .
*
* Copyright 2014 by Cyril Soler
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License Version 2 as published by the Free Software Foundation .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
* USA .
*
* Please report all bugs and problems to " csoler@users.sourceforge.net " .
*
*/
2014-11-08 12:57:21 -05:00
# include <unistd.h>
2014-11-08 09:55:29 -05:00
# include "openssl/rand.h"
# include "openssl/dh.h"
# include "openssl/err.h"
# include "util/rsaes.h"
# include <serialiser/rsmsgitems.h>
# include <retroshare/rsmsgs.h>
# include <retroshare/rsidentity.h>
# include <retroshare/rsiface.h>
# include <rsserver/p3face.h>
# include <services/p3idservice.h>
# include <gxs/gxssecurity.h>
# include <turtle/p3turtle.h>
# include <retroshare/rsids.h>
# include "distantchat.h"
2015-02-14 15:55:05 -05:00
# define DEBUG_DISTANT_CHAT
2014-12-07 16:51:30 -05:00
static const uint32_t DISTANT_CHAT_KEEP_ALIVE_TIMEOUT = 15 ; // send keep alive packet so as to avoid tunnel breaks.
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
static const uint32_t RS_DISTANT_CHAT_DH_STATUS_UNINITIALIZED = 0x0000 ;
static const uint32_t RS_DISTANT_CHAT_DH_STATUS_HALF_KEY_DONE = 0x0001 ;
static const uint32_t RS_DISTANT_CHAT_DH_STATUS_KEY_AVAILABLE = 0x0002 ;
2014-11-08 09:55:29 -05:00
void DistantChatService : : connectToTurtleRouter ( p3turtle * tr )
{
mTurtle = tr ;
tr - > registerTunnelService ( this ) ;
}
void DistantChatService : : flush ( )
{
2014-12-07 16:51:30 -05:00
// Flush items that could not be sent, probably because of a Mutex protected zone.
//
while ( ! pendingDistantChatItems . empty ( ) )
2014-11-22 07:47:21 -05:00
{
sendTurtleData ( pendingDistantChatItems . front ( ) ) ;
pendingDistantChatItems . pop_front ( ) ;
2014-11-20 18:18:14 -05:00
}
// TODO: also sweep GXS id map and disable any ID with no virtual peer id in the list.
2014-12-07 16:51:30 -05:00
RS_STACK_MUTEX ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
time_t now = time ( NULL ) ;
for ( std : : map < RsGxsId , DistantChatPeerInfo > : : iterator it ( _distant_chat_contacts . begin ( ) ) ; it ! = _distant_chat_contacts . end ( ) ; + + it )
{
if ( it - > second . last_contact + 10 + DISTANT_CHAT_KEEP_ALIVE_TIMEOUT < now & & it - > second . status = = RS_DISTANT_CHAT_STATUS_CAN_TALK )
{
std : : cerr < < " (II) DistantChatService:: connexion interrupted with peer. " < < std : : endl ;
it - > second . status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ;
it - > second . virtual_peer_id . clear ( ) ;
}
if ( it - > second . last_keep_alive_sent + DISTANT_CHAT_KEEP_ALIVE_TIMEOUT < now & & it - > second . status = = RS_DISTANT_CHAT_STATUS_CAN_TALK )
{
RsChatStatusItem * cs = new RsChatStatusItem ;
cs - > status_string . clear ( ) ;
cs - > flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_KEEP_ALIVE ;
cs - > PeerId ( RsPeerId ( it - > first ) ) ;
// we send off-mutex to avoid deadlock.
pendingDistantChatItems . push_back ( cs ) ;
it - > second . last_keep_alive_sent = now ;
std : : cerr < < " (II) DistantChatService:: Sending keep alive packet to gxs id " < < it - > first < < std : : endl ;
}
}
2014-11-08 09:55:29 -05:00
}
bool DistantChatService : : handleRecvItem ( RsChatItem * item )
{
2014-12-07 16:51:30 -05:00
if ( item = = NULL )
return false ;
2014-11-08 09:55:29 -05:00
2014-12-07 16:51:30 -05:00
switch ( item - > PacketSubType ( ) )
2014-11-22 07:47:21 -05:00
{
case RS_PKT_SUBTYPE_DISTANT_CHAT_DH_PUBLIC_KEY : handleRecvDHPublicKey ( dynamic_cast < RsChatDHPublicKeyItem * > ( item ) ) ; break ;
return true ;
2014-11-08 09:55:29 -05:00
2014-12-07 16:51:30 -05:00
case RS_PKT_SUBTYPE_CHAT_STATUS :
{
// Keep alive packets should not be forwarded to the GUI. It's just for keeping the tunnel up.
RsChatStatusItem * csi = dynamic_cast < RsChatStatusItem * > ( item ) ;
if ( csi ! = NULL & & csi - > flags & RS_CHAT_FLAG_KEEP_ALIVE )
return true ;
}
2014-11-22 07:47:21 -05:00
default :
return false ;
}
2014-11-08 09:55:29 -05:00
2014-12-07 16:51:30 -05:00
return false ;
2014-11-08 09:55:29 -05:00
}
bool DistantChatService : : handleOutgoingItem ( RsChatItem * item )
{
2014-12-07 16:51:30 -05:00
{
RS_STACK_MUTEX ( mDistantChatMtx ) ;
2014-11-20 18:18:14 -05:00
2014-12-07 16:51:30 -05:00
std : : map < RsGxsId , DistantChatPeerInfo > : : const_iterator it = _distant_chat_contacts . find ( RsGxsId ( item - > PeerId ( ) ) ) ;
if ( it = = _distant_chat_contacts . end ( ) )
return false ;
}
2014-11-22 07:47:21 -05:00
2014-11-08 09:55:29 -05:00
# ifdef CHAT_DEBUG
2014-11-22 07:47:21 -05:00
std : : cerr < < " p3ChatService::handleOutgoingItem(): sending to " < < item - > PeerId ( ) < < " : interpreted as a distant chat virtual peer id. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2014-11-22 07:47:21 -05:00
sendTurtleData ( item ) ;
return true ;
2014-11-08 09:55:29 -05:00
}
void DistantChatService : : handleRecvChatStatusItem ( RsChatStatusItem * cs )
{
2014-12-07 16:51:30 -05:00
if ( cs - > flags & RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION )
2014-11-16 17:46:18 -05:00
markDistantChatAsClosed ( RsGxsId ( cs - > PeerId ( ) ) ) ;
2014-12-07 16:51:30 -05:00
// nothing more to do, because the decryption routing will update the last_contact time when decrypting.
if ( cs - > flags & RS_CHAT_FLAG_KEEP_ALIVE )
std : : cerr < < " DistantChatService::handleRecvChatStatusItem(): received keep alive packet for inactive chat! peerId= " < < cs - > PeerId ( ) < < std : : endl ;
2014-11-08 09:55:29 -05:00
}
bool DistantChatService : : handleTunnelRequest ( const RsFileHash & hash , const RsPeerId & /*peer_id*/ )
{
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
// look into owned GXS ids, and see if the hash corresponds to the expected hash
//
std : : list < RsGxsId > own_id_list ;
rsIdentity - > getOwnIds ( own_id_list ) ;
2015-02-14 15:55:05 -05:00
// re-computing the hash from the GXS id allows to dynamically change the hash. That will allow
// the use of a contact passphrase, if needed.
2014-11-08 09:55:29 -05:00
for ( std : : list < RsGxsId > : : const_iterator it ( own_id_list . begin ( ) ) ; it ! = own_id_list . end ( ) ; + + it )
if ( hashFromGxsId ( * it ) = = hash )
{
# ifdef DEBUG_DISTANT_CHAT
2014-11-15 15:54:42 -05:00
std : : cerr < < " DistantChatService::handleTunnelRequest: received tunnel request for hash " < < hash < < std : : endl ;
2014-11-08 09:55:29 -05:00
std : : cerr < < " answering true! " < < std : : endl ;
# endif
return true ;
2014-11-20 18:18:14 -05:00
}
2014-11-08 09:55:29 -05:00
return false ;
}
void DistantChatService : : addVirtualPeer ( const TurtleFileHash & hash , const TurtleVirtualPeerId & virtual_peer_id , RsTurtleGenericTunnelItem : : Direction dir )
{
# ifdef DEBUG_DISTANT_CHAT
2014-12-07 16:51:30 -05:00
std : : cerr < < " DistantChatService:: received new virtual peer " < < virtual_peer_id < < " for hash " < < hash < < " , dir= " < < dir < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2014-11-20 18:18:14 -05:00
RsGxsId own_gxs_id ;
2014-11-08 09:55:29 -05:00
2014-11-16 17:46:18 -05:00
{
2014-11-20 18:18:14 -05:00
RS_STACK_MUTEX ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-16 17:46:18 -05:00
2015-02-14 15:55:05 -05:00
DistantChatDHInfo & dhinfo ( _distant_chat_virtual_peer_ids [ virtual_peer_id ] ) ;
dhinfo . gxs_id . clear ( ) ;
if ( dhinfo . dh ! = NULL )
DH_free ( dhinfo . dh ) ;
dhinfo . dh = NULL ;
dhinfo . direction = dir ;
dhinfo . hash = hash ;
dhinfo . status = RS_DISTANT_CHAT_DH_STATUS_UNINITIALIZED ;
// if( _distant_chat_virtual_peer_ids.find(virtual_peer_id) != _distant_chat_virtual_peer_ids.end())
// {
// std::cerr << " Tunnel already registered for " << hash << " and virtual peer " << virtual_peer_id << ". Doing nothing." << std::endl;
// return ;
// }
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( dir = = RsTurtleGenericTunnelItem : : DIRECTION_CLIENT )
2014-11-13 17:28:37 -05:00
{
2014-11-20 18:18:14 -05:00
// check that a tunnel is not already working for this hash. If so, give up.
2014-11-13 17:28:37 -05:00
2014-11-20 18:18:14 -05:00
own_gxs_id = gxsIdFromHash ( hash ) ;
2014-12-07 16:51:30 -05:00
2014-11-13 17:28:37 -05:00
}
2014-11-20 18:18:14 -05:00
else // client side
{
RsGxsId to_gxs_id = gxsIdFromHash ( hash ) ;
std : : map < RsGxsId , DistantChatPeerInfo > : : const_iterator it = _distant_chat_contacts . find ( to_gxs_id ) ;
2014-11-13 17:28:37 -05:00
2014-11-20 18:18:14 -05:00
if ( it = = _distant_chat_contacts . end ( ) )
{
std : : cerr < < " (EE) no pre-registered peer for hash " < < hash < < " on client side. This is a bug. " < < std : : endl ;
return ;
}
2014-12-16 16:45:49 -05:00
if ( it - > second . status = = RS_DISTANT_CHAT_STATUS_CAN_TALK )
{
std : : cerr < < " virtual peer is for a distant chat session that is already openned and alive. Giving it up. " < < std : : endl ;
return ;
}
2014-12-07 16:51:30 -05:00
2014-11-20 18:18:14 -05:00
own_gxs_id = it - > second . own_gxs_id ;
}
2014-12-16 16:45:49 -05:00
2015-02-14 15:55:05 -05:00
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " Creating new virtual peer ID entry and empty DH session key. " < < std : : endl ;
# endif
2014-12-16 16:45:49 -05:00
2014-11-16 17:46:18 -05:00
}
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " Adding virtual peer " < < virtual_peer_id < < " for chat hash " < < hash < < std : : endl ;
# endif
// Start a new DH session for this tunnel
RS_STACK_MUTEX ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
locked_restartDHSession ( virtual_peer_id , own_gxs_id ) ;
}
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
void DistantChatService : : locked_restartDHSession ( const RsPeerId & virtual_peer_id , const RsGxsId & own_gxs_id )
{
2014-11-22 07:47:21 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " Starting new DH session. " < < std : : endl ;
2014-11-22 07:47:21 -05:00
# endif
2015-02-14 15:55:05 -05:00
DistantChatDHInfo & dhinfo = _distant_chat_virtual_peer_ids [ virtual_peer_id ] ;
dhinfo . status = RS_DISTANT_CHAT_DH_STATUS_UNINITIALIZED ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( ! locked_initDHSessionKey ( dhinfo . dh ) )
2014-11-20 18:18:14 -05:00
{
std : : cerr < < " (EE) Cannot start DH session. Something went wrong. " < < std : : endl ;
return ;
2014-11-13 17:28:37 -05:00
}
2015-02-14 15:55:05 -05:00
dhinfo . status = RS_DISTANT_CHAT_DH_STATUS_HALF_KEY_DONE ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( ! locked_sendDHPublicKey ( dhinfo . dh , own_gxs_id , virtual_peer_id ) )
2014-11-20 18:18:14 -05:00
std : : cerr < < " (EE) Cannot send DH public key. Something went wrong. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
}
void DistantChatService : : removeVirtualPeer ( const TurtleFileHash & hash , const TurtleVirtualPeerId & virtual_peer_id )
{
2014-11-20 18:18:14 -05:00
bool tunnel_dn = false ;
2014-11-08 09:55:29 -05:00
2014-11-22 07:47:21 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-11-20 18:18:14 -05:00
std : : cerr < < " Distant chat: Removing virtual peer " < < virtual_peer_id < < " for hash " < < hash < < std : : endl ;
2014-11-22 07:47:21 -05:00
# endif
2014-11-20 18:18:14 -05:00
{
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
RsGxsId gxs_id ;
std : : map < RsPeerId , DistantChatDHInfo > : : iterator it = _distant_chat_virtual_peer_ids . find ( virtual_peer_id ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( it = = _distant_chat_virtual_peer_ids . end ( ) )
{
std : : cerr < < " (EE) Cannot remove virtual peer " < < virtual_peer_id < < " : not found in chat list!! " < < std : : endl ;
return ;
}
gxs_id = it - > second . gxs_id ;
if ( it - > second . dh ! = NULL )
DH_free ( it - > second . dh ) ;
_distant_chat_virtual_peer_ids . erase ( it ) ;
std : : map < RsGxsId , DistantChatPeerInfo > : : iterator it2 = _distant_chat_contacts . find ( gxs_id ) ;
if ( it2 = = _distant_chat_contacts . end ( ) )
{
std : : cerr < < " (EE) Cannot find GXS id " < < gxs_id < < " in contact list. Weird. " < < std : : endl ;
return ;
}
if ( it2 - > second . virtual_peer_id = = virtual_peer_id )
{
it2 - > second . status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ;
it2 - > second . virtual_peer_id . clear ( ) ;
tunnel_dn = true ;
}
}
if ( tunnel_dn )
{
2014-12-29 16:41:05 -05:00
RsServer : : notify ( ) - > notifyChatStatus ( ChatId ( RsGxsId ( virtual_peer_id ) ) , " tunnel is down... " ) ;
2014-11-20 18:18:14 -05:00
RsServer : : notify ( ) - > notifyPeerStatusChanged ( virtual_peer_id . toStdString ( ) , RS_STATUS_OFFLINE ) ;
}
2014-11-08 09:55:29 -05:00
}
# ifdef DEBUG_DISTANT_CHAT
static void printBinaryData ( void * data , uint32_t size )
{
static const char outl [ 16 ] = { ' 0 ' , ' 1 ' , ' 2 ' , ' 3 ' , ' 4 ' , ' 5 ' , ' 6 ' , ' 7 ' , ' 8 ' , ' 9 ' , ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' } ;
2014-12-07 16:51:30 -05:00
uint32_t mx = std : : min ( 50u , size ) ;
2014-11-22 07:47:21 -05:00
for ( uint32_t j = 0 ; j < mx ; j + + )
2014-11-08 09:55:29 -05:00
{
std : : cerr < < outl [ ( ( ( uint8_t * ) data ) [ j ] > > 4 ) ] ;
std : : cerr < < outl [ ( ( uint8_t * ) data ) [ j ] & 0xf ] ;
2014-11-22 07:47:21 -05:00
}
if ( size > 50 )
std : : cerr < < " ... " ;
2014-11-08 09:55:29 -05:00
}
# endif
2014-11-20 18:18:14 -05:00
void DistantChatService : : receiveTurtleData ( RsTurtleGenericTunnelItem * gitem , const RsFileHash & hash ,
const RsPeerId & virtual_peer_id , RsTurtleGenericTunnelItem : : Direction direction )
2014-11-08 09:55:29 -05:00
{
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " DistantChatService::receiveTurtleData(): Received turtle data. " < < std : : endl ;
2014-12-07 16:51:30 -05:00
std : : cerr < < " hash = " < < hash < < std : : endl ;
std : : cerr < < " vpid = " < < virtual_peer_id < < std : : endl ;
std : : cerr < < " acting as = " < < direction < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
RsTurtleGenericDataItem * item = dynamic_cast < RsTurtleGenericDataItem * > ( gitem ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( item = = NULL )
{
std : : cerr < < " (EE) item is not a data item. That is an error. " < < std : : endl ;
return ;
}
// Call the AES crypto module
// - the IV is the first 8 bytes of item->data_bytes
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( item - > data_size < 8 )
{
std : : cerr < < " (EE) item encrypted data stream is too small: size = " < < item - > data_size < < std : : endl ;
return ;
}
if ( * ( ( uint64_t * ) item - > data_bytes ) ! = 0 )
{
std : : cerr < < " Item is encrypted. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
// if cannot decrypt, it means the key is wrong. We need to re-negociate a new key.
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
handleEncryptedData ( ( uint8_t * ) item - > data_bytes , item - > data_size , hash , virtual_peer_id ) ;
}
else
{
std : : cerr < < " Item is not encrypted. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
// Now try deserialise the decrypted data to make an RsItem out of it.
//
RsItem * citem = RsChatSerialiser ( ) . deserialise ( & ( ( uint8_t * ) item - > data_bytes ) [ 8 ] , & item - > data_size ) ;
if ( citem = = NULL )
{
std : : cerr < < " (EE) item could not be de-serialized. That is an error. " < < std : : endl ;
return ;
}
2014-11-13 17:28:37 -05:00
2015-02-14 15:55:05 -05:00
// DH key items are sent even before we know who we speak to, so the virtual peer id is used in this
// case only.
if ( dynamic_cast < RsChatDHPublicKeyItem * > ( citem ) ! = NULL )
{
citem - > PeerId ( virtual_peer_id ) ;
handleIncomingItem ( citem ) ;
}
else
std : : cerr < < " (EE) Deserialiased item has unexpected type. " < < std : : endl ;
}
}
2014-11-08 09:55:29 -05:00
2014-11-13 17:28:37 -05:00
2015-02-14 15:55:05 -05:00
bool DistantChatService : : handleEncryptedData ( const uint8_t * data_bytes , uint32_t data_size , const TurtleFileHash & hash , const RsPeerId & virtual_peer_id )
{
2014-11-13 17:28:37 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " handleEncryptedDataItem() " < < std : : endl ;
std : : cerr < < " size = " < < data_size < < std : : endl ;
std : : cerr < < " data = " < < ( void * ) data_bytes < < std : : endl ;
std : : cerr < < " IV = " < < std : : hex < < * ( uint64_t * ) data_bytes < < std : : dec < < std : : endl ;
std : : cerr < < " data = " ;
printBinaryData ( ( uint8_t * ) data_bytes , data_size ) ;
std : : cerr < < std : : endl ;
2014-11-13 17:28:37 -05:00
# endif
2014-11-20 18:18:14 -05:00
2015-02-14 15:55:05 -05:00
RsItem * citem = NULL ;
2014-12-07 16:51:30 -05:00
{
RS_STACK_MUTEX ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2015-02-14 15:55:05 -05:00
uint32_t decrypted_size = RsAES : : get_buffer_size ( data_size - 8 ) ;
uint8_t * decrypted_data = new uint8_t [ decrypted_size ] ;
uint8_t aes_key [ DISTANT_CHAT_AES_KEY_SIZE ] ;
std : : map < RsPeerId , DistantChatDHInfo > : : iterator it = _distant_chat_virtual_peer_ids . find ( virtual_peer_id ) ;
2014-11-20 18:18:14 -05:00
2014-12-07 16:51:30 -05:00
if ( it = = _distant_chat_virtual_peer_ids . end ( ) )
{
std : : cerr < < " (EE) item is not coming out of a registered tunnel. Weird. hash= " < < hash < < " , peer id = " < < virtual_peer_id < < std : : endl ;
2015-02-14 15:55:05 -05:00
return true ;
2014-12-07 16:51:30 -05:00
}
2014-11-20 18:18:14 -05:00
2015-02-14 15:55:05 -05:00
RsGxsId gxs_id = it - > second . gxs_id ;
2014-12-07 16:51:30 -05:00
std : : map < RsGxsId , DistantChatPeerInfo > : : iterator it2 = _distant_chat_contacts . find ( gxs_id ) ;
2014-11-20 18:18:14 -05:00
2014-12-07 16:51:30 -05:00
if ( it2 = = _distant_chat_contacts . end ( ) )
{
std : : cerr < < " (EE) no GXS id data for ID= " < < gxs_id < < " . This is a bug. " < < std : : endl ;
2015-02-14 15:55:05 -05:00
return true ;
2014-11-20 18:18:14 -05:00
}
2014-12-07 16:51:30 -05:00
memcpy ( aes_key , it2 - > second . aes_key , DISTANT_CHAT_AES_KEY_SIZE ) ;
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " Using IV: " < < std : : hex < < * ( uint64_t * ) data_bytes < < std : : dec < < std : : endl ;
2014-11-13 17:28:37 -05:00
std : : cerr < < " Decrypted buffer size: " < < decrypted_size < < std : : endl ;
std : : cerr < < " key : " ; printBinaryData ( aes_key , 16 ) ; std : : cerr < < std : : endl ;
2015-02-14 15:55:05 -05:00
std : : cerr < < " data : " ; printBinaryData ( ( uint8_t * ) data_bytes , data_size ) ; std : : cerr < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
if ( ! RsAES : : aes_decrypt_8_16 ( ( uint8_t * ) data_bytes + 8 , data_size - 8 , aes_key , ( uint8_t * ) data_bytes , decrypted_data , decrypted_size ) )
2014-11-13 17:28:37 -05:00
{
std : : cerr < < " (EE) packet decryption failed. " < < std : : endl ;
2015-02-14 15:55:05 -05:00
std : : cerr < < " (EE) resetting new DH session. " < < std : : endl ;
2014-11-13 17:28:37 -05:00
delete [ ] decrypted_data ;
2015-02-14 15:55:05 -05:00
locked_restartDHSession ( virtual_peer_id , it2 - > second . own_gxs_id ) ;
return false ;
2014-11-13 17:28:37 -05:00
}
2014-12-07 16:51:30 -05:00
it2 - > second . status = RS_DISTANT_CHAT_STATUS_CAN_TALK ;
it2 - > second . last_contact = time ( NULL ) ;
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " (II) Decrypted data: size= " < < decrypted_size < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
// Now try deserialise the decrypted data to make an RsItem out of it.
//
citem = RsChatSerialiser ( ) . deserialise ( decrypted_data , & decrypted_size ) ;
delete [ ] decrypted_data ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( citem = = NULL )
{
std : : cerr < < " (EE) item could not be de-serialized. That is an error. " < < std : : endl ;
return true ;
}
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
// DH key items are sent even before we know who we speak to, so the virtual peer id is used in this
// case only.
2014-11-16 17:46:18 -05:00
2015-02-14 15:55:05 -05:00
citem - > PeerId ( RsPeerId ( gxs_id ) ) ;
}
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " (II) Setting peer id to " < < citem - > PeerId ( ) < < std : : endl ;
# endif
2015-02-14 15:55:05 -05:00
handleIncomingItem ( citem ) ; // Treats the item, and deletes it
return true ;
2014-11-08 09:55:29 -05:00
}
void DistantChatService : : handleRecvDHPublicKey ( RsChatDHPublicKeyItem * item )
{
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " DistantChatService: Received DH public key. " < < std : : endl ;
item - > print ( std : : cerr , 0 ) ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
// Look for the current state of the key agreement.
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
TurtleVirtualPeerId vpid = item - > PeerId ( ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
RS_STACK_MUTEX ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
std : : map < RsPeerId , DistantChatDHInfo > : : iterator it = _distant_chat_virtual_peer_ids . find ( vpid ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( it = = _distant_chat_virtual_peer_ids . end ( ) )
2015-02-14 15:55:05 -05:00
{
std : : cerr < < " (EE) Cannot find hash in distant chat peer list!! " < < std : : endl ;
return ;
}
// Now check the signature of the DH public key item.
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " Checking signature. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
uint32_t pubkey_size = BN_num_bytes ( item - > public_key ) ;
unsigned char * data = ( unsigned char * ) malloc ( pubkey_size ) ;
BN_bn2bin ( item - > public_key , data ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
RsTlvSecurityKey signature_key ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
// We need to get the key of the sender, but if the key is not cached, we
// need to get it first. So we let the system work for 2-3 seconds before
// giving up. Normally this would only cause a delay for uncached keys,
// which is rare. To force the system to cache the key, we first call for
// getIdDetails().
//
RsIdentityDetails details ;
RsGxsId senders_id ( item - > signature . keyId ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
mIdService - > getIdDetails ( senders_id , details ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
for ( int i = 0 ; i < 6 ; + + i )
if ( ! mIdService - > getKey ( senders_id , signature_key ) | | signature_key . keyData . bin_data = = NULL )
{
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " Cannot get key. Waiting for caching. try " < < i < < " /6 " < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
usleep ( 500 * 1000 ) ; // sleep for 500 msec.
}
else
break ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( signature_key . keyData . bin_data = = NULL )
{
std : : cerr < < " (EE) Key unknown for checking signature from " < < senders_id < < " , can't verify signature. " < < std : : endl ;
std : : cerr < < " Using key provided in DH packet. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
signature_key = item - > gxs_key ;
2014-11-08 09:55:29 -05:00
# warning At this point, we should check that the key Ids match!!
2014-11-22 07:47:21 -05:00
}
else if ( signature_key . keyId ! = item - > gxs_key . keyId )
{
std : : cerr < < " (EE) DH session key is signed by an ID that is not the ID of the key provided inthe packet. Refusing distant chat with this peer. " < < std : : endl ;
return ;
}
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( ! GxsSecurity : : validateSignature ( ( char * ) data , pubkey_size , signature_key , item - > signature ) )
{
std : : cerr < < " (EE) Signature was verified and it doesn't check! This is a security issue! " < < std : : endl ;
return ;
}
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-11-20 18:18:14 -05:00
std : : cerr < < " Signature checks! Sender's ID = " < < senders_id < < std : : endl ;
2015-02-14 15:55:05 -05:00
std : : cerr < < " Computing AES key " < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2014-12-07 16:51:30 -05:00
if ( it - > second . dh = = NULL )
{
std : : cerr < < " (EE) no DH information for that peer. This is an error. " < < std : : endl ;
return ;
}
2015-02-14 15:55:05 -05:00
if ( it - > second . status = = RS_DISTANT_CHAT_DH_STATUS_KEY_AVAILABLE )
{
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " DH Session already set for this tunnel. Re-initing a new session! " < < std : : endl ;
# endif
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
locked_restartDHSession ( vpid , _distant_chat_contacts [ senders_id ] . own_gxs_id ) ;
}
// gets current key params. By default, should contain all null pointers.
//
it - > second . gxs_id = senders_id ;
// Looks for the DH params. If not there yet, create them.
//
int size = DH_size ( it - > second . dh ) ;
unsigned char * key_buff = new unsigned char [ size ] ;
2014-11-08 09:55:29 -05:00
2014-11-22 07:47:21 -05:00
if ( size ! = DH_compute_key ( key_buff , item - > public_key , it - > second . dh ) )
2015-02-14 15:55:05 -05:00
{
std : : cerr < < " (EE) DH computation failed. Probably a bug. Error code= " < < ERR_get_error ( ) < < std : : endl ;
return ;
}
it - > second . status = = RS_DISTANT_CHAT_DH_STATUS_KEY_AVAILABLE ;
2014-11-22 07:47:21 -05:00
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " DH key computation successed. New key in place. " < < std : : endl ;
# endif
2014-11-20 18:18:14 -05:00
DistantChatPeerInfo & pinfo ( _distant_chat_contacts [ senders_id ] ) ;
2015-02-14 15:55:05 -05:00
// Now hash the key buffer into a 16 bytes key.
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
assert ( DISTANT_CHAT_AES_KEY_SIZE < = Sha1CheckSum : : SIZE_IN_BYTES ) ;
memcpy ( pinfo . aes_key , RsDirUtil : : sha1sum ( key_buff , size ) . toByteArray ( ) , DISTANT_CHAT_AES_KEY_SIZE ) ;
delete [ ] key_buff ;
pinfo . last_contact = time ( NULL ) ;
2014-12-07 16:51:30 -05:00
pinfo . last_keep_alive_sent = time ( NULL ) ;
2014-11-20 18:18:14 -05:00
pinfo . status = RS_DISTANT_CHAT_STATUS_CAN_TALK ;
pinfo . virtual_peer_id = vpid ;
2014-12-07 16:51:30 -05:00
pinfo . direction = it - > second . direction ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
if ( pinfo . direction = = RsTurtleGenericTunnelItem : : DIRECTION_CLIENT )
pinfo . own_gxs_id = gxsIdFromHash ( it - > second . hash ) ;
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-12-07 16:51:30 -05:00
std : : cerr < < " DH key computed. Tunnel is now secured! " < < std : : endl ;
2014-11-20 18:18:14 -05:00
std : : cerr < < " Key computed: " ; printBinaryData ( pinfo . aes_key , 16 ) ; std : : cerr < < std : : endl ;
2014-12-07 16:51:30 -05:00
std : : cerr < < " Sending a ACK packet. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
// then we send an ACK packet to notify that the tunnel works. That's useful
// because it makes the peer at the other end of the tunnel know that all
// intermediate peer in the tunnel are able to transmit the data.
2014-11-20 18:18:14 -05:00
// However, it is not possible here to call sendTurtleData(), without dead-locking
2015-02-14 15:55:05 -05:00
// the turtle router, so we store the item is a list of items to be sent.
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
RsChatStatusItem * cs = new RsChatStatusItem ;
2014-11-08 09:55:29 -05:00
2014-11-16 17:46:18 -05:00
cs - > status_string = " Tunnel is secured with PFS session. ACK received. You can talk! " ;
2015-02-14 15:55:05 -05:00
cs - > flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_ACK_DISTANT_CONNECTION ;
2014-11-16 17:46:18 -05:00
cs - > PeerId ( RsPeerId ( senders_id ) ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
pendingDistantChatItems . push_back ( cs ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
RsServer : : notify ( ) - > notifyListChange ( NOTIFY_LIST_PRIVATE_INCOMING_CHAT , NOTIFY_TYPE_ADD ) ;
2014-11-08 09:55:29 -05:00
}
2014-11-20 18:18:14 -05:00
bool DistantChatService : : locked_sendDHPublicKey ( const DH * dh , const RsGxsId & own_gxs_id , const RsPeerId & virtual_peer_id )
2014-11-08 09:55:29 -05:00
{
RsChatDHPublicKeyItem * dhitem = new RsChatDHPublicKeyItem ;
2014-11-20 18:18:14 -05:00
if ( dh = = NULL )
2014-11-08 09:55:29 -05:00
{
2014-11-20 18:18:14 -05:00
std : : cerr < < " (EE) DH struct is not initialised! Error. " < < std : : endl ;
delete dhitem ;
2014-11-08 09:55:29 -05:00
return false ;
}
2014-11-20 18:18:14 -05:00
dhitem - > public_key = BN_dup ( dh - > pub_key ) ;
2014-11-08 09:55:29 -05:00
// we should also sign the data and check the signature on the other end.
//
RsTlvKeySignature signature ;
RsTlvSecurityKey signature_key ;
RsTlvSecurityKey signature_key_public ;
2014-11-15 15:54:42 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-11-20 18:18:14 -05:00
std : : cerr < < " Getting key material for signature with GXS id " < < own_gxs_id < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
// The following code is only here to force caching the keys.
//
RsIdentityDetails details ;
2014-11-20 18:18:14 -05:00
mIdService - > getIdDetails ( own_gxs_id , details ) ;
2014-11-08 09:55:29 -05:00
2014-11-13 17:28:37 -05:00
int i ;
for ( i = 0 ; i < 6 ; + + i )
2014-11-20 18:18:14 -05:00
if ( ! mIdService - > getPrivateKey ( own_gxs_id , signature_key ) | | signature_key . keyData . bin_data = = NULL )
{
2014-11-22 07:47:21 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-11-13 17:28:37 -05:00
std : : cerr < < " Cannot get key. Waiting for caching. try " < < i < < " /6 " < < std : : endl ;
2014-11-22 07:47:21 -05:00
# endif
2014-11-20 18:18:14 -05:00
usleep ( 500 * 1000 ) ; // sleep for 500 msec.
}
else
2014-11-13 17:28:37 -05:00
break ;
if ( i = = 6 )
{
2014-11-20 18:18:14 -05:00
std : : cerr < < " (EE) Could not retrieve own private key for ID = " < < own_gxs_id < < " . Giging up sending DH session params. " < < std : : endl ;
2014-11-13 17:28:37 -05:00
return false ;
}
2014-11-08 09:55:29 -05:00
GxsSecurity : : extractPublicKey ( signature_key , signature_key_public ) ;
assert ( ! ( signature_key_public . keyFlags & RSTLV_KEY_TYPE_FULL ) ) ;
2014-11-15 15:54:42 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-11-08 09:55:29 -05:00
std : : cerr < < " Signing... " < < std : : endl ;
# endif
uint32_t size = BN_num_bytes ( dhitem - > public_key ) ;
unsigned char * data = ( unsigned char * ) malloc ( size ) ;
BN_bn2bin ( dhitem - > public_key , data ) ;
if ( ! GxsSecurity : : getSignature ( ( char * ) data , size , signature_key , signature ) )
{
2014-11-20 18:18:14 -05:00
std : : cerr < < " (EE) Cannot sign for id " < < own_gxs_id < < " . Signature call failed. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
return false ;
}
free ( data ) ;
dhitem - > signature = signature ;
dhitem - > gxs_key = signature_key_public ;
2014-11-20 18:18:14 -05:00
dhitem - > PeerId ( RsPeerId ( virtual_peer_id ) ) ; // special case for DH items
2014-11-08 09:55:29 -05:00
2014-11-15 15:54:42 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-11-13 17:28:37 -05:00
std : : cerr < < " Pushing DH session key item to pending distant messages... " < < std : : endl ;
2014-11-15 15:54:42 -05:00
dhitem - > print ( std : : cerr , 2 ) ;
std : : cerr < < std : : endl ;
2014-11-13 17:28:37 -05:00
# endif
2014-11-20 18:18:14 -05:00
pendingDistantChatItems . push_back ( dhitem ) ; // sent off-mutex to avoid deadlocking.
2014-11-08 09:55:29 -05:00
return true ;
}
2014-11-20 18:18:14 -05:00
bool DistantChatService : : locked_initDHSessionKey ( DH * & dh )
2014-11-08 09:55:29 -05:00
{
2014-11-20 18:18:14 -05:00
static const std : : string dh_prime_2048_hex = " B3B86A844550486C7EA459FA468D3A8EFD71139593FE1C658BBEFA9B2FC0AD2628242C2CDC2F91F5B220ED29AAC271192A7374DFA28CDDCA70252F342D0821273940344A7A6A3CB70C7897A39864309F6CAC5C7EA18020EF882693CA2C12BB211B7BA8367D5A7C7252A5B5E840C9E8F081469EBA0B98BCC3F593A4D9C4D5DF539362084F1B9581316C1F80FDAD452FD56DBC6B8ED0775F596F7BB22A3FE2B4753764221528D33DB4140DE58083DB660E3E105123FC963BFF108AC3A268B7380FFA72005A1515C371287C5706FFA6062C9AC73A9B1A6AC842C2764CDACFC85556607E86611FDF486C222E4896CDF6908F239E177ACC641FCBFF72A758D1C10CBB " ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( dh ! = NULL )
{
DH_free ( dh ) ;
dh = NULL ;
}
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
dh = DH_new ( ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( ! dh )
{
std : : cerr < < " (EE) DH_new() failed. " < < std : : endl ;
return false ;
}
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
BN_hex2bn ( & dh - > p , dh_prime_2048_hex . c_str ( ) ) ;
BN_hex2bn ( & dh - > g , " 5 " ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
int codes = 0 ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( ! DH_check ( dh , & codes ) | | codes ! = 0 )
{
std : : cerr < < " (EE) DH check failed! " < < std : : endl ;
return false ;
}
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( ! DH_generate_key ( dh ) )
{
std : : cerr < < " (EE) DH generate_key() failed! Error code = " < < ERR_get_error ( ) < < std : : endl ;
return false ;
2014-11-13 17:28:37 -05:00
}
2014-11-22 07:47:21 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-11-13 17:28:37 -05:00
std : : cerr < < " (II) DH Session key inited. " < < std : : endl ;
2014-11-22 07:47:21 -05:00
# endif
2014-11-20 18:18:14 -05:00
return true ;
2014-11-08 09:55:29 -05:00
}
void DistantChatService : : sendTurtleData ( RsChatItem * item )
{
# ifdef DEBUG_DISTANT_CHAT
2014-11-20 18:18:14 -05:00
std : : cerr < < " DistantChatService::sendTurtleData(): try sending item " < < ( void * ) item < < " to peer " < < item - > PeerId ( ) < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
if ( dynamic_cast < RsChatDHPublicKeyItem * > ( item ) ! = NULL )
{
// make a TurtleGenericData item out of it, and send it in clear.
//
RsTurtleGenericDataItem * gitem = new RsTurtleGenericDataItem ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
uint32_t rssize = item - > serial_size ( ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
gitem - > data_size = rssize + 8 ;
gitem - > data_bytes = malloc ( rssize + 8 ) ;
memset ( gitem - > data_bytes , 0 , 8 ) ;
if ( ! item - > serialise ( & ( ( uint8_t * ) gitem - > data_bytes ) [ 8 ] , rssize ) )
{
std : : cerr < < " (EE) Could not serialise item!!! " < < std : : endl ;
delete gitem ;
delete item ;
return ;
}
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " DistantChatService::sendTurtleData(): Sending clear data to virtual peer: " < < item - > PeerId ( ) < < std : : endl ;
std : : cerr < < " gitem->data_size = " < < gitem - > data_size < < std : : endl ;
std : : cerr < < " data = " ;
printBinaryData ( gitem - > data_bytes , gitem - > data_size ) ;
std : : cerr < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
mTurtle - > sendTurtleData ( item - > PeerId ( ) , gitem ) ;
2014-11-17 16:56:41 -05:00
}
else
{
2015-02-14 15:55:05 -05:00
uint32_t rssize = item - > serial_size ( ) ;
uint8_t * buff = ( uint8_t * ) malloc ( rssize ) ;
2014-11-20 18:18:14 -05:00
2015-02-14 15:55:05 -05:00
if ( ! item - > serialise ( buff , rssize ) )
2014-11-20 18:18:14 -05:00
{
2015-02-14 15:55:05 -05:00
std : : cerr < < " (EE) DistantChatService::sendTurtleData(): Could not serialise item! " < < std : : endl ;
2014-11-20 18:18:14 -05:00
delete [ ] buff ;
2015-02-14 15:55:05 -05:00
delete item ;
2014-11-20 18:18:14 -05:00
return ;
}
2015-02-14 15:55:05 -05:00
sendEncryptedTurtleData ( buff , rssize , RsGxsId ( item - > PeerId ( ) ) ) ;
free ( buff ) ;
}
delete item ;
}
void DistantChatService : : sendEncryptedTurtleData ( const uint8_t * buff , uint32_t rssize , const RsGxsId & gxs_id )
{
uint8_t aes_key [ DISTANT_CHAT_AES_KEY_SIZE ] ;
uint64_t IV = 0 ;
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " Sending encrypted data to virtual gxs id " < < gxs_id < < std : : endl ;
# endif
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
std : : map < RsGxsId , DistantChatPeerInfo > : : iterator it = _distant_chat_contacts . find ( gxs_id ) ;
if ( it = = _distant_chat_contacts . end ( ) )
{
std : : cerr < < " (EE) Cannot find contact key info for ID " < < gxs_id < < " . Cannot send message! " < < std : : endl ;
return ;
}
if ( it - > second . status ! = RS_DISTANT_CHAT_STATUS_CAN_TALK )
{
std : : cerr < < " (EE) Cannot talk to " < < gxs_id < < " . Tunnel status is: " < < it - > second . status < < std : : endl ;
return ;
}
memcpy ( aes_key , it - > second . aes_key , DISTANT_CHAT_AES_KEY_SIZE ) ;
RsPeerId virtual_peer_id = it - > second . virtual_peer_id ;
while ( IV = = 0 ) IV = RSRandom : : random_u64 ( ) ; // make a random 8 bytes IV, that is not 0
2014-11-17 16:56:41 -05:00
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " DistantChatService::sendTurtleData(): tunnel found. Encrypting data. " < < std : : endl ;
# endif
// Now encrypt this data using AES.
//
uint8_t * encrypted_data = new uint8_t [ RsAES : : get_buffer_size ( rssize ) ] ;
uint32_t encrypted_size = RsAES : : get_buffer_size ( rssize ) ;
2014-11-08 09:55:29 -05:00
2014-11-13 17:28:37 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " Using IV: " < < std : : hex < < IV < < std : : dec < < std : : endl ;
2014-11-13 17:28:37 -05:00
std : : cerr < < " Using Key: " ; printBinaryData ( aes_key , 16 ) ; std : : cerr < < std : : endl ;
# endif
if ( ! RsAES : : aes_crypt_8_16 ( buff , rssize , aes_key , ( uint8_t * ) & IV , encrypted_data , encrypted_size ) )
2014-11-17 16:56:41 -05:00
{
std : : cerr < < " (EE) packet encryption failed. " < < std : : endl ;
delete [ ] encrypted_data ;
return ;
2014-11-20 18:18:14 -05:00
}
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
// make a TurtleGenericData item out of it:
//
RsTurtleGenericDataItem * gitem = new RsTurtleGenericDataItem ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
gitem - > data_size = encrypted_size + 8 ;
gitem - > data_bytes = malloc ( gitem - > data_size ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
memcpy ( gitem - > data_bytes , & IV , 8 ) ;
memcpy ( & ( ( ( uint8_t * ) gitem - > data_bytes ) [ 8 ] ) , encrypted_data , encrypted_size ) ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
delete [ ] encrypted_data ;
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2015-02-14 15:55:05 -05:00
std : : cerr < < " DistantChatService::sendTurtleData(): Sending encrypted data to virtual peer: " < < virtual_peer_id < < std : : endl ;
std : : cerr < < " gitem->data_size = " < < gitem - > data_size < < std : : endl ;
std : : cerr < < " data = " ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
printBinaryData ( gitem - > data_bytes , gitem - > data_size ) ;
std : : cerr < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-02-14 15:55:05 -05:00
mTurtle - > sendTurtleData ( virtual_peer_id , gitem ) ;
2014-11-08 09:55:29 -05:00
}
2014-11-18 10:55:31 -05:00
bool DistantChatService : : initiateDistantChatConnexion ( const RsGxsId & to_gxs_id , const RsGxsId & from_gxs_id , uint32_t & error_code )
2014-11-08 09:55:29 -05:00
{
2014-11-20 18:18:14 -05:00
// should be a parameter.
2014-11-08 09:55:29 -05:00
2014-11-18 10:55:31 -05:00
std : : list < RsGxsId > lst ;
2014-11-20 18:18:14 -05:00
mIdService - > getOwnIds ( lst ) ;
2014-11-08 09:55:29 -05:00
2014-11-18 10:55:31 -05:00
bool found = false ;
for ( std : : list < RsGxsId > : : const_iterator it = lst . begin ( ) ; it ! = lst . end ( ) ; + + it )
if ( * it = = from_gxs_id )
2014-11-20 18:18:14 -05:00
{
2014-11-18 10:55:31 -05:00
found = true ;
2014-11-20 18:18:14 -05:00
break ;
}
2014-11-18 10:55:31 -05:00
if ( ! found )
{
std : : cerr < < " (EE) Cannot start distant chat, since GXS id " < < from_gxs_id < < " is not available. " < < std : : endl ;
return false ;
}
RsGxsId own_gxs_id = from_gxs_id ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
startClientDistantChatConnection ( to_gxs_id , own_gxs_id ) ;
2014-11-17 16:56:41 -05:00
error_code = RS_DISTANT_CHAT_ERROR_NO_ERROR ;
2014-11-20 18:18:14 -05:00
return true ;
2014-11-08 09:55:29 -05:00
}
2014-11-20 18:18:14 -05:00
void DistantChatService : : startClientDistantChatConnection ( const RsGxsId & to_gxs_id , const RsGxsId & from_gxs_id )
2014-11-08 09:55:29 -05:00
{
2014-12-07 16:51:30 -05:00
{
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
if ( _distant_chat_contacts . find ( to_gxs_id ) ! = _distant_chat_contacts . end ( ) )
{
std : : cerr < < " DistantChatService:: asking distant chat connexion to a peer who's already in a chat. Ignoring. " < < std : : endl ;
return ;
}
}
DistantChatPeerInfo info ;
2014-11-08 09:55:29 -05:00
2014-12-07 16:51:30 -05:00
time_t now = time ( NULL ) ;
info . last_contact = now ;
info . last_keep_alive_sent = now ;
info . status = RS_DISTANT_CHAT_STATUS_TUNNEL_DN ;
info . own_gxs_id = from_gxs_id ;
info . direction = RsTurtleGenericTunnelItem : : DIRECTION_SERVER ;
2014-11-20 18:18:14 -05:00
info . virtual_peer_id . clear ( ) ;
memset ( info . aes_key , 0 , DISTANT_CHAT_AES_KEY_SIZE ) ;
2014-11-08 09:55:29 -05:00
2014-12-07 16:51:30 -05:00
{
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-20 18:18:14 -05:00
_distant_chat_contacts [ to_gxs_id ] = info ;
2014-12-07 16:51:30 -05:00
}
2014-11-08 09:55:29 -05:00
2014-12-07 16:51:30 -05:00
// Now ask the turtle router to manage a tunnel for that hash.
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
RsFileHash hash = hashFromGxsId ( to_gxs_id ) ;
2014-11-08 09:55:29 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-12-07 16:51:30 -05:00
std : : cerr < < " Starting distant chat to " < < to_gxs_id < < " , hash = " < < hash < < " , from " < < from_gxs_id < < std : : endl ;
std : : cerr < < " Asking turtle router to monitor tunnels for hash " < < hash < < std : : endl ;
2014-11-08 09:55:29 -05:00
# endif
2015-01-22 15:25:39 -05:00
mTurtle - > monitorTunnels ( hash , this , false ) ;
2014-12-07 16:51:30 -05:00
// spawn a status item so as to open the chat window.
RsChatMsgItem * item = new RsChatMsgItem ;
item - > message = " [Starting distant chat. Please wait for secure tunnel to be established] " ;
item - > chatFlags = RS_CHAT_FLAG_PRIVATE ;
item - > PeerId ( RsPeerId ( to_gxs_id ) ) ;
handleRecvChatMsgItem ( item ) ;
2014-11-08 09:55:29 -05:00
}
2015-02-14 15:55:05 -05:00
TurtleFileHash DistantChatService : : hashFromGxsId ( const RsGxsId & destination )
2014-11-08 09:55:29 -05:00
{
2015-02-14 15:55:05 -05:00
// This is in prevision for the "secured GXS tunnel" service, which will need a service ID to register,
// just like GRouter does.
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
static const uint32_t client = RS_SERVICE_TYPE_DISTANT_CHAT ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
assert ( destination . SIZE_IN_BYTES = = 16 ) ;
assert ( Sha1CheckSum : : SIZE_IN_BYTES = = 20 ) ;
2014-11-16 17:46:18 -05:00
2015-02-14 15:55:05 -05:00
uint8_t bytes [ 20 ] ;
memcpy ( bytes , destination . toByteArray ( ) , 16 ) ;
bytes [ 16 ] = 0 ;
bytes [ 17 ] = 0 ;
bytes [ 18 ] = ( client > > 8 ) & 0xff ;
bytes [ 19 ] = client & 0xff ;
// We could rehash this, with a secret key to get a HMAC. That would allow to publish secret distant chat
// passphrases. I'll do this later if needed.
return Sha1CheckSum ( bytes ) ;
2014-11-08 09:55:29 -05:00
}
2015-02-14 15:55:05 -05:00
RsGxsId DistantChatService : : gxsIdFromHash ( const TurtleFileHash & sum )
2014-11-20 18:18:14 -05:00
{
2015-02-14 15:55:05 -05:00
assert ( RsGxsId : : SIZE_IN_BYTES = = 16 ) ;
assert ( Sha1CheckSum : : SIZE_IN_BYTES = = 20 ) ;
uint32_t client_id = sum . toByteArray ( ) [ 19 ] + ( sum . toByteArray ( ) [ 18 ] < < 8 ) ;
2014-11-20 18:18:14 -05:00
2015-02-14 15:55:05 -05:00
if ( client_id ! = RS_SERVICE_TYPE_DISTANT_CHAT )
std : : cerr < < " WARNING: DistantChatService::gxsIdFromHash(). Hash is not a distant file hash. This should not happen. " < < std : : endl ;
2014-11-08 09:55:29 -05:00
2015-02-14 15:55:05 -05:00
return RsGxsId ( sum . toByteArray ( ) ) ; // takes the first 16 bytes
2014-11-20 18:18:14 -05:00
}
2015-02-08 16:06:36 -05:00
bool DistantChatService : : getDistantChatStatus ( const RsGxsId & gxs_id , uint32_t & status , RsGxsId * from_gxs_id )
2014-11-08 09:55:29 -05:00
{
2014-11-20 18:18:14 -05:00
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
std : : map < RsGxsId , DistantChatPeerInfo > : : const_iterator it = _distant_chat_contacts . find ( gxs_id ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( it ! = _distant_chat_contacts . end ( ) )
{
status = it - > second . status ;
2015-02-08 16:06:36 -05:00
if ( from_gxs_id ! = NULL )
* from_gxs_id = it - > second . own_gxs_id ;
2014-11-20 18:18:14 -05:00
return true ;
}
status = RS_DISTANT_CHAT_STATUS_UNKNOWN ;
2015-02-08 16:06:36 -05:00
2014-11-20 18:18:14 -05:00
return false ;
2014-11-08 09:55:29 -05:00
}
2014-11-20 18:18:14 -05:00
bool DistantChatService : : closeDistantChatConnexion ( const RsGxsId & gxs_id )
2014-11-08 09:55:29 -05:00
{
// two cases:
// - client needs to stop asking for tunnels => remove the hash from the list of tunnelled files
// - server needs to only close the window and let the tunnel die. But the window should only open
// if a message arrives.
2014-11-20 18:18:14 -05:00
{
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
std : : map < RsGxsId , DistantChatPeerInfo > : : const_iterator it = _distant_chat_contacts . find ( gxs_id ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( it = = _distant_chat_contacts . end ( ) )
{
std : : cerr < < " (EE) Cannot close distant chat connection. No connection openned for gxs id " < < gxs_id < < std : : endl ;
2014-12-03 14:26:12 -05:00
// We don't know if we are server or client side, but mTurtle will not complain if the hash doesn't exist.
mTurtle - > stopMonitoringTunnels ( hashFromGxsId ( gxs_id ) ) ;
2014-11-20 18:18:14 -05:00
return false ;
}
2014-12-07 16:51:30 -05:00
if ( it - > second . direction = = RsTurtleGenericTunnelItem : : DIRECTION_CLIENT ) // nothing more to do for server side.
2014-11-20 18:18:14 -05:00
return true ;
}
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
// send a status item saying that we're closing the connection
2014-12-03 14:26:12 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-12-07 16:51:30 -05:00
std : : cerr < < " Sending a ACK to close the tunnel since we're managing it. Peer id=. " < < gxs_id < < std : : endl ;
2014-12-03 14:26:12 -05:00
# endif
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
RsChatStatusItem * cs = new RsChatStatusItem ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
cs - > status_string = " " ;
cs - > flags = RS_CHAT_FLAG_PRIVATE | RS_CHAT_FLAG_CLOSING_DISTANT_CONNECTION ;
cs - > PeerId ( RsPeerId ( gxs_id ) ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
sendTurtleData ( cs ) ; // that needs to be done off-mutex and before we close the tunnel.
2014-11-08 09:55:29 -05:00
2014-12-03 14:26:12 -05:00
# ifdef DEBUG_DISTANT_CHAT
2014-12-07 16:51:30 -05:00
std : : cerr < < " This is client side. Stopping tunnel manageement for gxs_id " < < gxs_id < < std : : endl ;
2014-12-03 14:26:12 -05:00
# endif
mTurtle - > stopMonitoringTunnels ( hashFromGxsId ( gxs_id ) ) ;
2014-11-20 18:18:14 -05:00
{
2014-11-16 17:46:18 -05:00
RsStackMutex stack ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-20 18:18:14 -05:00
std : : map < RsGxsId , DistantChatPeerInfo > : : iterator it = _distant_chat_contacts . find ( gxs_id ) ;
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
if ( it = = _distant_chat_contacts . end ( ) ) // server side. Nothing to do.
2014-11-16 17:46:18 -05:00
{
2014-11-20 18:18:14 -05:00
std : : cerr < < " (EE) Cannot close chat associated to GXS id " < < gxs_id < < " : not found. " < < std : : endl ;
2014-11-16 17:46:18 -05:00
return false ;
}
2014-11-08 09:55:29 -05:00
2014-12-07 16:51:30 -05:00
_distant_chat_contacts . erase ( it ) ;
2015-02-14 15:55:05 -05:00
// DistantChatService::removeVirtualPeerId() will be called by the turtle service.
2014-11-20 18:18:14 -05:00
}
return true ;
2014-11-08 09:55:29 -05:00
}
2014-11-20 18:18:14 -05:00
void DistantChatService : : markDistantChatAsClosed ( const RsGxsId & gxs_id )
2014-11-08 09:55:29 -05:00
{
2014-12-07 16:51:30 -05:00
RS_STACK_MUTEX ( mDistantChatMtx ) ; /********** STACK LOCKED MTX ******/
2014-11-08 09:55:29 -05:00
2014-11-20 18:18:14 -05:00
std : : map < RsGxsId , DistantChatPeerInfo > : : iterator it = _distant_chat_contacts . find ( gxs_id ) ;
if ( it = = _distant_chat_contacts . end ( ) )
{
std : : cerr < < " (EE) Cannot mark distant chat connection as closed. No connection openned for gxs id " < < gxs_id < < " . Unexpected situation. " < < std : : endl ;
return ;
}
2014-12-07 16:51:30 -05:00
if ( it - > second . direction = = RsTurtleGenericDataItem : : DIRECTION_CLIENT )
2015-02-14 15:55:05 -05:00
{
# ifdef DEBUG_DISTANT_CHAT
std : : cerr < < " This is server side. Marking distant chat as remotely closed for GXS id " < < gxs_id < < std : : endl ;
# endif
2014-12-07 16:51:30 -05:00
it - > second . status = RS_DISTANT_CHAT_STATUS_REMOTELY_CLOSED ;
2015-02-14 15:55:05 -05:00
}
2014-11-08 09:55:29 -05:00
}