Added PFS support. Parallel auth_key generation. Small bug fixes

This commit is contained in:
vvaltman 2014-08-29 17:33:15 +04:00
parent bc5a7e671c
commit e179f25fe9
13 changed files with 399 additions and 109 deletions

View File

@ -1,2 +1,4 @@
decryptedMessageMediaVideoL12#4cee6ef3 thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaVideoL12#4cee6ef3 thumb:bytes thumb_w:int thumb_h:int duration:int w:int h:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
decryptedMessageMediaAudioL12#6080758f duration:int size:int key:bytes iv:bytes = DecryptedMessageMedia; decryptedMessageMediaAudioL12#6080758f duration:int size:int key:bytes iv:bytes = DecryptedMessageMedia;
auth.bindTempAuthKey perm_auth_key_id:long nonce:long expires_at:int encrypted_message:string = Bool;

31
loop.c
View File

@ -226,6 +226,16 @@ int is_authorized (void) {
return tgl_authorized_dc (cur_a_dc); return tgl_authorized_dc (cur_a_dc);
} }
int all_authorized (void) {
int i;
for (i = 0; i <= tgl_state.max_dc_num; i++) if (tgl_state.DC_list[i]) {
if (!tgl_authorized_dc (tgl_state.DC_list[i])) {
return 0;
}
}
return 1;
}
int config_got; int config_got;
int got_config (void) { int got_config (void) {
@ -491,25 +501,12 @@ int loop (void) {
lua_binlog_end (); lua_binlog_end ();
#endif #endif
update_prompt (); update_prompt ();
if (!tgl_authorized_dc (tgl_state.DC_working)) { net_loop (0, all_authorized);
cur_a_dc = tgl_state.DC_working;
tgl_dc_authorize (tgl_state.DC_working);
net_loop (0, is_authorized);
}
tgl_do_help_get_config (on_get_config, 0);
net_loop (0, got_config);
if (verbosity >= E_DEBUG) {
logprintf ("DC_info: %d new DC got\n", new_dc_num);
}
int i; int i;
for (i = 0; i <= tgl_state.max_dc_num; i++) if (tgl_state.DC_list[i] && !tgl_authorized_dc (tgl_state.DC_list[i])) { for (i = 0; i <= tgl_state.max_dc_num; i++) if (tgl_state.DC_list[i] && !tgl_authorized_dc (tgl_state.DC_list[i])) {
cur_a_dc = tgl_state.DC_list[i]; assert (0);
tgl_dc_authorize (cur_a_dc);
net_loop (0, is_authorized);
} }
if (!tgl_signed_dc (tgl_state.DC_working)) { if (!tgl_signed_dc (tgl_state.DC_working)) {
@ -610,7 +607,7 @@ int loop (void) {
assert (tgl_signed_dc (tgl_state.DC_list[i])); assert (tgl_signed_dc (tgl_state.DC_list[i]));
} }
write_auth_file (); write_auth_file ();
fflush (stdout); fflush (stdout);
fflush (stderr); fflush (stderr);

View File

@ -477,6 +477,7 @@ enum lua_query_type {
lq_load_document_thumb, lq_load_document_thumb,
lq_delete_msg, lq_delete_msg,
lq_restore_msg, lq_restore_msg,
lq_accept_secret_chat
}; };
struct lua_query_extra { struct lua_query_extra {
@ -1000,6 +1001,10 @@ void lua_do_all (void) {
tgl_do_delete_msg ((long)lua_ptr[p + 1], lua_empty_cb, lua_ptr[p]); tgl_do_delete_msg ((long)lua_ptr[p + 1], lua_empty_cb, lua_ptr[p]);
p += 2; p += 2;
break; break;
case lq_accept_secret_chat:
tgl_do_accept_encr_chat_request (lua_ptr[p + 1], lua_secret_chat_cb, lua_ptr[p]);
p += 2;
break;
/* /*
lq_delete_msg, lq_delete_msg,
lq_restore_msg, lq_restore_msg,
@ -1076,6 +1081,7 @@ struct lua_function functions[] = {
{"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }}, {"create_group_chat", lq_create_group_chat, { lfp_user, lfp_string, lfp_none }},
{"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }}, {"delete_msg", lq_delete_msg, { lfp_msg, lfp_none }},
{"restore_msg", lq_restore_msg, { lfp_positive_number, lfp_none }}, {"restore_msg", lq_restore_msg, { lfp_positive_number, lfp_none }},
{"accept_secret_chat", lq_accept_secret_chat, { lfp_secret_chat, lfp_none }},
{ 0, 0, { lfp_none}} { 0, 0, { lfp_none}}
}; };

9
main.c
View File

@ -330,6 +330,13 @@ void parse_config (void) {
strcpy (buf + l, "binlog_enabled"); strcpy (buf + l, "binlog_enabled");
config_lookup_bool (&conf, buf, &binlog_enabled); config_lookup_bool (&conf, buf, &binlog_enabled);
int pfs_enabled;
strcpy (buf + l, "pfs_enabled");
config_lookup_bool (&conf, buf, &pfs_enabled);
if (pfs_enabled) {
tgl_enable_pfs ();
}
if (binlog_enabled) { if (binlog_enabled) {
parse_config_val (&conf, &binlog_file_name, "binlog", BINLOG_FILE, config_directory); parse_config_val (&conf, &binlog_file_name, "binlog", BINLOG_FILE, config_directory);
@ -534,7 +541,7 @@ int main (int argc, char **argv) {
running_for_first_time (); running_for_first_time ();
parse_config (); parse_config ();
tgl_set_rsa_key ("/etc/ " PROG_NAME "/server.pub"); tgl_set_rsa_key ("/etc/" PROG_NAME "/server.pub");
tgl_set_rsa_key ("tg-server.pub"); tgl_set_rsa_key ("tg-server.pub");

View File

@ -78,9 +78,6 @@
//int verbosity; //int verbosity;
static int auth_success; static int auth_success;
//static enum tgl_dc_state c_state; //static enum tgl_dc_state c_state;
static char nonce[256];
static char new_nonce[256];
static char server_nonce[256];
//extern int binlog_enabled; //extern int binlog_enabled;
//extern int disable_auto_accept; //extern int disable_auto_accept;
//extern int allow_weak_random; //extern int allow_weak_random;
@ -122,7 +119,7 @@ static char Response[MAX_RESPONSE_SIZE];
*/ */
#define TG_SERVER_PUBKEY_FILENAME "tg-server.pub" #define TG_SERVER_PUBKEY_FILENAME "tg-server.pub"
static char *rsa_public_key_name; // = TG_SERVER_PUBKEY_FILENAME; //static char *rsa_public_key_name; // = TG_SERVER_PUBKEY_FILENAME;
static RSA *pubKey; static RSA *pubKey;
static long long pk_fingerprint; static long long pk_fingerprint;
@ -140,7 +137,7 @@ static int rsa_load_public_key (const char *public_key_name) {
return -1; return -1;
} }
vlogprintf (E_WARNING, "public key '%s' loaded successfully\n", rsa_public_key_name); vlogprintf (E_WARNING, "public key '%s' loaded successfully\n", public_key_name);
return 0; return 0;
} }
@ -235,17 +232,32 @@ static int send_req_pq_packet (struct connection *c) {
struct tgl_dc *D = tgl_state.net_methods->get_dc (c); struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
assert (D->state == st_init); assert (D->state == st_init);
tglt_secure_random (nonce, 16); tglt_secure_random (D->nonce, 16);
unenc_msg_header.out_msg_id = 0; unenc_msg_header.out_msg_id = 0;
clear_packet (); clear_packet ();
out_int (CODE_req_pq); out_int (CODE_req_pq);
out_ints ((int *)nonce, 4); out_ints ((int *)D->nonce, 4);
rpc_send_packet (c); rpc_send_packet (c);
D->state = st_reqpq_sent; D->state = st_reqpq_sent;
return 1; return 1;
} }
static int send_req_pq_temp_packet (struct connection *c) {
struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
assert (D->state == st_authorized);
tglt_secure_random (D->nonce, 16);
unenc_msg_header.out_msg_id = 0;
clear_packet ();
out_int (CODE_req_pq);
out_ints ((int *)D->nonce, 4);
rpc_send_packet (c);
D->state = st_reqpq_sent_temp;
return 1;
}
static unsigned long long gcd (unsigned long long a, unsigned long long b) { static unsigned long long gcd (unsigned long long a, unsigned long long b) {
return b ? gcd (b, a % b) : a; return b ? gcd (b, a % b) : a;
@ -253,7 +265,8 @@ static unsigned long long gcd (unsigned long long a, unsigned long long b) {
//typedef unsigned int uint128_t __attribute__ ((mode(TI))); //typedef unsigned int uint128_t __attribute__ ((mode(TI)));
static int process_respq_answer (struct connection *c, char *packet, int len) { static int process_respq_answer (struct connection *c, char *packet, int len, int temp_key) {
struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
unsigned long long what; unsigned long long what;
unsigned p1, p2; unsigned p1, p2;
int i; int i;
@ -263,8 +276,8 @@ static int process_respq_answer (struct connection *c, char *packet, int len) {
assert (*(int *) (packet + 16) == len - 20); assert (*(int *) (packet + 16) == len - 20);
assert (!(len & 3)); assert (!(len & 3));
assert (*(int *) (packet + 20) == CODE_resPQ); assert (*(int *) (packet + 20) == CODE_resPQ);
assert (!memcmp (packet + 24, nonce, 16)); assert (!memcmp (packet + 24, D->nonce, 16));
memcpy (server_nonce, packet + 40, 16); memcpy (D->server_nonce, packet + 40, 16);
char *from = packet + 56; char *from = packet + 56;
int clen = *from++; int clen = *from++;
assert (clen <= 8); assert (clen <= 8);
@ -340,7 +353,7 @@ static int process_respq_answer (struct connection *c, char *packet, int len) {
// create inner part (P_Q_inner_data) // create inner part (P_Q_inner_data)
clear_packet (); clear_packet ();
packet_ptr += 5; packet_ptr += 5;
out_int (CODE_p_q_inner_data); out_int (temp_key ? CODE_p_q_inner_data_temp : CODE_p_q_inner_data);
out_cstring (packet + 57, clen); out_cstring (packet + 57, clen);
//out_int (0x0f01); // pq=15 //out_int (0x0f01); // pq=15
@ -372,18 +385,21 @@ static int process_respq_answer (struct connection *c, char *packet, int len) {
//out_int (0x0301); // p=3 //out_int (0x0301); // p=3
//out_int (0x0501); // q=5 //out_int (0x0501); // q=5
out_ints ((int *) nonce, 4); out_ints ((int *) D->nonce, 4);
out_ints ((int *) server_nonce, 4); out_ints ((int *) D->server_nonce, 4);
tglt_secure_random (new_nonce, 32); tglt_secure_random (D->new_nonce, 32);
out_ints ((int *) new_nonce, 8); out_ints ((int *) D->new_nonce, 8);
if (temp_key) {
out_int (tgl_state.temp_key_expire_time);
}
sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer); sha1 ((unsigned char *) (packet_buffer + 5), (packet_ptr - packet_buffer - 5) * 4, (unsigned char *) packet_buffer);
int l = encrypt_packet_buffer (); int l = encrypt_packet_buffer ();
clear_packet (); clear_packet ();
out_int (CODE_req_DH_params); out_int (CODE_req_DH_params);
out_ints ((int *) nonce, 4); out_ints ((int *) D->nonce, 4);
out_ints ((int *) server_nonce, 4); out_ints ((int *) D->server_nonce, 4);
//out_int (0x0301); // p=3 //out_int (0x0301); // p=3
//out_int (0x0501); // q=5 //out_int (0x0501); // q=5
if (p1 < 256) { if (p1 < 256) {
@ -414,7 +430,7 @@ static int process_respq_answer (struct connection *c, char *packet, int len) {
out_long (pk_fingerprint); out_long (pk_fingerprint);
out_cstring ((char *) encrypt_buffer, l); out_cstring ((char *) encrypt_buffer, l);
tgl_state.net_methods->get_dc (c)->state = st_reqdh_sent; D->state = temp_key ? st_reqdh_sent_temp : st_reqdh_sent;
return rpc_send_packet (c); return rpc_send_packet (c);
} }
@ -515,7 +531,8 @@ int tglmp_check_g_bn (BIGNUM *p, BIGNUM *g) {
return tglmp_check_g (s, g); return tglmp_check_g (s, g);
} }
static int process_dh_answer (struct connection *c, char *packet, int len) { static int process_dh_answer (struct connection *c, char *packet, int len, int temp_key) {
struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
vlogprintf (E_DEBUG, "process_dh_answer(), len=%d\n", len); vlogprintf (E_DEBUG, "process_dh_answer(), len=%d\n", len);
//if (len < 116) { //if (len < 116) {
// vlogprintf (E_ERROR, "%u * %u = %llu", p1, p2, what); // vlogprintf (E_ERROR, "%u * %u = %llu", p1, p2, what);
@ -525,9 +542,9 @@ static int process_dh_answer (struct connection *c, char *packet, int len) {
assert (*(int *) (packet + 16) == len - 20); assert (*(int *) (packet + 16) == len - 20);
assert (!(len & 3)); assert (!(len & 3));
assert (*(int *) (packet + 20) == (int)CODE_server_DH_params_ok); assert (*(int *) (packet + 20) == (int)CODE_server_DH_params_ok);
assert (!memcmp (packet + 24, nonce, 16)); assert (!memcmp (packet + 24, D->nonce, 16));
assert (!memcmp (packet + 40, server_nonce, 16)); assert (!memcmp (packet + 40, D->server_nonce, 16));
tgl_init_aes_unauth (server_nonce, new_nonce, AES_DECRYPT); tgl_init_aes_unauth (D->server_nonce, D->new_nonce, AES_DECRYPT);
in_ptr = (int *)(packet + 56); in_ptr = (int *)(packet + 56);
in_end = (int *)(packet + len); in_end = (int *)(packet + len);
int l = prefetch_strlen (); int l = prefetch_strlen ();
@ -536,8 +553,8 @@ static int process_dh_answer (struct connection *c, char *packet, int len) {
assert (in_ptr == in_end); assert (in_ptr == in_end);
assert (l >= 60); assert (l >= 60);
assert (decrypt_buffer[5] == (int)CODE_server_DH_inner_data); assert (decrypt_buffer[5] == (int)CODE_server_DH_inner_data);
assert (!memcmp (decrypt_buffer + 6, nonce, 16)); assert (!memcmp (decrypt_buffer + 6, D->nonce, 16));
assert (!memcmp (decrypt_buffer + 10, server_nonce, 16)); assert (!memcmp (decrypt_buffer + 10, D->server_nonce, 16));
int g = decrypt_buffer[14]; int g = decrypt_buffer[14];
in_ptr = decrypt_buffer + 15; in_ptr = decrypt_buffer + 15;
in_end = decrypt_buffer + (l >> 2); in_end = decrypt_buffer + (l >> 2);
@ -556,7 +573,6 @@ static int process_dh_answer (struct connection *c, char *packet, int len) {
assert (!memcmp (decrypt_buffer, sha1_buffer, 20)); assert (!memcmp (decrypt_buffer, sha1_buffer, 20));
assert ((char *) in_end - (char *) in_ptr < 16); assert ((char *) in_end - (char *) in_ptr < 16);
struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
D->server_time_delta = server_time - time (0); D->server_time_delta = server_time - time (0);
D->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC); D->server_time_udelta = server_time - get_utime (CLOCK_MONOTONIC);
//logprintf ( "server time is %d, delta = %d\n", server_time, server_time_delta); //logprintf ( "server time is %d, delta = %d\n", server_time, server_time_delta);
@ -565,8 +581,8 @@ static int process_dh_answer (struct connection *c, char *packet, int len) {
clear_packet (); clear_packet ();
packet_ptr += 5; packet_ptr += 5;
out_int (CODE_client_DH_inner_data); out_int (CODE_client_DH_inner_data);
out_ints ((int *) nonce, 4); out_ints ((int *) D->nonce, 4);
out_ints ((int *) server_nonce, 4); out_ints ((int *) D->server_nonce, 4);
out_long (0LL); out_long (0LL);
BN_init (&dh_g); BN_init (&dh_g);
@ -586,8 +602,8 @@ static int process_dh_answer (struct connection *c, char *packet, int len) {
ensure (BN_mod_exp (&auth_key_num, &g_a, dh_power, &dh_prime, tgl_state.BN_ctx)); ensure (BN_mod_exp (&auth_key_num, &g_a, dh_power, &dh_prime, tgl_state.BN_ctx));
l = BN_num_bytes (&auth_key_num); l = BN_num_bytes (&auth_key_num);
assert (l >= 250 && l <= 256); assert (l >= 250 && l <= 256);
assert (BN_bn2bin (&auth_key_num, (unsigned char *)D->auth_key)); assert (BN_bn2bin (&auth_key_num, (unsigned char *)(temp_key ? D->temp_auth_key : D->auth_key)));
memset (D->auth_key + l, 0, 256 - l); memset (temp_key ? D->temp_auth_key + l : D->auth_key + l, 0, 256 - l);
BN_free (dh_power); BN_free (dh_power);
BN_free (&auth_key_num); BN_free (&auth_key_num);
BN_free (&dh_g); BN_free (&dh_g);
@ -600,53 +616,103 @@ static int process_dh_answer (struct connection *c, char *packet, int len) {
//hexdump ((char *)packet_buffer, (char *)packet_ptr); //hexdump ((char *)packet_buffer, (char *)packet_ptr);
l = encrypt_packet_buffer_aes_unauth (server_nonce, new_nonce); l = encrypt_packet_buffer_aes_unauth (D->server_nonce, D->new_nonce);
clear_packet (); clear_packet ();
out_int (CODE_set_client_DH_params); out_int (CODE_set_client_DH_params);
out_ints ((int *) nonce, 4); out_ints ((int *) D->nonce, 4);
out_ints ((int *) server_nonce, 4); out_ints ((int *) D->server_nonce, 4);
out_cstring ((char *) encrypt_buffer, l); out_cstring ((char *) encrypt_buffer, l);
tgl_state.net_methods->get_dc (c)->state = st_client_dh_sent; D->state = temp_key ? st_client_dh_sent_temp : st_client_dh_sent;;
return rpc_send_packet (c); return rpc_send_packet (c);
} }
static void create_temp_auth_key (struct connection *c) {
send_req_pq_temp_packet (c);
}
static int process_auth_complete (struct connection *c UU, char *packet, int len) { int tglmp_encrypt_inner_temp (struct connection *c, int *msg, int msg_ints, int useful, void *data, long long msg_id);
static long long generate_next_msg_id (struct tgl_dc *DC);
static long long msg_id_override;
static void mpc_on_get_config (void *extra, int success);
static int process_auth_complete (struct connection *c UU, char *packet, int len, int temp_key) {
struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
vlogprintf (E_DEBUG, "process_dh_answer(), len=%d\n", len); vlogprintf (E_DEBUG, "process_dh_answer(), len=%d\n", len);
assert (len == 72); assert (len == 72);
assert (!*(long long *) packet); assert (!*(long long *) packet);
assert (*(int *) (packet + 16) == len - 20); assert (*(int *) (packet + 16) == len - 20);
assert (!(len & 3)); assert (!(len & 3));
assert (*(int *) (packet + 20) == CODE_dh_gen_ok); assert (*(int *) (packet + 20) == CODE_dh_gen_ok);
assert (!memcmp (packet + 24, nonce, 16)); assert (!memcmp (packet + 24, D->nonce, 16));
assert (!memcmp (packet + 40, server_nonce, 16)); assert (!memcmp (packet + 40, D->server_nonce, 16));
static unsigned char tmp[44], sha1_buffer[20]; static unsigned char tmp[44], sha1_buffer[20];
memcpy (tmp, new_nonce, 32); memcpy (tmp, D->new_nonce, 32);
tmp[32] = 1; tmp[32] = 1;
//GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12); //GET_DC(c)->auth_key_id = *(long long *)(sha1_buffer + 12);
struct tgl_dc *D = tgl_state.net_methods->get_dc (c); if (!temp_key) {
bl_do_set_auth_key_id (D->id, (unsigned char *)D->auth_key); bl_do_set_auth_key_id (D->id, (unsigned char *)D->auth_key);
sha1 ((unsigned char *)D->auth_key, 256, sha1_buffer); sha1 ((unsigned char *)D->auth_key, 256, sha1_buffer);
} else {
sha1 ((unsigned char *)D->temp_auth_key, 256, sha1_buffer);
D->temp_auth_key_id = *(long long *)(sha1_buffer + 12);
}
memcpy (tmp + 33, sha1_buffer, 8); memcpy (tmp + 33, sha1_buffer, 8);
sha1 (tmp, 41, sha1_buffer); sha1 (tmp, 41, sha1_buffer);
assert (!memcmp (packet + 56, sha1_buffer + 4, 16)); assert (!memcmp (packet + 56, sha1_buffer + 4, 16));
D->server_salt = *(long long *)server_nonce ^ *(long long *)new_nonce; D->server_salt = *(long long *)D->server_nonce ^ *(long long *)D->new_nonce;
//kprintf ("OK\n"); //kprintf ("OK\n");
//c->status = conn_error; //c->status = conn_error;
//sleep (1); //sleep (1);
tgl_state.net_methods->get_dc (c)->state = st_authorized; D->state = st_authorized;
//return 1; //return 1;
vlogprintf (E_DEBUG, "Auth success\n"); vlogprintf (E_DEBUG, "Auth success\n");
auth_success ++; auth_success ++;
D->flags |= 1; if (temp_key) {
//D->flags |= 2;
long long msg_id = generate_next_msg_id (D);
clear_packet ();
out_int (CODE_bind_auth_key_inner);
long long rand;
tglt_secure_random (&rand, 8);
out_long (rand);
out_long (D->temp_auth_key_id);
out_long (D->auth_key_id);
struct tgl_session *S = tgl_state.net_methods->get_session (c);
if (!S->session_id) {
tglt_secure_random (&S->session_id, 8);
}
out_long (S->session_id);
int expires = time (0) + D->server_time_delta + tgl_state.temp_key_expire_time;
out_int (expires);
static int data[1000];
int len = tglmp_encrypt_inner_temp (c, packet_buffer, packet_ptr - packet_buffer, 0, data, msg_id);
msg_id_override = msg_id;
tgl_do_send_bind_temp_key (D, rand, expires, (void *)data, len, msg_id);
msg_id_override = 0;
} else {
D->flags |= 1;
if (tgl_state.enable_pfs) {
create_temp_auth_key (c);
} else {
D->temp_auth_key_id = D->auth_key_id;
memcpy (D->temp_auth_key, D->auth_key, 256);
D->flags |= 2;
if (!(D->flags & 4)) {
tgl_do_help_get_config_dc (D, mpc_on_get_config, D);
}
}
}
//write_auth_file (); //write_auth_file ();
return 1; return 1;
@ -681,8 +747,11 @@ static long long generate_next_msg_id (struct tgl_dc *DC) {
static void init_enc_msg (struct tgl_session *S, int useful) { static void init_enc_msg (struct tgl_session *S, int useful) {
struct tgl_dc *DC = S->dc; struct tgl_dc *DC = S->dc;
assert (DC->auth_key_id); assert (DC->state == st_authorized);
enc_msg.auth_key_id = DC->auth_key_id; //assert (DC->flags & 2);
assert (DC->temp_auth_key_id);
vlogprintf (E_DEBUG, "temp_auth_key_id = 0x%016llx, auth_key_id = 0x%016llx\n", DC->temp_auth_key_id, DC->auth_key_id);
enc_msg.auth_key_id = DC->temp_auth_key_id;
// assert (DC->server_salt); // assert (DC->server_salt);
enc_msg.server_salt = DC->server_salt; enc_msg.server_salt = DC->server_salt;
if (!S->session_id) { if (!S->session_id) {
@ -690,7 +759,7 @@ static void init_enc_msg (struct tgl_session *S, int useful) {
} }
enc_msg.session_id = S->session_id; enc_msg.session_id = S->session_id;
//enc_msg.auth_key_id2 = auth_key_id; //enc_msg.auth_key_id2 = auth_key_id;
enc_msg.msg_id = generate_next_msg_id (DC); enc_msg.msg_id = msg_id_override ? msg_id_override : generate_next_msg_id (DC);
//enc_msg.msg_id -= 0x10000000LL * (lrand48 () & 15); //enc_msg.msg_id -= 0x10000000LL * (lrand48 () & 15);
//kprintf ("message id %016llx\n", enc_msg.msg_id); //kprintf ("message id %016llx\n", enc_msg.msg_id);
enc_msg.seq_no = S->seq_no; enc_msg.seq_no = S->seq_no;
@ -700,7 +769,16 @@ static void init_enc_msg (struct tgl_session *S, int useful) {
S->seq_no += 2; S->seq_no += 2;
}; };
static int aes_encrypt_message (struct tgl_dc *DC, struct encrypted_message *enc) { static void init_enc_msg_inner_temp (struct tgl_dc *DC, long long msg_id) {
enc_msg.auth_key_id = DC->auth_key_id;
tglt_secure_random (&enc_msg.server_salt, 8);
tglt_secure_random (&enc_msg.session_id, 8);
enc_msg.msg_id = msg_id;
enc_msg.seq_no = 0;
};
static int aes_encrypt_message (char *key, struct encrypted_message *enc) {
unsigned char sha1_buffer[20]; unsigned char sha1_buffer[20];
const int MINSZ = offsetof (struct encrypted_message, message); const int MINSZ = offsetof (struct encrypted_message, message);
const int UNENCSZ = offsetof (struct encrypted_message, server_salt); const int UNENCSZ = offsetof (struct encrypted_message, server_salt);
@ -710,13 +788,16 @@ static int aes_encrypt_message (struct tgl_dc *DC, struct encrypted_message *enc
//printf ("enc_len is %d\n", enc_len); //printf ("enc_len is %d\n", enc_len);
vlogprintf (E_DEBUG, "sending message with sha1 %08x\n", *(int *)sha1_buffer); vlogprintf (E_DEBUG, "sending message with sha1 %08x\n", *(int *)sha1_buffer);
memcpy (enc->msg_key, sha1_buffer + 4, 16); memcpy (enc->msg_key, sha1_buffer + 4, 16);
tgl_init_aes_auth (DC->auth_key, enc->msg_key, AES_ENCRYPT); tgl_init_aes_auth (key, enc->msg_key, AES_ENCRYPT);
//hexdump ((char *)enc, (char *)enc + enc_len + 24); //hexdump ((char *)enc, (char *)enc + enc_len + 24);
return tgl_pad_aes_encrypt ((char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ)); return tgl_pad_aes_encrypt ((char *) &enc->server_salt, enc_len, (char *) &enc->server_salt, MAX_MESSAGE_INTS * 4 + (MINSZ - UNENCSZ));
} }
long long tglmp_encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful) { long long tglmp_encrypt_send_message (struct connection *c, int *msg, int msg_ints, int flags) {
struct tgl_dc *DC = tgl_state.net_methods->get_dc (c); struct tgl_dc *DC = tgl_state.net_methods->get_dc (c);
if (!(DC->flags & 4) && !(flags & 2)) {
return generate_next_msg_id (DC);
}
struct tgl_session *S = tgl_state.net_methods->get_session (c); struct tgl_session *S = tgl_state.net_methods->get_session (c);
assert (S); assert (S);
@ -732,17 +813,41 @@ long long tglmp_encrypt_send_message (struct connection *c, int *msg, int msg_in
return -1; return -1;
} }
} }
init_enc_msg (S, useful); init_enc_msg (S, flags & 1);
//hexdump ((char *)msg, (char *)msg + (msg_ints * 4)); //hexdump ((char *)msg, (char *)msg + (msg_ints * 4));
int l = aes_encrypt_message (DC, &enc_msg); int l = aes_encrypt_message (DC->temp_auth_key, &enc_msg);
//hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24); //hexdump ((char *)&enc_msg, (char *)&enc_msg + l + 24);
assert (l > 0); assert (l > 0);
vlogprintf (E_DEBUG, "Sending message to DC%d: %s:%d with key_id=%lld\n", DC->id, DC->ip, DC->port, enc_msg.auth_key_id);
rpc_send_message (c, &enc_msg, l + UNENCSZ); rpc_send_message (c, &enc_msg, l + UNENCSZ);
return client_last_msg_id; return client_last_msg_id;
} }
int tglmp_encrypt_inner_temp (struct connection *c, int *msg, int msg_ints, int useful, void *data, long long msg_id) {
struct tgl_dc *DC = tgl_state.net_methods->get_dc (c);
struct tgl_session *S = tgl_state.net_methods->get_session (c);
assert (S);
const int UNENCSZ = offsetof (struct encrypted_message, server_salt);
if (msg_ints <= 0 || msg_ints > MAX_MESSAGE_INTS - 4) {
return -1;
}
memcpy (enc_msg.message, msg, msg_ints * 4);
enc_msg.msg_len = msg_ints * 4;
init_enc_msg_inner_temp (DC, msg_id);
int l = aes_encrypt_message (DC->auth_key, &enc_msg);
assert (l > 0);
//rpc_send_message (c, &enc_msg, l + UNENCSZ);
memcpy (data, &enc_msg, l + UNENCSZ);
return l + UNENCSZ;
}
static int good_messages; static int good_messages;
static void rpc_execute_answer (struct connection *c, long long msg_id UU); static void rpc_execute_answer (struct connection *c, long long msg_id UU);
@ -930,9 +1035,19 @@ static int process_rpc_message (struct connection *c UU, struct encrypted_messag
vlogprintf (E_DEBUG, "process_rpc_message(), len=%d\n", len); vlogprintf (E_DEBUG, "process_rpc_message(), len=%d\n", len);
assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15)); assert (len >= MINSZ && (len & 15) == (UNENCSZ & 15));
struct tgl_dc *DC = tgl_state.net_methods->get_dc (c); struct tgl_dc *DC = tgl_state.net_methods->get_dc (c);
assert (enc->auth_key_id == DC->auth_key_id); if (enc->auth_key_id != DC->temp_auth_key_id && enc->auth_key_id != DC->auth_key_id) {
assert (DC->auth_key_id); vlogprintf (E_ERROR, "received msg from dc %d with auth_key_id %lld (perm_auth_key_id %lld temp_auth_key_id %lld)\n",
tgl_init_aes_auth (DC->auth_key + 8, enc->msg_key, AES_DECRYPT); DC->id, enc->auth_key_id, DC->auth_key_id, DC->temp_auth_key_id);
}
if (enc->auth_key_id == DC->temp_auth_key_id) {
assert (enc->auth_key_id == DC->temp_auth_key_id);
assert (DC->temp_auth_key_id);
tgl_init_aes_auth (DC->temp_auth_key + 8, enc->msg_key, AES_DECRYPT);
} else {
assert (enc->auth_key_id == DC->auth_key_id);
assert (DC->auth_key_id);
tgl_init_aes_auth (DC->auth_key + 8, enc->msg_key, AES_DECRYPT);
}
int l = tgl_pad_aes_decrypt ((char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ); int l = tgl_pad_aes_decrypt ((char *)&enc->server_salt, len - UNENCSZ, (char *)&enc->server_salt, len - UNENCSZ);
assert (l == len - UNENCSZ); assert (l == len - UNENCSZ);
//assert (enc->auth_key_id2 == enc->auth_key_id); //assert (enc->auth_key_id2 == enc->auth_key_id);
@ -945,6 +1060,7 @@ static int process_rpc_message (struct connection *c UU, struct encrypted_messag
DC->server_salt = enc->server_salt; DC->server_salt = enc->server_salt;
//write_auth_file (); //write_auth_file ();
} }
int this_server_time = enc->msg_id >> 32LL; int this_server_time = enc->msg_id >> 32LL;
if (!DC->server_time_delta) { if (!DC->server_time_delta) {
@ -972,6 +1088,20 @@ static int process_rpc_message (struct connection *c UU, struct encrypted_messag
in_ptr = enc->message; in_ptr = enc->message;
in_end = in_ptr + (enc->msg_len / 4); in_end = in_ptr + (enc->msg_len / 4);
/*{
assert (len <= 10000);
static char s[1 << 20];
int p = 0;
int i;
//static int buf[10000];
//assert (tgl_state.net_methods->read_in_lookup (c, buf, len) == len);
for (i = 0; i < in_end - in_ptr; i++) {
p += sprintf (s + p, "%08x ", *(int *)(in_ptr + i));
}
vlogprintf (E_DEBUG, "%s\n", s);
}*/
struct tgl_session *S = tgl_state.net_methods->get_session (c); struct tgl_session *S = tgl_state.net_methods->get_session (c);
if (enc->msg_id & 1) { if (enc->msg_id & 1) {
@ -985,8 +1115,23 @@ static int process_rpc_message (struct connection *c UU, struct encrypted_messag
static int rpc_execute (struct connection *c, int op, int len) { static int rpc_execute (struct connection *c, int op, int len) {
vlogprintf (E_DEBUG, "outbound rpc connection from dc #%d : received rpc answer %d with %d content bytes\n", tgl_state.net_methods->get_dc(c)->id, op, len); struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
/* if (op < 0) { vlogprintf (E_DEBUG, "outbound rpc connection from dc #%d (%s:%d) : received rpc answer %d with %d content bytes\n", D->id, D->ip, D->port, op, len);
/*{
assert (len <= 10000);
static char s[1 << 20];
int p = 0;
int i;
static int buf[10000];
assert (tgl_state.net_methods->read_in_lookup (c, buf, len) == len);
for (i = 0; i < len / 4; i++) {
p += sprintf (s + p, "%08x ", *(int *)(buf + i));
}
vlogprintf (E_DEBUG, "%s\n", s);
}*/
/* if (op < 0) {
assert (tgl_state.net_methods->read_in (c, Response, Response_len) == Response_len); assert (tgl_state.net_methods->read_in (c, Response, Response_len) == Response_len);
return 0; return 0;
}*/ }*/
@ -1005,27 +1150,26 @@ static int rpc_execute (struct connection *c, int op, int len) {
#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) #if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); // setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
#endif #endif
struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
int o = D->state; int o = D->state;
if (D->flags & 1) { o = st_authorized;} //if (D->flags & 1) { o = st_authorized;}
switch (o) { switch (o) {
case st_reqpq_sent: case st_reqpq_sent:
process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/); process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/, 0);
#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
#endif
return 0; return 0;
case st_reqdh_sent: case st_reqdh_sent:
process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/); process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/, 0);
#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
#endif
return 0; return 0;
case st_client_dh_sent: case st_client_dh_sent:
process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/); process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/, 0);
#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__) return 0;
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4); case st_reqpq_sent_temp:
#endif process_respq_answer (c, Response/* + 8*/, Response_len/* - 12*/, 1);
return 0;
case st_reqdh_sent_temp:
process_dh_answer (c, Response/* + 8*/, Response_len/* - 12*/, 1);
return 0;
case st_client_dh_sent_temp:
process_auth_complete (c, Response/* + 8*/, Response_len/* - 12*/, 1);
return 0; return 0;
case st_authorized: case st_authorized:
if (op < 0 && op >= -999) { if (op < 0 && op >= -999) {
@ -1033,9 +1177,6 @@ static int rpc_execute (struct connection *c, int op, int len) {
} else { } else {
process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/); process_rpc_message (c, (void *)(Response/* + 8*/), Response_len/* - 12*/);
} }
#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
#endif
return 0; return 0;
default: default:
vlogprintf (E_ERROR, "fatal: cannot receive answer in state %d\n", D->state); vlogprintf (E_ERROR, "fatal: cannot receive answer in state %d\n", D->state);
@ -1051,23 +1192,37 @@ static int tc_close (struct connection *c, int who) {
return 0; return 0;
} }
static void mpc_on_get_config (void *extra, int success) {
assert (success);
struct tgl_dc *D = extra;
D->flags |= 4;
}
static int tc_becomes_ready (struct connection *c) { static int tc_becomes_ready (struct connection *c) {
vlogprintf (E_DEBUG, "outbound rpc connection from dc #%d becomed ready\n", tgl_state.net_methods->get_dc(c)->id); vlogprintf (E_DEBUG, "outbound rpc connection from dc #%d becomed ready\n", tgl_state.net_methods->get_dc(c)->id);
//char byte = 0xef; //char byte = 0xef;
//assert (tgl_state.net_methods->write_out (c, &byte, 1) == 1); //assert (tgl_state.net_methods->write_out (c, &byte, 1) == 1);
//tgl_state.net_methods->flush_out (c); //tgl_state.net_methods->flush_out (c);
#if !defined(__MACH__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined (__CYGWIN__)
// setsockopt (c->fd, IPPROTO_TCP, TCP_QUICKACK, (int[]){0}, 4);
#endif
struct tgl_dc *D = tgl_state.net_methods->get_dc (c); struct tgl_dc *D = tgl_state.net_methods->get_dc (c);
if (D->flags & 1) { D->state = st_authorized; }
int o = D->state; int o = D->state;
if (D->flags & 1) { o = st_authorized; } if (o == st_authorized && !tgl_state.enable_pfs) {
D->temp_auth_key_id = D->auth_key_id;
memcpy (D->temp_auth_key, D->auth_key, 256);
D->flags |= 2;
}
switch (o) { switch (o) {
case st_init: case st_init:
send_req_pq_packet (c); send_req_pq_packet (c);
break; break;
case st_authorized: case st_authorized:
if (!(D->flags & 2)) {
assert (!D->temp_auth_key_id);
create_temp_auth_key (c);
} else if (!(D->flags & 4)) {
tgl_do_help_get_config_dc (D, mpc_on_get_config, D);
}
break; break;
default: default:
vlogprintf (E_DEBUG, "c_state = %d\n", D->state); vlogprintf (E_DEBUG, "c_state = %d\n", D->state);
@ -1158,6 +1313,11 @@ void tgln_insert_msg_id (struct tgl_session *S, long long id) {
//extern struct tgl_dc *DC_list[]; //extern struct tgl_dc *DC_list[];
static void regen_temp_key_gw (evutil_socket_t fd, short what, void *arg) {
tglmp_regenerate_temp_auth_key (arg);
}
struct tgl_dc *tglmp_alloc_dc (int id, char *ip, int port UU) { struct tgl_dc *tglmp_alloc_dc (int id, char *ip, int port UU) {
assert (!tgl_state.DC_list[id]); assert (!tgl_state.DC_list[id]);
struct tgl_dc *DC = talloc0 (sizeof (*DC)); struct tgl_dc *DC = talloc0 (sizeof (*DC));
@ -1168,6 +1328,9 @@ struct tgl_dc *tglmp_alloc_dc (int id, char *ip, int port UU) {
if (id > tgl_state.max_dc_num) { if (id > tgl_state.max_dc_num) {
tgl_state.max_dc_num = id; tgl_state.max_dc_num = id;
} }
DC->ev = evtimer_new (tgl_state.ev_base, regen_temp_key_gw, DC);
static struct timeval p;
event_add (DC->ev, &p);
return DC; return DC;
} }
@ -1211,3 +1374,26 @@ void tgl_dc_iterator_ex (void (*iterator)(struct tgl_dc *DC, void *extra), void
iterator (tgl_state.DC_list[i], extra); iterator (tgl_state.DC_list[i], extra);
} }
} }
void tglmp_regenerate_temp_auth_key (struct tgl_dc *D) {
D->flags &= ~6;
D->temp_auth_key_id = 0;
memset (D->temp_auth_key, 0, 256);
if (!D->sessions[0]) {
tgl_dc_authorize (D);
return;
}
struct tgl_session *S = D->sessions[0];
tglt_secure_random (&S->session_id, 8);
S->seq_no = 0;
event_del (S->ev);
S->ack_tree = tree_clear_long (S->ack_tree);
if (S->c) {
create_temp_auth_key (S->c);
}
}

View File

@ -45,11 +45,12 @@ struct tgl_dc;
struct connection; struct connection;
long long tglmp_encrypt_send_message (struct connection *c, int *msg, int msg_ints, int useful); long long tglmp_encrypt_send_message (struct connection *c, int *msg, int msg_ints, int flags);
void tglmp_dc_create_session (struct tgl_dc *DC); void tglmp_dc_create_session (struct tgl_dc *DC);
int tglmp_check_g (unsigned char p[256], BIGNUM *g); int tglmp_check_g (unsigned char p[256], BIGNUM *g);
int tglmp_check_DH_params (BIGNUM *p, int g); int tglmp_check_DH_params (BIGNUM *p, int g);
struct tgl_dc *tglmp_alloc_dc (int id, char *ip, int port); struct tgl_dc *tglmp_alloc_dc (int id, char *ip, int port);
void tglmp_regenerate_temp_auth_key (struct tgl_dc *D);
void tgln_insert_msg_id (struct tgl_session *S, long long id); void tgln_insert_msg_id (struct tgl_session *S, long long id);
void tglmp_on_start (void); void tglmp_on_start (void);

View File

@ -39,6 +39,7 @@
#define CODE_resPQ 0x05162463 #define CODE_resPQ 0x05162463
#define CODE_req_DH_params 0xd712e4be #define CODE_req_DH_params 0xd712e4be
#define CODE_p_q_inner_data 0x83c95aec #define CODE_p_q_inner_data 0x83c95aec
#define CODE_p_q_inner_data_temp 0x3c6a84d4
#define CODE_server_DH_inner_data 0xb5890dba #define CODE_server_DH_inner_data 0xb5890dba
#define CODE_server_DH_params_fail 0x79cb045d #define CODE_server_DH_params_fail 0x79cb045d
#define CODE_server_DH_params_ok 0xd0e8075c #define CODE_server_DH_params_ok 0xd0e8075c
@ -48,6 +49,8 @@
#define CODE_dh_gen_retry 0x46dc1fb9 #define CODE_dh_gen_retry 0x46dc1fb9
#define CODE_dh_gen_fail 0xa69dae02 #define CODE_dh_gen_fail 0xa69dae02
#define CODE_bind_auth_key_inner 0x75a3f765
/* service messages */ /* service messages */
#define CODE_rpc_result 0xf35c6d01 #define CODE_rpc_result 0xf35c6d01
#define CODE_rpc_error 0x2144ca19 #define CODE_rpc_error 0x2144ca19

View File

@ -101,15 +101,23 @@ static int alarm_query (struct query *q) {
return 0; return 0;
}*/ }*/
clear_packet (); if (q->session->session_id == q->session_id) {
out_int (CODE_msg_container); clear_packet ();
out_int (1); out_int (CODE_msg_container);
out_long (q->msg_id); out_int (1);
out_int (q->seq_no); out_long (q->msg_id);
out_int (4 * q->data_len); out_int (q->seq_no);
out_ints (q->data, q->data_len); out_int (4 * q->data_len);
out_ints (q->data, q->data_len);
tglmp_encrypt_send_message (q->session->c, packet_buffer, packet_ptr - packet_buffer, 0); tglmp_encrypt_send_message (q->session->c, packet_buffer, packet_ptr - packet_buffer, q->flags & QUERY_FORCE_SEND);
} else {
q->msg_id = tglmp_encrypt_send_message (q->session->c, q->data, q->data_len, (q->flags & QUERY_FORCE_SEND) | 1);
q->session_id = q->session->session_id;
if (!(q->session->dc->flags & 4) && !(q->flags & QUERY_FORCE_SEND)) {
q->session_id = 0;
}
}
return 0; return 0;
} }
@ -126,7 +134,7 @@ static void alarm_query_gateway (evutil_socket_t fd, short what, void *arg) {
} }
struct query *tglq_send_query (struct tgl_dc *DC, int ints, void *data, struct query_methods *methods, void *extra, void *callback, void *callback_extra) { struct query *tglq_send_query_ex (struct tgl_dc *DC, int ints, void *data, struct query_methods *methods, void *extra, void *callback, void *callback_extra, int flags) {
assert (DC); assert (DC);
assert (DC->auth_key_id); assert (DC->auth_key_id);
if (!DC->sessions[0]) { if (!DC->sessions[0]) {
@ -137,12 +145,17 @@ struct query *tglq_send_query (struct tgl_dc *DC, int ints, void *data, struct q
q->data_len = ints; q->data_len = ints;
q->data = talloc (4 * ints); q->data = talloc (4 * ints);
memcpy (q->data, data, 4 * ints); memcpy (q->data, data, 4 * ints);
q->msg_id = tglmp_encrypt_send_message (DC->sessions[0]->c, data, ints, 1); q->msg_id = tglmp_encrypt_send_message (DC->sessions[0]->c, data, ints, 1 | (flags & QUERY_FORCE_SEND));
q->session = DC->sessions[0]; q->session = DC->sessions[0];
q->seq_no = DC->sessions[0]->seq_no - 1; q->seq_no = q->session->seq_no - 1;
q->session_id = q->session->session_id;
if (!(DC->flags & 4) && !(flags & QUERY_FORCE_SEND)) {
q->session_id = 0;
}
vlogprintf (E_DEBUG, "Msg_id is %lld %p\n", q->msg_id, q); vlogprintf (E_DEBUG, "Msg_id is %lld %p\n", q->msg_id, q);
q->methods = methods; q->methods = methods;
q->DC = DC; q->DC = DC;
q->flags = flags & QUERY_FORCE_SEND;
if (queries_tree) { if (queries_tree) {
vlogprintf (E_DEBUG + 2, "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); vlogprintf (E_DEBUG + 2, "%lld %lld\n", q->msg_id, queries_tree->x->msg_id);
} }
@ -164,6 +177,10 @@ struct query *tglq_send_query (struct tgl_dc *DC, int ints, void *data, struct q
return q; return q;
} }
struct query *tglq_send_query (struct tgl_dc *DC, int ints, void *data, struct query_methods *methods, void *extra, void *callback, void *callback_extra) {
return tglq_send_query_ex (DC, ints, data, methods, extra, callback, callback_extra, 0);
}
static int fail_on_error (struct query *q UU, int error_code UU, int l UU, char *error UU) { static int fail_on_error (struct query *q UU, int error_code UU, int l UU, char *error UU) {
fprintf (stderr, "error #%d: %.*s\n", error_code, l, error); fprintf (stderr, "error #%d: %.*s\n", error_code, l, error);
assert (0); assert (0);
@ -364,6 +381,13 @@ void tgl_do_help_get_config (void (*callback)(void *, int), void *callback_extra
out_int (CODE_help_get_config); out_int (CODE_help_get_config);
tglq_send_query (tgl_state.DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0, callback, callback_extra); tglq_send_query (tgl_state.DC_working, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0, callback, callback_extra);
} }
void tgl_do_help_get_config_dc (struct tgl_dc *D, void (*callback)(void *, int), void *callback_extra) {
clear_packet ();
tgl_do_insert_header ();
out_int (CODE_help_get_config);
tglq_send_query_ex (D, packet_ptr - packet_buffer, packet_buffer, &help_get_config_methods, 0, callback, callback_extra, 2);
}
/* }}} */ /* }}} */
/* {{{ Send code */ /* {{{ Send code */
@ -2821,7 +2845,8 @@ static int get_difference_on_answer (struct query *q UU) {
bl_do_set_date (fetch_int ()); bl_do_set_date (fetch_int ());
bl_do_set_seq (fetch_int ()); bl_do_set_seq (fetch_int ());
//difference_got = 1; //difference_got = 1;
vlogprintf (E_DEBUG, "Empty difference. Seq = %d\n", tgl_state.seq);
if (q->callback) { if (q->callback) {
((void (*)(void *, int))q->callback) (q->callback_extra, 1); ((void (*)(void *, int))q->callback) (q->callback_extra, 1);
} }
@ -2862,6 +2887,7 @@ static int get_difference_on_answer (struct query *q UU) {
bl_do_set_date (fetch_int ()); bl_do_set_date (fetch_int ());
if (x == CODE_updates_difference) { if (x == CODE_updates_difference) {
bl_do_set_seq (fetch_int ()); bl_do_set_seq (fetch_int ());
vlogprintf (E_DEBUG, "Difference end. New seq = %d\n", tgl_state.seq);
} else { } else {
fetch_int (); fetch_int ();
} }
@ -3172,6 +3198,41 @@ void tgl_do_restore_msg (long long id, void (*callback)(void *callback_extra, in
} }
/* }}} */ /* }}} */
static void set_flag_4 (void *_D, int success) {
struct tgl_dc *D = _D;
assert (success);
D->flags |= 4;
static struct timeval ptimeout;
ptimeout.tv_sec = tgl_state.temp_key_expire_time * 0.9;
event_add (D->ev, &ptimeout);
}
static int send_bind_temp_on_answer (struct query *q UU) {
assert (fetch_int () == (int)CODE_bool_true);
struct tgl_dc *D = q->extra;
D->flags |= 2;
tgl_do_help_get_config_dc (D, set_flag_4, D);
vlogprintf (E_DEBUG, "Bind successful in dc %d\n", D->id);
return 0;
}
static struct query_methods send_bind_temp_methods = {
.on_answer = send_bind_temp_on_answer,
.type = TYPE_TO_PARAM (bool)
};
void tgl_do_send_bind_temp_key (struct tgl_dc *D, long long nonce, int expires_at, void *data, int len, long long msg_id) {
clear_packet ();
out_int (CODE_auth_bind_temp_auth_key);
out_long (D->auth_key_id);
out_long (nonce);
out_int (expires_at);
out_cstring (data, len);
struct query *q = tglq_send_query_ex (D, packet_ptr - packet_buffer, packet_buffer, &send_bind_temp_methods, D, 0, 0, 2);
assert (q->msg_id == msg_id);
}
static int update_status_on_answer (struct query *q UU) { static int update_status_on_answer (struct query *q UU) {
fetch_bool (); fetch_bool ();

View File

@ -27,6 +27,7 @@
struct event; struct event;
#define QUERY_ACK_RECEIVED 1 #define QUERY_ACK_RECEIVED 1
#define QUERY_FORCE_SEND 2
struct query; struct query;
struct query_methods { struct query_methods {
@ -41,6 +42,7 @@ struct query {
int data_len; int data_len;
int flags; int flags;
int seq_no; int seq_no;
long long session_id;
void *data; void *data;
struct query_methods *methods; struct query_methods *methods;
struct event *ev; struct event *ev;
@ -65,6 +67,7 @@ void work_timers (void);
double get_double_time (void); double get_double_time (void);
void tgl_do_send_bind_temp_key (struct tgl_dc *D, long long nonce, int expires_at, void *data, int len, long long msg_id);
// For binlog // For binlog

View File

@ -46,6 +46,10 @@ enum tgl_dc_state {
st_reqpq_sent, st_reqpq_sent,
st_reqdh_sent, st_reqdh_sent,
st_client_dh_sent, st_client_dh_sent,
st_init_temp,
st_reqpq_sent_temp,
st_reqdh_sent_temp,
st_client_dh_sent_temp,
st_authorized, st_authorized,
st_error st_error
}; };
@ -71,8 +75,15 @@ struct tgl_dc {
char *user; char *user;
struct tgl_session *sessions[MAX_DC_SESSIONS]; struct tgl_session *sessions[MAX_DC_SESSIONS];
char auth_key[256]; char auth_key[256];
char temp_auth_key[256];
char nonce[256];
char new_nonce[256];
char server_nonce[256];
long long auth_key_id; long long auth_key_id;
long long temp_auth_key_id;
long long server_salt; long long server_salt;
struct event *ev;
int server_time_delta; int server_time_delta;
double server_time_udelta; double server_time_udelta;

6
tgl.c
View File

@ -69,12 +69,16 @@ void tgl_init (void) {
if (!tgl_state.callback.create_print_name) { if (!tgl_state.callback.create_print_name) {
tgl_state.callback.create_print_name = tgls_default_create_print_name; tgl_state.callback.create_print_name = tgls_default_create_print_name;
} }
if (!tgl_state.temp_key_expire_time) {
tgl_state.temp_key_expire_time = 60; //100000;
}
tglmp_on_start (); tglmp_on_start ();
} }
int tgl_authorized_dc (struct tgl_dc *DC) { int tgl_authorized_dc (struct tgl_dc *DC) {
assert (DC); assert (DC);
return DC->auth_key_id; return (DC->flags & 4) != 0;//DC->auth_key_id;
} }
int tgl_signed_dc (struct tgl_dc *DC) { int tgl_signed_dc (struct tgl_dc *DC) {

8
tgl.h
View File

@ -136,6 +136,8 @@ struct tgl_state {
struct tgl_dc *DC_working; struct tgl_dc *DC_working;
int max_dc_num; int max_dc_num;
int dc_working_num; int dc_working_num;
int enable_pfs;
int temp_key_expire_time;
long long cur_uploading_bytes; long long cur_uploading_bytes;
long long cur_uploaded_bytes; long long cur_uploaded_bytes;
@ -219,6 +221,10 @@ static inline void tgl_set_verbosity (int val) {
tgl_state.verbosity = val; tgl_state.verbosity = val;
} }
static inline void tgl_enable_pfs (void) {
tgl_state.enable_pfs = 1;
}
static inline void tgl_set_test_mode (void) { static inline void tgl_set_test_mode (void) {
tgl_state.test_mode ++; tgl_state.test_mode ++;
} }
@ -267,6 +273,8 @@ void tgl_do_create_group_chat (tgl_peer_id_t id, char *chat_topic, void (*callba
void tgl_do_delete_msg (long long id, void (*callback)(void *callback_extra, int success), void *callback_extra); void tgl_do_delete_msg (long long id, void (*callback)(void *callback_extra, int success), void *callback_extra);
void tgl_do_restore_msg (long long id, void (*callback)(void *callback_extra, int success), void *callback_extra); void tgl_do_restore_msg (long long id, void (*callback)(void *callback_extra, int success), void *callback_extra);
void tgl_do_update_status (int online, void (*callback)(void *callback_extra, int success), void *callback_extra); void tgl_do_update_status (int online, void (*callback)(void *callback_extra, int success), void *callback_extra);
void tgl_do_help_get_config_dc (struct tgl_dc *D, void (*callback)(void *, int), void *callback_extra);
void tgl_do_visualize_key (tgl_peer_id_t id, unsigned char buf[16]); void tgl_do_visualize_key (tgl_peer_id_t id, unsigned char buf[16]);

View File

@ -427,6 +427,7 @@ static int do_skip_seq (int seq) {
} }
if (seq > tgl_state.seq + 1) { if (seq > tgl_state.seq + 1) {
vlogprintf (E_NOTICE, "Hole in seq (seq = %d, cur_seq = %d)\n", seq, tgl_state.seq); vlogprintf (E_NOTICE, "Hole in seq (seq = %d, cur_seq = %d)\n", seq, tgl_state.seq);
//vlogprintf (E_NOTICE, "lock_diff = %s\n", (tgl_state.locks & TGL_LOCK_DIFF) ? "true" : "false");
tgl_do_get_difference (0, 0, 0); tgl_do_get_difference (0, 0, 0);
return -1; return -1;
} }