Commit e4c6b8bc authored by levlam's avatar levlam

Implement TLS transport for MTProto-proxy.

parent 2c942119
...@@ -18,9 +18,12 @@ ...@@ -18,9 +18,12 @@
2016 Nikolai Durov 2016 Nikolai Durov
*/ */
#include <assert.h>
#include "sha256.h" #include "sha256.h"
#include <assert.h>
#include <openssl/hmac.h>
void sha256_starts (sha256_context *ctx) { void sha256_starts (sha256_context *ctx) {
EVP_MD_CTX_init (ctx); EVP_MD_CTX_init (ctx);
EVP_DigestInit_ex (ctx, EVP_sha256(), NULL); EVP_DigestInit_ex (ctx, EVP_sha256(), NULL);
...@@ -52,3 +55,10 @@ void sha256_two_chunks (const unsigned char *input1, int ilen1, const unsigned c ...@@ -52,3 +55,10 @@ void sha256_two_chunks (const unsigned char *input1, int ilen1, const unsigned c
sha256_finish (ctx, output); sha256_finish (ctx, output);
EVP_MD_CTX_free (ctx); EVP_MD_CTX_free (ctx);
} }
void sha256_hmac (unsigned char *key, int keylen, unsigned char *input, int ilen, unsigned char output[32]) {
unsigned int len = 0;
unsigned char *result = HMAC(EVP_sha256(), key, keylen, input, ilen, output, &len);
assert (result == output);
assert (len == 32);
}
...@@ -35,3 +35,5 @@ void sha256_update (sha256_context *ctx, const unsigned char *input, int ilen); ...@@ -35,3 +35,5 @@ void sha256_update (sha256_context *ctx, const unsigned char *input, int ilen);
void sha256_finish (sha256_context *ctx, unsigned char output[32]); void sha256_finish (sha256_context *ctx, unsigned char output[32]);
void sha256 (const unsigned char *input, int ilen, unsigned char output[32]); void sha256 (const unsigned char *input, int ilen, unsigned char output[32]);
void sha256_two_chunks (const unsigned char *input1, int ilen1, const unsigned char *input2, int ilen2, unsigned char output[32]); void sha256_two_chunks (const unsigned char *input1, int ilen1, const unsigned char *input2, int ilen2, unsigned char output[32]);
void sha256_hmac (unsigned char *key, int keylen, unsigned char *input, int ilen, unsigned char output[32]);
...@@ -54,35 +54,36 @@ ...@@ -54,35 +54,36 @@
/* for connection flags */ /* for connection flags */
#define C_WANTRD 1 #define C_WANTRD 1
#define C_WANTWR 2 #define C_WANTWR 2
#define C_WANTRW (C_WANTRD | C_WANTWR) #define C_WANTRW (C_WANTRD | C_WANTWR)
#define C_INCONN 4 #define C_INCONN 4
#define C_ERROR 8 #define C_ERROR 8
#define C_NORD 0x10 #define C_NORD 0x10
#define C_NOWR 0x20 #define C_NOWR 0x20
#define C_NORW (C_NORD | C_NOWR) #define C_NORW (C_NORD | C_NOWR)
#define C_INQUERY 0x40 #define C_INQUERY 0x40
#define C_FAILED 0x80 #define C_FAILED 0x80
#define C_ALARM 0x100 #define C_ALARM 0x100
#define C_AIO 0x200 #define C_AIO 0x200
#define C_INTIMEOUT 0x400 #define C_INTIMEOUT 0x400
#define C_STOPREAD 0x800 #define C_STOPREAD 0x800
#define C_REPARSE 0x1000 #define C_REPARSE 0x1000
#define C_DFLUSH 0x2000 #define C_DFLUSH 0x2000
#define C_IPV6 0x4000 #define C_IPV6 0x4000
#define C_EXTERNAL 0x8000 #define C_EXTERNAL 0x8000
#define C_SPECIAL 0x10000 #define C_SPECIAL 0x10000
#define C_NOQACK 0x20000 #define C_NOQACK 0x20000
#define C_RAWMSG 0x40000 #define C_RAWMSG 0x40000
#define C_NET_FAILED 0x80000 #define C_NET_FAILED 0x80000
#define C_CRYPTOIN 0x100000 #define C_CRYPTOIN 0x100000
#define C_CRYPTOOUT 0x200000 #define C_CRYPTOOUT 0x200000
#define C_STOPPARSE 0x400000 #define C_STOPPARSE 0x400000
#define C_ISDH 0x800000 #define C_ISDH 0x800000
#define C_READY_PENDING 0x1000000 #define C_READY_PENDING 0x1000000
#define C_CONNECTED 0x2000000 #define C_CONNECTED 0x2000000
#define C_STOPWRITE 0x4000000 #define C_STOPWRITE 0x4000000
#define C_IS_TLS 0x8000000
#define C_PERMANENT (C_IPV6 | C_RAWMSG) #define C_PERMANENT (C_IPV6 | C_RAWMSG)
/* for connection status */ /* for connection status */
...@@ -232,6 +233,7 @@ struct connection_info { ...@@ -232,6 +233,7 @@ struct connection_info {
void *crypto_temp; void *crypto_temp;
int listening, listening_generation; int listening, listening_generation;
int window_clamp; int window_clamp;
int left_tls_packet_length;
struct raw_message in_u, in, out, out_p; struct raw_message in_u, in, out, out_p;
......
...@@ -238,11 +238,22 @@ int cpu_tcp_aes_crypto_ctr128_encrypt_output (connection_job_t C) /* {{{ */ { ...@@ -238,11 +238,22 @@ int cpu_tcp_aes_crypto_ctr128_encrypt_output (connection_job_t C) /* {{{ */ {
struct aes_crypto *T = c->crypto; struct aes_crypto *T = c->crypto;
assert (c->crypto); assert (c->crypto);
struct raw_message *out = &c->out;
int l = out->total_bytes; while (c->out.total_bytes) {
if (l) { int len = c->out.total_bytes;
assert (rwm_encrypt_decrypt_to (&c->out, &c->out_p, l, &T->write_aeskey, (void *)T->write_aeskey.type->ctr128_crypt, T->write_iv, 1, T->write_ebuf, &T->write_num) == l); if (c->flags & C_IS_TLS) {
assert (c->left_tls_packet_length >= 0);
const int MAX_PACKET_LENGTH = 1425;
if (MAX_PACKET_LENGTH < len) {
len = MAX_PACKET_LENGTH;
}
unsigned char header[5] = {0x17, 0x03, 0x03, len >> 8, len & 255};
rwm_push_data (&c->out_p, header, 5);
vkprintf (2, "Send TLS-packet of length %d\n", len);
}
assert (rwm_encrypt_decrypt_to (&c->out, &c->out_p, len, &T->write_aeskey, (void *)T->write_aeskey.type->ctr128_crypt, T->write_iv, 1, T->write_ebuf, &T->write_num) == len);
} }
return 0; return 0;
...@@ -254,11 +265,37 @@ int cpu_tcp_aes_crypto_ctr128_decrypt_input (connection_job_t C) /* {{{ */ { ...@@ -254,11 +265,37 @@ int cpu_tcp_aes_crypto_ctr128_decrypt_input (connection_job_t C) /* {{{ */ {
struct connection_info *c = CONN_INFO (C); struct connection_info *c = CONN_INFO (C);
struct aes_crypto *T = c->crypto; struct aes_crypto *T = c->crypto;
assert (c->crypto); assert (c->crypto);
struct raw_message *in = &c->in_u;
int l = in->total_bytes; while (c->in_u.total_bytes) {
if (l) { int len = c->in_u.total_bytes;
assert (rwm_encrypt_decrypt_to (&c->in_u, &c->in, l, &T->read_aeskey, (void *)T->read_aeskey.type->ctr128_crypt, T->read_iv, 1, T->read_ebuf, &T->read_num) == l); if (c->flags & C_IS_TLS) {
assert (c->left_tls_packet_length >= 0);
if (c->left_tls_packet_length == 0) {
if (len < 5) {
vkprintf (2, "Need %d more bytes to parse TLS header\n", 5 - len);
return 5 - len;
}
unsigned char header[5];
assert (rwm_fetch_lookup (&c->in_u, header, 5) == 5);
if (memcmp (header, "\x17\x03\x03", 3) != 0) {
vkprintf (1, "error while parsing packet: expect TLS header\n");
fail_connection (C, -1);
return 0;
}
c->left_tls_packet_length = 256 * header[3] + header[4];
vkprintf (2, "Receive TLS-packet of length %d\n", c->left_tls_packet_length);
assert (rwm_skip_data (&c->in_u, 5) == 5);
len -= 5;
}
if (c->left_tls_packet_length < len) {
len = c->left_tls_packet_length;
}
c->left_tls_packet_length -= len;
}
vkprintf (2, "Read %d bytes out of %d available\n", len, c->in_u.total_bytes);
assert (rwm_encrypt_decrypt_to (&c->in_u, &c->in, len, &T->read_aeskey, (void *)T->read_aeskey.type->ctr128_crypt, T->read_iv, 1, T->read_ebuf, &T->read_num) == len);
} }
return 0; return 0;
......
...@@ -180,6 +180,11 @@ int tcp_rpc_write_packet_compact (connection_job_t C, struct raw_message *raw) { ...@@ -180,6 +180,11 @@ int tcp_rpc_write_packet_compact (connection_job_t C, struct raw_message *raw) {
rwm_union (&CONN_INFO(C)->out, raw); rwm_union (&CONN_INFO(C)->out, raw);
return 0; return 0;
} }
if ((CONN_INFO (C)->flags & C_IS_TLS) && CONN_INFO (C)->left_tls_packet_length == -1) {
// uninited TLS connection
rwm_union (&CONN_INFO(C)->out, raw);
return 0;
}
if (!(TCP_RPC_DATA(C)->flags & (RPC_F_COMPACT | RPC_F_MEDIUM))) { if (!(TCP_RPC_DATA(C)->flags & (RPC_F_COMPACT | RPC_F_MEDIUM))) {
return tcp_rpc_write_packet (C, raw); return tcp_rpc_write_packet (C, raw);
......
...@@ -94,18 +94,18 @@ void tcp_rpc_conn_send_data_im (JOB_REF_ARG (C), int len, void *Q); ...@@ -94,18 +94,18 @@ void tcp_rpc_conn_send_data_im (JOB_REF_ARG (C), int len, void *Q);
int tcp_rpc_default_execute (connection_job_t C, int op, struct raw_message *raw); int tcp_rpc_default_execute (connection_job_t C, int op, struct raw_message *raw);
/* for crypto_flags in struct tcp_rpc_data */ /* for crypto_flags in struct tcp_rpc_data */
#define RPCF_ALLOW_UNENC 1 #define RPCF_ALLOW_UNENC 1 // allow unencrypted
#define RPCF_ALLOW_ENC 2 #define RPCF_ALLOW_ENC 2 // allow encrypted
#define RPCF_REQ_DH 4 #define RPCF_REQ_DH 4 // require DH
#define RPCF_ALLOW_SKIP_DH 8 #define RPCF_ALLOW_SKIP_DH 8 // crypto NONCE packet sent
#define RPCF_ENC_SENT 16 #define RPCF_ENC_SENT 16
#define RPCF_SEQNO_HOLES 256 #define RPCF_SEQNO_HOLES 256 // packet numbers not sequential
#define RPCF_QUICKACK 512 #define RPCF_QUICKACK 512 // allow quick ack packets
#define RPCF_COMPACT_OFF 1024 #define RPCF_COMPACT_OFF 1024 // compact mode off
#define RPCF_USE_CRC32C 2048 #define RPCF_USE_CRC32C 2048 // use CRC32-C instead of CRC32
/* for flags in struct tcp_rpc_data */ /* for flags in struct tcp_rpc_data */
#define RPC_F_PAD 0x8000000 #define RPC_F_PAD 0x8000000
#define RPC_F_DROPPED 0x10000000 #define RPC_F_DROPPED 0x10000000
#define RPC_F_MEDIUM 0x20000000 #define RPC_F_MEDIUM 0x20000000
#define RPC_F_COMPACT 0x40000000 #define RPC_F_COMPACT 0x40000000
...@@ -124,7 +124,7 @@ struct tcp_rpc_data { ...@@ -124,7 +124,7 @@ struct tcp_rpc_data {
int flags; int flags;
int in_packet_num; int in_packet_num;
int out_packet_num; int out_packet_num;
int crypto_flags; /* 1 = allow unencrypted, 2 = allow encrypted, 4 = require DH, 8 = crypto NONCE packet sent, 256 = packet numbers not sequential, 512 = allow quick ack packets, 1024 = compact mode off, 2048 = use CRC32-C instead of CRC32 */ int crypto_flags; /* RPCF_* flags */
struct process_id remote_pid; struct process_id remote_pid;
char nonce[16]; char nonce[16];
int nonce_time; int nonce_time;
......
This diff is collapsed.
...@@ -547,9 +547,6 @@ int tcp_rpcs_init_fake_crypto (connection_job_t c) { ...@@ -547,9 +547,6 @@ int tcp_rpcs_init_fake_crypto (connection_job_t c) {
return 1; return 1;
} }
#include "net/net-crypto-aes.h"
#include "net/net-config.h"
int tcp_rpcs_default_check_perm (connection_job_t C) { int tcp_rpcs_default_check_perm (connection_job_t C) {
return RPCF_ALLOW_ENC | RPCF_REQ_DH | tcp_get_default_rpc_flags(); return RPCF_ALLOW_ENC | RPCF_REQ_DH | tcp_get_default_rpc_flags();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment