Fake TLS protocol

* pretends being TLS1.3 + http2
* mtp_handler state-machine refactored
This commit is contained in:
Sergey Prokhorov 2019-07-24 19:00:19 +02:00
parent c711054bf2
commit 0a1604d4be
No known key found for this signature in database
GPG key ID: 1C570244E4EF3337
11 changed files with 457 additions and 82 deletions

View file

@ -7,6 +7,7 @@
packet_4b/0,
stream_16b/0,
packet_16b/0,
binary/2,
key/0,
iv/0,
secret/0,
@ -33,6 +34,14 @@ packet_16b() ->
stream_16b() ->
proper_types:list(packet_16b()).
%% Binary of size between Min and Max
binary(Min, Max) when Min < Max ->
TailSize = Max - Min,
?LET({First, Tail}, {proper_types:binary(Min),
proper_types:resize(TailSize,
proper_types:list(proper_types:byte()))},
iolist_to_binary([First | Tail])).
%% 32-byte encryption key: `binary()`
key() ->
proper_types:binary(32).

View file

@ -31,7 +31,7 @@ connect(Host, Port, Seed, Secret, DcId, Protocol) ->
ok = gen_tcp:send(Sock, Header),
PacketLayer = Protocol:new(),
Codec = mtp_codec:new(mtp_obfuscated, CryptoLayer,
Protocol, PacketLayer),
Protocol, PacketLayer, false, undefined, 25 * 1024 * 1024),
#client{sock = Sock,
codec = Codec}.

View file

@ -118,10 +118,8 @@ wait_nonce(info, {tcp, _Sock, TcpData},
{DecKey, DecIv} = mtp_down_conn:get_middle_key(Args#{purpose => <<"CLIENT">>}),
{EncKey, EncIv} = mtp_down_conn:get_middle_key(Args#{purpose => <<"SERVER">>}),
%% Add encryption layer to codec
{_, _, PacketMod, PacketState} = mtp_codec:decompose(Codec2),
CryptoState = mtp_aes_cbc:new(EncKey, EncIv, DecKey, DecIv, 16),
Codec3 = mtp_codec:new(mtp_aes_cbc, CryptoState,
PacketMod, PacketState),
Codec3 = mtp_codec:replace(crypto, mtp_aes_cbc, CryptoState, Codec2),
{next_state, wait_handshake,
activate(S1#hs_state{codec = Codec3,

View file

@ -0,0 +1,62 @@
%% @doc property-based tests for mtp_fake_tls
-module(prop_mtp_fake_tls).
-include_lib("proper/include/proper.hrl").
-include_lib("stdlib/include/assert.hrl").
-export([prop_codec_small/1, prop_codec_big/1, prop_stream/1]).
prop_codec_small(doc) ->
"Tests that any binary below 65535 bytes can be encoded and decoded back as single frame".
prop_codec_small() ->
?FORALL(Bin, mtp_prop_gen:binary(8, 65535), codec_small(Bin)).
codec_small(Bin) ->
%% fake_tls can split big packets to multiple TLS frames of 64kb
Codec = mtp_fake_tls:new(),
{Data, Codec1} = mtp_fake_tls:encode_packet(Bin, Codec),
{ok, Decoded, <<>>, _} = mtp_fake_tls:try_decode_packet(iolist_to_binary(Data), Codec1),
Decoded == Bin.
prop_codec_big(doc) ->
"Tests that big binaries will be split to multiple chunks".
prop_codec_big() ->
?FORALL(Bin, mtp_prop_gen:binary(65536, 75000), codec_big(Bin)).
codec_big(Bin) ->
Codec = mtp_fake_tls:new(),
{Data, Codec1} = mtp_fake_tls:encode_packet(Bin, Codec),
Chunks = decode_stream(iolist_to_binary(Data), Codec1, []),
?assert(length(Chunks) > 1),
?assertEqual(Bin, iolist_to_binary(Chunks)),
true.
prop_stream(doc) ->
"Tests that set of packets of size below 65535b can be encoded and decoded back".
prop_stream() ->
?FORALL(Stream, proper_types:list(mtp_prop_gen:binary(8, 20000)),
codec_stream(Stream)).
codec_stream(Stream) ->
Codec = mtp_fake_tls:new(),
{BinStream, Codec1} =
lists:foldl(
fun(Bin, {Acc, Codec1}) ->
{Data, Codec2} = mtp_fake_tls:encode_packet(Bin, Codec1),
{<<Acc/binary, (iolist_to_binary(Data))/binary>>,
Codec2}
end, {<<>>, Codec}, Stream),
DecodedStream = decode_stream(BinStream, Codec1, []),
Stream == DecodedStream.
decode_stream(BinStream, Codec, Acc) ->
case mtp_fake_tls:try_decode_packet(BinStream, Codec) of
{incomplete, _} ->
lists:reverse(Acc);
{ok, DecPacket, Tail, Codec1} ->
decode_stream(Tail, Codec1, [DecPacket | Acc])
end.