2019-07-17 19:37:18 +02:00
# include <tommath.h>
# include <tomcrypt.h>
# include <misc/endianness.h>
# include <misc/digest.h>
# include <misc/base64.h>
# include <openssl/sha.h>
# include <log/LogUtils.h>
# include <src/client/SpeakingClient.h>
# include "VoiceClient.h"
# include "../../InstanceHandler.h"
# include "../../server/VoiceServer.h"
using namespace std ;
using namespace std : : chrono ;
using namespace ts : : server ;
using namespace ts : : protocol ;
using namespace ts : : connection ;
inline void generate_random ( uint8_t * destination , size_t length ) {
2020-01-24 02:57:58 +01:00
while ( length - - > 0 )
* ( destination + + ) = ( uint8_t ) rand ( ) ;
2019-07-17 19:37:18 +02:00
}
ts : : CommandResult VoiceClient : : handleCommandClientInitIv ( Command & command ) {
2020-01-24 02:57:58 +01:00
this - > last_packet_handshake = system_clock : : now ( ) ;
if ( this - > state = = ConnectionState : : CONNECTED ) { /* we've a reconnect */
if ( system_clock : : now ( ) - this - > lastPingResponse < seconds ( 5 ) ) {
logMessage ( this - > getServerId ( ) , " {} Client initialized session reconnect, but last ping response is not older then 5 seconds ({}). Ignoring attempt " ,
CLIENT_STR_LOG_PREFIX ,
duration_cast < milliseconds > ( system_clock : : now ( ) - this - > lastPingResponse ) . count ( )
) ;
return CommandResult : : Success ;
} else if ( ! config : : voice : : allow_session_reinitialize ) {
logMessage ( this - > getServerId ( ) , " {} Client initialized session reconnect and last ping response is older then 5 seconds ({}). Dropping attempt because its not allowed due to config settings " ,
CLIENT_STR_LOG_PREFIX ,
duration_cast < milliseconds > ( system_clock : : now ( ) - this - > lastPingResponse ) . count ( )
) ;
return CommandResult : : Success ;
}
logMessage ( this - > getServerId ( ) , " {} Client initialized reconnect and last ping response is older then 5 seconds ({}). Allowing attempt " ,
CLIENT_STR_LOG_PREFIX ,
duration_cast < milliseconds > ( system_clock : : now ( ) - this - > lastPingResponse ) . count ( )
) ;
{
unique_lock server_channel_lock ( this - > server - > channel_tree_lock ) ; /* we cant get moved if this is locked! */
if ( this - > currentChannel ) {
this - > server - > client_move ( this - > ref ( ) , nullptr , nullptr , config : : messages : : timeout : : connection_reinitialized , ViewReasonId : : VREASON_TIMEOUT , false , server_channel_lock ) ;
}
}
this - > finalDisconnect ( ) ;
} else if ( this - > state = = ConnectionState : : DISCONNECTING ) {
this - > closeConnection ( ) ; /* executing final disconnect right now! */
}
this - > connection - > reset ( ) ;
{
auto & read_queue = this - > connection - > packet_buffers ( ) [ protocol : : COMMAND ] ;
unique_lock buffer_lock ( read_queue . buffer_lock ) ;
read_queue . set_full_index_to ( 1 ) ; /* the first packet (0) is already the clientinitiv packet */
}
this - > state = ConnectionState : : INIT_HIGH ;
bool use_teaspeak = command . hasParm ( " teaspeak " ) ;
if ( use_teaspeak ) {
debugMessage ( this - > getServerId ( ) , " {} Client using TeaSpeak with auth type {} " , CLIENT_STR_LOG_PREFIX , command [ " verify_type " ] . string ( ) ) ;
this - > properties ( ) [ property : : CLIENT_TYPE_EXACT ] = ClientType : : CLIENT_TEASPEAK ;
}
/* normal TeamSpeak handling */
string clientAlpha = base64 : : decode ( command [ " alpha " ] ) ; //random
if ( clientAlpha . length ( ) ! = 10 ) return { findError ( " parameter_invalid " ) , " Invalid alpha " } ;
string clientOmega = base64 : : decode ( command [ " omega " ] ) ; //The identity public key
string ip = command [ " ip " ] ;
bool ot = command [ 0 ] . has ( " ot " ) ? command [ " ot " ] : false ;
this - > crypto . remote_key = std : : shared_ptr < ecc_key > ( new ecc_key { } , [ ] ( ecc_key * key ) {
if ( ! key ) return ;
ecc_free ( key ) ;
delete key ;
} ) ;
auto state = ecc_import ( ( const unsigned char * ) clientOmega . data ( ) , clientOmega . length ( ) , this - > crypto . remote_key . get ( ) ) ;
if ( state ! = CRYPT_OK ) {
this - > crypto . remote_key . reset ( ) ;
return { ts : : findError ( " client_could_not_validate_identity " ) , error_to_string ( state ) } ;
}
this - > properties ( ) [ property : : CLIENT_UNIQUE_IDENTIFIER ] = base64 : : encode ( digest : : sha1 ( command [ " omega " ] . string ( ) ) ) ;
this - > crypto . alpha = clientAlpha ;
this - > crypto . new_protocol = ! use_teaspeak & & ot & & config : : experimental_31 & & ( this - > crypto . client_time > = 173265950 | | this - > crypto . client_time = = 5680278000UL ) ;
{
size_t beta_length = this - > crypto . new_protocol ? 54 : 10 ;
char beta [ beta_length ] ;
generate_random ( ( uint8_t * ) beta , beta_length ) ;
this - > crypto . beta = string ( beta , beta_length ) ;
}
if ( this - > crypto . new_protocol ) {
//Pre setup
//Generate chain
debugMessage ( this - > getServerId ( ) , " {} Got client 3.1 protocol with build timestamp {} " , CLIENT_STR_LOG_PREFIX , this - > crypto . client_time ) ;
this - > crypto . chain_data = serverInstance - > getTeamSpeakLicense ( ) - > license ( ) ;
this - > crypto . chain_data - > chain - > addEphemeralEntry ( ) ;
auto rawLicense = this - > crypto . chain_data - > chain - > exportChain ( ) ;
//Sign license
auto serverOmega = this - > getServer ( ) - > publicServerKey ( ) ;
auto rawServerOmega = base64 : : decode ( serverOmega ) ;
auto licenseHash = digest : : sha256 ( rawLicense ) ;
size_t signBufferLength = 128 ;
char signBuffer [ signBufferLength ] ;
prng_state prngState { } ;
memset ( & prngState , 0 , sizeof ( prngState ) ) ;
if ( ecc_sign_hash ( ( u_char * ) licenseHash . data ( ) , licenseHash . length ( ) , ( u_char * ) signBuffer , & signBufferLength , & prngState , find_prng ( " sprng " ) , this - > getServer ( ) - > serverKey ( ) ) ! = CRYPT_OK ) return { findError ( " vs_critical " ) , " Could not sign license! " } ;
auto proof = base64 : : encode ( signBuffer , signBufferLength ) ;
Command initivexpand2 ( " initivexpand2 " ) ;
initivexpand2 [ " time " ] = duration_cast < seconds > ( system_clock : : now ( ) . time_since_epoch ( ) ) . count ( ) ;
initivexpand2 [ " l " ] = base64 : : encode ( rawLicense ) ;
initivexpand2 [ " beta " ] = base64 : : encode ( this - > crypto . beta ) ;
initivexpand2 [ " omega " ] = serverOmega ;
initivexpand2 [ " proof " ] = proof ;
initivexpand2 [ " tvd " ] = " " ;
initivexpand2 [ " root " ] = base64 : : encode ( ( char * ) this - > crypto . chain_data - > public_key , 32 ) ;
initivexpand2 [ " ot " ] = 1 ;
this - > sendCommand ( initivexpand2 ) ;
this - > handshake . state = HandshakeState : : SUCCEEDED ; /* we're doing the verify via TeamSpeak */
} else {
debugMessage ( this - > getServerId ( ) , " {} Got non client 3.1 protocol with build timestamp {} " , CLIENT_STR_LOG_PREFIX , this - > crypto . client_time ) ;
auto serverOmega = this - > getServer ( ) - > publicServerKey ( ) ;
if ( serverOmega . empty ( ) ) return { findError ( " vs_critical " ) , " Could not export public key! " } ;
{
Command initivexpand ( " initivexpand " ) ;
initivexpand [ " alpha " ] = base64 : : encode ( clientAlpha ) ;
initivexpand [ " beta " ] = base64 : : encode ( this - > crypto . beta ) ;
initivexpand [ " omega " ] = serverOmega ;
if ( use_teaspeak ) {
initivexpand [ " teaspeak " ] = 1 ;
this - > handshake . state = HandshakeState : : BEGIN ; /* we need to start the handshake */
} else {
this - > handshake . state = HandshakeState : : SUCCEEDED ; /* we're doing the verify via TeamSpeak */
}
this - > sendCommand0 ( initivexpand , false , true ) ; //If we setup the encryption now
}
{
this - > connection - > getCryptHandler ( ) - > block ( ) ; //Block until the key is setuped
string error ;
if ( ! this - > connection - > getCryptHandler ( ) - > setupSharedSecret ( this - > crypto . alpha , this - > crypto . beta , this - > crypto . remote_key . get ( ) , this - > server - > serverKey ( ) , error ) ) {
this - > connection - > getCryptHandler ( ) - > unblock ( ) ;
debugMessage ( this - > server - > getServerId ( ) , " Could not setup shared secret! ( " + error + " ) " ) ;
return { findError ( " vs_critical " ) , " Could not setup shared secret " } ;
}
this - > connection - > getCryptHandler ( ) - > unblock ( ) ;
this - > crypto . protocol_encrypted = true ;
}
}
return CommandResult : : Success ;
2019-07-17 19:37:18 +02:00
}
ts : : CommandResult VoiceClient : : handleCommandClientEk ( const std : : unique_ptr < protocol : : ClientPacket > & packet , Command & cmd ) {
2020-01-24 02:57:58 +01:00
this - > last_packet_handshake = system_clock : : now ( ) ;
debugMessage ( this - > getServerId ( ) , " {} Got client ek! " , CLIENT_STR_LOG_PREFIX ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
auto client_key = base64 : : decode ( cmd [ " ek " ] ) ;
auto x = this - > crypto . chain_data - > chain - > generatePrivateKey ( this - > crypto . chain_data - > root_key , this - > crypto . chain_data - > root_index ) ;
2019-07-17 19:37:18 +02:00
2020-01-24 02:57:58 +01:00
this - > connection - > getCryptHandler ( ) - > setupSharedSecretNew ( this - > crypto . alpha , this - > crypto . beta , ( char * ) x . data ( ) , client_key . data ( ) ) ;
this - > connection - > acknowledge_handler . reset ( ) ;
this - > crypto . protocol_encrypted = true ;
this - > sendAcknowledge ( packet - > packetId ( ) ) ; //Send the encrypted acknowledge
return CommandResult : : Success ;
2019-07-17 19:37:18 +02:00
}