From 795bf65f8dad838cfc9621bf366af98947452a80 Mon Sep 17 00:00:00 2001 From: Arseny Smirnov Date: Wed, 26 Jun 2019 16:13:07 +0200 Subject: [PATCH] TlsInit.{cpp,h} GitOrigin-RevId: acc8f3fd672382392ea9bd82e8426700aec34c04 --- CMakeLists.txt | 2 + td/mtproto/TlsInit.cpp | 403 ++++++++++++++++++++++++++++++++++++++++ td/mtproto/TlsInit.h | 31 ++++ test/mtproto.cpp | 404 +---------------------------------------- 4 files changed, 437 insertions(+), 403 deletions(-) create mode 100644 td/mtproto/TlsInit.cpp create mode 100644 td/mtproto/TlsInit.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 40dd2c495..3821ae706 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -348,6 +348,7 @@ set(TDLIB_SOURCE td/mtproto/RawConnection.cpp td/mtproto/SessionConnection.cpp td/mtproto/TcpTransport.cpp + td/mtproto/TlsInit.cpp td/mtproto/TlsReaderByteFlow.cpp td/mtproto/Transport.cpp td/mtproto/utils.cpp @@ -479,6 +480,7 @@ set(TDLIB_SOURCE td/mtproto/RawConnection.h td/mtproto/SessionConnection.h td/mtproto/TcpTransport.h + td/mtproto/TlsInit.h td/mtproto/TlsReaderByteFlow.h td/mtproto/Transport.h td/mtproto/TransportType.h diff --git a/td/mtproto/TlsInit.cpp b/td/mtproto/TlsInit.cpp new file mode 100644 index 000000000..bf62933bc --- /dev/null +++ b/td/mtproto/TlsInit.cpp @@ -0,0 +1,403 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#include "td/mtproto/TlsInit.h" + +#include "td/utils/as.h" +#include "td/utils/crypto.h" +#include "td/utils/Random.h" +#include "td/utils/Span.h" + +namespace td { +void Grease::init(MutableSlice res) { + Random::secure_bytes(res); + for (auto &c : res) { + c = (c & 0xF0) + 0x0A; + } + for (size_t i = 1; i < res.size(); i += 2) { + if (res[i] == res[i - 1]) { + res[i] ^= 0x10; + } + } +} + +class TlsHello { + public: + struct Op { + enum class Type { String, Random, Zero, Domain, Grease, BeginScope, EndScope }; + Type type; + int length; + int seed; + std::string data; + + static Op string(Slice str) { + Op res; + res.type = Type::String; + res.data = str.str(); + return res; + } + static Op random(int length) { + Op res; + res.type = Type::Random; + res.length = length; + return res; + } + static Op zero(int length) { + Op res; + res.type = Type::Zero; + res.length = length; + return res; + } + static Op domain() { + Op res; + res.type = Type::Domain; + return res; + } + static Op grease(int seed) { + Op res; + res.type = Type::Grease; + res.seed = seed; + return res; + } + static Op begin_scope() { + Op res; + res.type = Type::BeginScope; + return res; + } + static Op end_scope() { + Op res; + res.type = Type::EndScope; + return res; + } + }; + + static const TlsHello &get_default() { + static TlsHello res = [] { + TlsHello res; + res.ops_ = { + Op::string("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"), + Op::zero(32), + Op::string("\x20"), + Op::random(32), + Op::string("\x00\x22"), + Op::grease(0), + Op::string("\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c" + "\x00\x9d\x00\x2f\x00\x35\x00\x0a\x01\x00\x01\x91"), + Op::grease(2), + Op::string("\x00\x00\x00\x00"), + Op::begin_scope(), + Op::begin_scope(), + Op::string("\x00"), + Op::begin_scope(), + Op::domain(), + Op::end_scope(), + Op::end_scope(), + Op::end_scope(), + Op::string("\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\x0a\x00\x0a\x00\x08"), + Op::grease(4), + Op::string( + "\x00\x1d\x00\x17\x00\x18\x00\x0b\x00\x02\x01\x00\x00\x23\x00\x00\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08" + "\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x0d\x00\x14\x00\x12\x04\x03\x08" + "\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01\x02\x01\x00\x12\x00\x00\x00\x33\x00\x2b\x00\x29"), + Op::grease(4), + Op::string("\x00\x01\x00\x00\x1d\x00\x20"), + Op::random(32), + Op::string("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x0b\x0a"), + Op::grease(6), + Op::string("\x03\x04\x03\x03\x03\x02\x03\x01\x00\x1b\x00\x03\x02\x00\x02"), + Op::grease(3), + Op::string("\x00\x01\x00\x00\x15")}; + return res; + }(); + return res; + } + Span get_ops() const { + return ops_; + } + + private: + std::vector ops_; +}; + +class TlsHelloContext { + public: + explicit TlsHelloContext(std::string domain) { + Grease::init(MutableSlice(grease_.data(), grease_.size())); + domain_ = std::move(domain); + } + char get_grease(size_t i) const { + CHECK(i < grease_.size()); + return grease_[i]; + } + size_t grease_size() const { + return grease_.size(); + } + Slice get_domain() const { + return domain_; + } + + private: + constexpr static size_t MAX_GREASE = 8; + std::array grease_; + std::string domain_; +}; + +class TlsHelloCalcLength { + public: + void do_op(const TlsHello::Op &op, const TlsHelloContext *context) { + using Type = TlsHello::Op::Type; + switch (op.type) { + case Type::String: + size_ += op.data.size(); + break; + case Type::Random: + if (op.length <= 0 || op.length > 1024) { + on_error(Status::Error("Invalid random length")); + } + size_ += op.length; + break; + case Type::Zero: + if (op.length < 0 || op.length > 1024) { + on_error(Status::Error("Invalid zero length")); + } + size_ += op.length; + break; + case Type::Domain: + CHECK(context); + size_ += context->get_domain().size(); + break; + case Type::Grease: + CHECK(context); + if (op.seed < 0 || static_cast(op.seed) > context->grease_size()) { + on_error(Status::Error("Invalid grease seed")); + } + size_ += 2; + break; + case Type::BeginScope: + size_ += 2; + scope_offset_.push_back(size_); + break; + case Type::EndScope: + if (scope_offset_.empty()) { + on_error(Status::Error("Unbalanced scopes")); + } + auto begin_offset = scope_offset_.back(); + scope_offset_.pop_back(); + auto end_offset = size_; + auto size = end_offset - begin_offset; + if (size >= (1 << 14)) { + on_error(Status::Error("Scope is too big")); + } + break; + } + } + + Result finish() { + if (size_ > 515) { + on_error(Status::Error("Too long for zero padding")); + } + if (size_ < 11 + 32) { + on_error(Status::Error("Too small for hash")); + } + int zero_pad = 515 - static_cast(size_); + using Op = TlsHello::Op; + do_op(Op::begin_scope(), nullptr); + do_op(Op::zero(zero_pad), nullptr); + do_op(Op::end_scope(), nullptr); + if (!scope_offset_.empty()) { + on_error(Status::Error("Unbalanced scopes")); + } + TRY_STATUS(std::move(status_)); + return size_; + } + + private: + int64 size_{0}; + Status status_; + std::vector scope_offset_; + + void on_error(Status error) { + if (status_.is_ok()) { + status_ = std::move(error); + } + } +}; + +class TlsHelloStore { + public: + TlsHelloStore(MutableSlice dest) : data_(dest), dest_(dest) { + } + void do_op(const TlsHello::Op &op, TlsHelloContext *context) { + using Type = TlsHello::Op::Type; + switch (op.type) { + case Type::String: + dest_.copy_from(op.data); + dest_.remove_prefix(op.data.size()); + break; + case Type::Random: + Random::secure_bytes(dest_.substr(0, op.length)); + dest_.remove_prefix(op.length); + break; + case Type::Zero: + std::memset(dest_.begin(), 0, op.length); + dest_.remove_prefix(op.length); + break; + case Type::Domain: { + CHECK(context); + auto domain = context->get_domain(); + dest_.copy_from(domain); + dest_.remove_prefix(domain.size()); + break; + } + case Type::Grease: { + CHECK(context) + auto grease = context->get_grease(op.seed); + dest_[0] = grease; + dest_[1] = grease; + dest_.remove_prefix(2); + break; + } + case Type::BeginScope: + scope_offset_.push_back(get_offset()); + dest_.remove_prefix(2); + break; + case Type::EndScope: { + CHECK(!scope_offset_.empty()); + auto begin_offset = scope_offset_.back(); + scope_offset_.pop_back(); + auto end_offset = get_offset(); + size_t size = end_offset - begin_offset - 2; + CHECK(size < (1 << 14)); + data_[begin_offset] = static_cast((size >> 8) & 0xff); + data_[begin_offset + 1] = static_cast(size & 0xff); + break; + } + } + } + void finish(int32 unix_time) { + int zero_pad = 515 - static_cast(get_offset()); + using Op = TlsHello::Op; + do_op(Op::begin_scope(), nullptr); + do_op(Op::zero(zero_pad), nullptr); + do_op(Op::end_scope(), nullptr); + + auto tmp = sha256(data_); + auto hash_dest = data_.substr(11); + hash_dest.copy_from(tmp); + int32 old = as(hash_dest.substr(28).data()); + as(hash_dest.substr(28).data()) = old ^ unix_time; + CHECK(dest_.empty()); + } + + private: + MutableSlice data_; + MutableSlice dest_; + std::vector scope_offset_; + size_t get_offset() { + return data_.size() - dest_.size(); + } +}; + +class TlsObfusaction { + public: + static std::string generate_header(std::string domain, int32 unix_time) { + auto &hello = TlsHello::get_default(); + TlsHelloContext context(domain); + TlsHelloCalcLength calc_length; + for (auto &op : hello.get_ops()) { + calc_length.do_op(op, &context); + } + auto length = calc_length.finish().move_as_ok(); + std::string data(length, 0); + TlsHelloStore storer(data); + for (auto &op : hello.get_ops()) { + storer.do_op(op, &context); + } + storer.finish(0); + return data; + } +}; + +void TlsInit::send_hello() { + auto hello = TlsObfusaction::generate_header(username_, 0); + fd_.output_buffer().append(hello); + state_ = State::WaitHelloResponse; +} + +Status TlsInit::wait_hello_response() { + //[ + auto it = fd_.input_buffer().clone(); + //S "\x16\x03\x03" + { + Slice first = "\x16\x03\x03"; + std::string got_first(first.size(), 0); + if (it.size() < first.size()) { + return td::Status::OK(); + } + it.advance(first.size(), got_first); + if (first != got_first) { + return Status::Error("First part of response to hello is invalid"); + } + } + + //[ + { + if (it.size() < 2) { + return td::Status::OK(); + } + uint8 tmp[2]; + it.advance(2, MutableSlice(tmp, 2)); + size_t skip_size = (tmp[0] << 8) + tmp[1]; + if (it.size() < skip_size) { + return td::Status::OK(); + } + it.advance(skip_size); + } + + //S "\x14\x03\x03\x00\x01\x01\x17\x03\x03" + { + Slice first = "\x14\x03\x03\x00\x01\x01\x17\x03\x03"; + std::string got_first(first.size(), 0); + if (it.size() < first.size()) { + return td::Status::OK(); + } + it.advance(first.size(), got_first); + if (first != got_first) { + return Status::Error("Second part of response to hello is invalid"); + } + } + + //[ + { + if (it.size() < 2) { + return td::Status::OK(); + } + uint8 tmp[2]; + it.advance(2, MutableSlice(tmp, 2)); + size_t skip_size = (tmp[0] << 8) + tmp[1]; + if (it.size() < skip_size) { + return td::Status::OK(); + } + it.advance(skip_size); + } + fd_.input_buffer() = std::move(it); + + stop(); + return td::Status::OK(); +} + +Status TlsInit::loop_impl() { + switch (state_) { + case State::SendHello: + send_hello(); + break; + case State::WaitHelloResponse: + TRY_STATUS(wait_hello_response()); + break; + } + return Status::OK(); +} +} // namespace td diff --git a/td/mtproto/TlsInit.h b/td/mtproto/TlsInit.h new file mode 100644 index 000000000..2314e8de9 --- /dev/null +++ b/td/mtproto/TlsInit.h @@ -0,0 +1,31 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2019 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once +#include "td/net/TransparentProxy.h" + +namespace td { +class Grease { + public: + static void init(MutableSlice res); +}; + +class TlsInit : public TransparentProxy { + public: + using TransparentProxy::TransparentProxy; + + private: + enum class State { + SendHello, + WaitHelloResponse, + } state_ = State::SendHello; + + void send_hello(); + Status wait_hello_response(); + + Status loop_impl() override; +}; +} // namespace td diff --git a/test/mtproto.cpp b/test/mtproto.cpp index 3b726b86f..3959a8d0d 100644 --- a/test/mtproto.cpp +++ b/test/mtproto.cpp @@ -17,6 +17,7 @@ #include "td/mtproto/Ping.h" #include "td/mtproto/PingConnection.h" #include "td/mtproto/RawConnection.h" +#include "td/mtproto/TlsInit.h" #include "td/mtproto/TransportType.h" #include "td/net/GetHostByNameActor.h" @@ -590,409 +591,6 @@ class Mtproto_FastPing : public Test { }; RegisterTest mtproto_fastping("Mtproto_FastPing"); -class Grease { - public: - static void init(MutableSlice res) { - Random::secure_bytes(res); - for (auto &c : res) { - c = (c & 0xF0) + 0x0A; - } - for (size_t i = 1; i < res.size(); i += 2) { - if (res[i] == res[i - 1]) { - res[i] ^= 0x10; - } - } - } -}; - -class TlsHello { - public: - struct Op { - enum class Type { String, Random, Zero, Domain, Grease, BeginScope, EndScope }; - Type type; - int length; - int seed; - std::string data; - - static Op string(Slice str) { - Op res; - res.type = Type::String; - res.data = str.str(); - return res; - } - static Op random(int length) { - Op res; - res.type = Type::Random; - res.length = length; - return res; - } - static Op zero(int length) { - Op res; - res.type = Type::Zero; - res.length = length; - return res; - } - static Op domain() { - Op res; - res.type = Type::Domain; - return res; - } - static Op grease(int seed) { - Op res; - res.type = Type::Grease; - res.seed = seed; - return res; - } - static Op begin_scope() { - Op res; - res.type = Type::BeginScope; - return res; - } - static Op end_scope() { - Op res; - res.type = Type::EndScope; - return res; - } - }; - - static const TlsHello &get_default() { - static TlsHello res = [] { - TlsHello res; - res.ops_ = { - Op::string("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"), - Op::zero(32), - Op::string("\x20"), - Op::random(32), - Op::string("\x00\x22"), - Op::grease(0), - Op::string("\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9\xcc\xa8\xc0\x13\xc0\x14\x00\x9c" - "\x00\x9d\x00\x2f\x00\x35\x00\x0a\x01\x00\x01\x91"), - Op::grease(2), - Op::string("\x00\x00\x00\x00"), - Op::begin_scope(), - Op::begin_scope(), - Op::string("\x00"), - Op::begin_scope(), - Op::domain(), - Op::end_scope(), - Op::end_scope(), - Op::end_scope(), - Op::string("\x00\x17\x00\x00\xff\x01\x00\x01\x00\x00\x0a\x00\x0a\x00\x08"), - Op::grease(4), - Op::string( - "\x00\x1d\x00\x17\x00\x18\x00\x0b\x00\x02\x01\x00\x00\x23\x00\x00\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08" - "\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x05\x00\x05\x01\x00\x00\x00\x00\x00\x0d\x00\x14\x00\x12\x04\x03\x08" - "\x04\x04\x01\x05\x03\x08\x05\x05\x01\x08\x06\x06\x01\x02\x01\x00\x12\x00\x00\x00\x33\x00\x2b\x00\x29"), - Op::grease(4), - Op::string("\x00\x01\x00\x00\x1d\x00\x20"), - Op::random(32), - Op::string("\x00\x2d\x00\x02\x01\x01\x00\x2b\x00\x0b\x0a"), - Op::grease(6), - Op::string("\x03\x04\x03\x03\x03\x02\x03\x01\x00\x1b\x00\x03\x02\x00\x02"), - Op::grease(3), - Op::string("\x00\x01\x00\x00\x15")}; - return res; - }(); - return res; - } - Span get_ops() const { - return ops_; - } - - private: - std::vector ops_; -}; - -class TlsHelloContext { - public: - explicit TlsHelloContext(std::string domain) { - Grease::init(MutableSlice(grease_.data(), grease_.size())); - domain_ = std::move(domain); - } - char get_grease(size_t i) const { - CHECK(i < grease_.size()); - return grease_[i]; - } - size_t grease_size() const { - return grease_.size(); - } - Slice get_domain() const { - return domain_; - } - - private: - constexpr static size_t MAX_GREASE = 8; - std::array grease_; - std::string domain_; -}; - -class TlsHelloCalcLength { - public: - void do_op(const TlsHello::Op &op, const TlsHelloContext *context) { - using Type = TlsHello::Op::Type; - switch (op.type) { - case Type::String: - size_ += op.data.size(); - break; - case Type::Random: - if (op.length <= 0 || op.length > 1024) { - on_error(Status::Error("Invalid random length")); - } - size_ += op.length; - break; - case Type::Zero: - if (op.length < 0 || op.length > 1024) { - on_error(Status::Error("Invalid zero length")); - } - size_ += op.length; - break; - case Type::Domain: - CHECK(context); - size_ += context->get_domain().size(); - break; - case Type::Grease: - CHECK(context); - if (op.seed < 0 || static_cast(op.seed) > context->grease_size()) { - on_error(Status::Error("Invalid grease seed")); - } - size_ += 2; - break; - case Type::BeginScope: - size_ += 2; - scope_offset_.push_back(size_); - break; - case Type::EndScope: - if (scope_offset_.empty()) { - on_error(Status::Error("Unbalanced scopes")); - } - auto begin_offset = scope_offset_.back(); - scope_offset_.pop_back(); - auto end_offset = size_; - auto size = end_offset - begin_offset; - if (size >= (1 << 14)) { - on_error(Status::Error("Scope is too big")); - } - break; - } - } - - Result finish() { - if (size_ > 515) { - on_error(Status::Error("Too long for zero padding")); - } - if (size_ < 11 + 32) { - on_error(Status::Error("Too small for hash")); - } - int zero_pad = 515 - static_cast(size_); - using Op = TlsHello::Op; - do_op(Op::begin_scope(), nullptr); - do_op(Op::zero(zero_pad), nullptr); - do_op(Op::end_scope(), nullptr); - if (!scope_offset_.empty()) { - on_error(Status::Error("Unbalanced scopes")); - } - TRY_STATUS(std::move(status_)); - return size_; - } - - private: - int64 size_{0}; - Status status_; - std::vector scope_offset_; - - void on_error(Status error) { - if (status_.is_ok()) { - status_ = std::move(error); - } - } -}; - -class TlsHelloStore { - public: - TlsHelloStore(MutableSlice dest) : data_(dest), dest_(dest) { - } - void do_op(const TlsHello::Op &op, TlsHelloContext *context) { - using Type = TlsHello::Op::Type; - switch (op.type) { - case Type::String: - dest_.copy_from(op.data); - dest_.remove_prefix(op.data.size()); - break; - case Type::Random: - Random::secure_bytes(dest_.substr(0, op.length)); - dest_.remove_prefix(op.length); - break; - case Type::Zero: - std::memset(dest_.begin(), 0, op.length); - dest_.remove_prefix(op.length); - break; - case Type::Domain: { - CHECK(context); - auto domain = context->get_domain(); - dest_.copy_from(domain); - dest_.remove_prefix(domain.size()); - break; - } - case Type::Grease: { - CHECK(context) - auto grease = context->get_grease(op.seed); - dest_[0] = grease; - dest_[1] = grease; - dest_.remove_prefix(2); - break; - } - case Type::BeginScope: - scope_offset_.push_back(get_offset()); - dest_.remove_prefix(2); - break; - case Type::EndScope: { - CHECK(!scope_offset_.empty()); - auto begin_offset = scope_offset_.back(); - scope_offset_.pop_back(); - auto end_offset = get_offset(); - size_t size = end_offset - begin_offset - 2; - CHECK(size < (1 << 14)); - data_[begin_offset] = static_cast((size >> 8) & 0xff); - data_[begin_offset + 1] = static_cast(size & 0xff); - break; - } - } - } - void finish(int32 unix_time) { - int zero_pad = 515 - static_cast(get_offset()); - using Op = TlsHello::Op; - do_op(Op::begin_scope(), nullptr); - do_op(Op::zero(zero_pad), nullptr); - do_op(Op::end_scope(), nullptr); - - auto tmp = sha256(data_); - auto hash_dest = data_.substr(11); - hash_dest.copy_from(tmp); - int32 old = as(hash_dest.substr(28).data()); - as(hash_dest.substr(28).data()) = old ^ unix_time; - CHECK(dest_.empty()); - } - - private: - MutableSlice data_; - MutableSlice dest_; - std::vector scope_offset_; - size_t get_offset() { - return data_.size() - dest_.size(); - } -}; - -class TlsObfusaction { - public: - static std::string generate_header(std::string domain, int32 unix_time) { - auto &hello = TlsHello::get_default(); - TlsHelloContext context(domain); - TlsHelloCalcLength calc_length; - for (auto &op : hello.get_ops()) { - calc_length.do_op(op, &context); - } - auto length = calc_length.finish().move_as_ok(); - std::string data(length, 0); - TlsHelloStore storer(data); - for (auto &op : hello.get_ops()) { - storer.do_op(op, &context); - } - storer.finish(0); - return data; - } -}; - -class TlsInit : public TransparentProxy { - public: - using TransparentProxy::TransparentProxy; - - private: - enum class State { - SendHello, - WaitHelloResponse, - } state_ = State::SendHello; - - void send_hello() { - auto hello = TlsObfusaction::generate_header(username_, 0); - fd_.output_buffer().append(hello); - state_ = State::WaitHelloResponse; - } - - Status wait_hello_response() { - //[ - auto it = fd_.input_buffer().clone(); - //S "\x16\x03\x03" - { - Slice first = "\x16\x03\x03"; - std::string got_first(first.size(), 0); - if (it.size() < first.size()) { - return td::Status::OK(); - } - it.advance(first.size(), got_first); - if (first != got_first) { - return Status::Error("First part of response to hello is invalid"); - } - } - - //[ - { - if (it.size() < 2) { - return td::Status::OK(); - } - uint8 tmp[2]; - it.advance(2, MutableSlice(tmp, 2)); - size_t skip_size = (tmp[0] << 8) + tmp[1]; - if (it.size() < skip_size) { - return td::Status::OK(); - } - it.advance(skip_size); - } - - //S "\x14\x03\x03\x00\x01\x01\x17\x03\x03" - { - Slice first = "\x14\x03\x03\x00\x01\x01\x17\x03\x03"; - std::string got_first(first.size(), 0); - if (it.size() < first.size()) { - return td::Status::OK(); - } - it.advance(first.size(), got_first); - if (first != got_first) { - return Status::Error("Second part of response to hello is invalid"); - } - } - - //[ - { - if (it.size() < 2) { - return td::Status::OK(); - } - uint8 tmp[2]; - it.advance(2, MutableSlice(tmp, 2)); - size_t skip_size = (tmp[0] << 8) + tmp[1]; - if (it.size() < skip_size) { - return td::Status::OK(); - } - it.advance(skip_size); - } - fd_.input_buffer() = std::move(it); - - stop(); - return td::Status::OK(); - } - - Status loop_impl() override { - switch (state_) { - case State::SendHello: - send_hello(); - break; - case State::WaitHelloResponse: - TRY_STATUS(wait_hello_response()); - break; - } - return Status::OK(); - } -}; - TEST(Mtproto, TlsObfusaction) { std::string s(10000, 'a'); Grease::init(s);