"Fossies" - the Fresh Open Source Software Archive

Member "tdesktop-4.8.3/Telegram/SourceFiles/mtproto/details/mtproto_tls_socket.cpp" (1 Jun 2023, 24170 Bytes) of package /linux/misc/tdesktop-4.8.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "mtproto_tls_socket.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.8.1_vs_4.8.3.

    1 /*
    2 This file is part of Telegram Desktop,
    3 the official desktop application for the Telegram messaging service.
    4 
    5 For license and copyright information please follow this link:
    6 https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
    7 */
    8 #include "mtproto/details/mtproto_tls_socket.h"
    9 
   10 #include "mtproto/details/mtproto_tcp_socket.h"
   11 #include "base/openssl_help.h"
   12 #include "base/bytes.h"
   13 #include "base/invoke_queued.h"
   14 #include "base/unixtime.h"
   15 
   16 #include <QtCore/QtEndian>
   17 #include <range/v3/algorithm/reverse.hpp>
   18 
   19 namespace MTP::details {
   20 namespace {
   21 
   22 constexpr auto kMaxGrease = 8;
   23 constexpr auto kClientHelloLength = 517;
   24 constexpr auto kHelloDigestLength = 32;
   25 constexpr auto kLengthSize = sizeof(uint16);
   26 const auto kServerHelloPart1 = qstr("\x16\x03\x03");
   27 const auto kServerHelloPart3 = qstr("\x14\x03\x03\x00\x01\x01\x17\x03\x03");
   28 constexpr auto kServerHelloDigestPosition = 11;
   29 const auto kServerHeader = qstr("\x17\x03\x03");
   30 constexpr auto kClientPartSize = 2878;
   31 const auto kClientPrefix = qstr("\x14\x03\x03\x00\x01\x01");
   32 const auto kClientHeader = qstr("\x17\x03\x03");
   33 
   34 using BigNum = openssl::BigNum;
   35 using BigNumContext = openssl::Context;
   36 
   37 [[nodiscard]] MTPTlsClientHello PrepareClientHelloRules() {
   38     using Scope = QVector<MTPTlsBlock>;
   39     using Permutation = std::vector<Scope>;
   40     using StackElement = std::variant<Scope, Permutation>;
   41     auto stack = std::vector<StackElement>();
   42     const auto pushToBack = [&](MTPTlsBlock &&block) {
   43         Expects(!stack.empty());
   44 
   45         if (const auto scope = std::get_if<Scope>(&stack.back())) {
   46             scope->push_back(std::move(block));
   47         } else {
   48             auto &permutation = v::get<Permutation>(stack.back());
   49             Assert(!permutation.empty());
   50             permutation.back().push_back(std::move(block));
   51         }
   52     };
   53     const auto S = [&](QByteArray data) {
   54         pushToBack(MTP_tlsBlockString(MTP_bytes(data)));
   55     };
   56     const auto Z = [&](int length) {
   57         pushToBack(MTP_tlsBlockZero(MTP_int(length)));
   58     };
   59     const auto G = [&](int seed) {
   60         pushToBack(MTP_tlsBlockGrease(MTP_int(seed)));
   61     };
   62     const auto R = [&](int length) {
   63         pushToBack(MTP_tlsBlockRandom(MTP_int(length)));
   64     };
   65     const auto D = [&] {
   66         pushToBack(MTP_tlsBlockDomain());
   67     };
   68     const auto K = [&] {
   69         pushToBack(MTP_tlsBlockPublicKey());
   70     };
   71     const auto OpenScope = [&] {
   72         stack.emplace_back(Scope());
   73     };
   74     const auto CloseScope = [&] {
   75         Expects(stack.size() > 1);
   76         Expects(v::is<Scope>(stack.back()));
   77 
   78         const auto blocks = std::move(v::get<Scope>(stack.back()));
   79         stack.pop_back();
   80         pushToBack(MTP_tlsBlockScope(MTP_vector<MTPTlsBlock>(blocks)));
   81     };
   82     const auto OpenPermutation = [&] {
   83         stack.emplace_back(Permutation());
   84     };
   85     const auto ClosePermutation = [&] {
   86         Expects(stack.size() > 1);
   87         Expects(v::is<Permutation>(stack.back()));
   88 
   89         const auto list = std::move(v::get<Permutation>(stack.back()));
   90         stack.pop_back();
   91 
   92         const auto wrapped = list | ranges::views::transform([](
   93                 const QVector<MTPTlsBlock> &elements) {
   94             return MTP_vector<MTPTlsBlock>(elements);
   95         }) | ranges::to<QVector<MTPVector<MTPTlsBlock>>>();
   96 
   97         pushToBack(MTP_tlsBlockPermutation(
   98             MTP_vector<MTPVector<MTPTlsBlock>>(wrapped)));
   99     };
  100     const auto StartPermutationElement = [&] {
  101         Expects(stack.size() > 1);
  102         Expects(v::is<Permutation>(stack.back()));
  103 
  104         v::get<Permutation>(stack.back()).emplace_back();
  105     };
  106     const auto Finish = [&] {
  107         Expects(stack.size() == 1);
  108         Expects(v::is<Scope>(stack.back()));
  109 
  110         return v::get<Scope>(stack.back());
  111     };
  112 
  113     stack.emplace_back(Scope());
  114 
  115     S("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"_q);
  116     Z(32);
  117     S("\x20"_q);
  118     R(32);
  119     S("\x00\x20"_q);
  120     G(0);
  121     S(""
  122         "\x13\x01\x13\x02\x13\x03\xc0\x2b\xc0\x2f\xc0\x2c\xc0\x30\xcc\xa9"
  123         "\xcc\xa8\xc0\x13\xc0\x14\x00\x9c\x00\x9d\x00\x2f\x00\x35\x01\x00"
  124         "\x01\x93"_q);
  125     G(2);
  126     S("\x00\x00"_q);
  127     OpenPermutation(); {
  128         StartPermutationElement(); {
  129             S("\x00\x00"_q);
  130             OpenScope();
  131             OpenScope();
  132             S("\x00"_q);
  133             OpenScope();
  134             D();
  135             CloseScope();
  136             CloseScope();
  137             CloseScope();
  138         }
  139         StartPermutationElement(); {
  140             S("\x00\x05\x00\x05\x01\x00\x00\x00\x00"_q);
  141         }
  142         StartPermutationElement(); {
  143             S("\x00\x0a\x00\x0a\x00\x08"_q);
  144             G(4);
  145             S("\x00\x1d\x00\x17\x00\x18"_q);
  146         }
  147         StartPermutationElement(); {
  148             S("\x00\x0b\x00\x02\x01\x00"_q);
  149         }
  150         StartPermutationElement(); {
  151             S(""
  152                 "\x00\x0d\x00\x12\x00\x10\x04\x03\x08\x04\x04\x01\x05\x03"
  153                 "\x08\x05\x05\x01\x08\x06\x06\x01"_q);
  154         }
  155         StartPermutationElement(); {
  156             S(""
  157                 "\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08\x68\x74\x74\x70"
  158                 "\x2f\x31\x2e\x31"_q);
  159         }
  160         StartPermutationElement(); {
  161             S("\x00\x12\x00\x00"_q);
  162         }
  163         StartPermutationElement(); {
  164             S("\x00\x17\x00\x00"_q);
  165         }
  166         StartPermutationElement(); {
  167             S("\x00\x1b\x00\x03\x02\x00\x02"_q);
  168         }
  169         StartPermutationElement(); {
  170             S("\x00\x23\x00\x00"_q);
  171         }
  172         StartPermutationElement(); {
  173             S("\x00\x2b\x00\x07\x06"_q);
  174             G(6);
  175             S("\x03\x04\x03\x03"_q);
  176         }
  177         StartPermutationElement(); {
  178             S("\x00\x2d\x00\x02\x01\x01"_q);
  179         }
  180         StartPermutationElement(); {
  181             S("\x00\x33\x00\x2b\x00\x29"_q);
  182             G(4);
  183             S("\x00\x01\x00\x00\x1d\x00\x20"_q);
  184             K();
  185         }
  186         StartPermutationElement(); {
  187             S("\x44\x69\x00\x05\x00\x03\x02\x68\x32"_q);
  188         }
  189         StartPermutationElement(); {
  190             S("\xff\x01\x00\x01\x00"_q);
  191         }
  192     } ClosePermutation();
  193     G(3);
  194     S("\x00\x01\x00\x00\x15"_q);
  195 
  196     return MTP_tlsClientHello(MTP_vector<MTPTlsBlock>(Finish()));
  197 }
  198 
  199 [[nodiscard]] bytes::vector PrepareGreases() {
  200     auto result = bytes::vector(kMaxGrease);
  201     bytes::set_random(result);
  202     for (auto &byte : result) {
  203         byte = bytes::type((uchar(byte) & 0xF0) + 0x0A);
  204     }
  205     static_assert(kMaxGrease % 2 == 0);
  206     for (auto i = 0; i != kMaxGrease; i += 2) {
  207         if (result[i] == result[i + 1]) {
  208             result[i + 1] = bytes::type(uchar(result[i + 1]) ^ 0x10);
  209         }
  210     }
  211     return result;
  212 }
  213 
  214 // Returns y^2 = x^3 + 486662 * x^2 + x.
  215 [[nodiscard]] BigNum GenerateY2(
  216         const BigNum &x,
  217         const BigNum &mod,
  218         const BigNumContext &context) {
  219     auto coef = BigNum(486662);
  220     auto y = BigNum::ModAdd(x, coef, mod, context);
  221     y.setModMul(y, x, mod, context);
  222     coef.setWord(1);
  223     y.setModAdd(y, coef, mod, context);
  224     return BigNum::ModMul(y, x, mod, context);
  225 }
  226 
  227 // Returns x_2 = (x^2 - 1)^2/(4*y^2).
  228 [[nodiscard]] BigNum GenerateX2(
  229         const BigNum &x,
  230         const BigNum &mod,
  231         const BigNumContext &context) {
  232     auto denominator = GenerateY2(x, mod, context);
  233     auto coef = BigNum(4);
  234     denominator.setModMul(denominator, coef, mod, context);
  235 
  236     auto numerator = BigNum::ModMul(x, x, mod, context);
  237     coef.setWord(1);
  238     numerator.setModSub(numerator, coef, mod, context);
  239     numerator.setModMul(numerator, numerator, mod, context);
  240 
  241     denominator.setModInverse(denominator, mod, context);
  242     return BigNum::ModMul(numerator, denominator, mod, context);
  243 }
  244 
  245 [[nodiscard]] bytes::vector GeneratePublicKey() {
  246     const auto context = BigNumContext();
  247     const char modBytes[] = ""
  248         "\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
  249         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xed";
  250     const char powBytes[] = ""
  251         "\x3f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
  252         "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf6";
  253     const auto mod = BigNum(bytes::make_span(modBytes).subspan(0, 32));
  254     const auto pow = BigNum(bytes::make_span(powBytes).subspan(0, 32));
  255 
  256     auto x = BigNum();
  257     do {
  258         while (true) {
  259             auto random = bytes::vector(32);
  260             bytes::set_random(random);
  261             random[31] &= bytes::type(0x7FU);
  262             x.setBytes(random);
  263             x.setModMul(x, x, mod, context);
  264 
  265             auto y = GenerateY2(x, mod, context);
  266             if (BigNum::ModExp(y, pow, mod, context).isOne()) {
  267                 break;
  268             }
  269         }
  270         for (auto i = 0; i != 3; ++i) {
  271             x = GenerateX2(x, mod, context);
  272         }
  273         const auto xBytes = x.getBytes();
  274         Assert(!xBytes.empty());
  275         Assert(xBytes.size() <= 32);
  276     } while (x.bytesSize() == 32);
  277 
  278     const auto xBytes = x.getBytes();
  279     auto result = bytes::vector(32, bytes::type());
  280     bytes::copy(
  281         bytes::make_span(result).subspan(32 - xBytes.size()),
  282         xBytes);
  283     ranges::reverse(result);
  284 
  285     //auto string = QString();
  286     //string.reserve(64);
  287     //for (const auto byte : result) {
  288     //  const auto code = uchar(byte);
  289     //  const auto hex = [](uchar value) -> char {
  290     //      if (value >= 0 && value <= 9) {
  291     //          return '0' + value;
  292     //      } else if (value >= 10 && value <= 15) {
  293     //          return 'a' + (value - 10);
  294     //      }
  295     //      return '-';
  296     //  };
  297     //  string.append(hex(code / 16)).append(hex(code % 16));
  298     //}
  299     //LOG(("KEY: %1").arg(string));
  300 
  301     return result;
  302 }
  303 
  304 struct ClientHello {
  305     QByteArray data;
  306     QByteArray digest;
  307 };
  308 
  309 class Generator {
  310 public:
  311     Generator(
  312         const MTPTlsClientHello &rules,
  313         bytes::const_span domain,
  314         bytes::const_span key);
  315     [[nodiscard]] ClientHello take();
  316 
  317 private:
  318     class Part final {
  319     public:
  320         explicit Part(
  321             bytes::const_span domain,
  322             const bytes::vector &greases);
  323 
  324         [[nodiscard]] bytes::span grow(int size);
  325         void writeBlocks(const QVector<MTPTlsBlock> &blocks);
  326         void writeBlock(const MTPTlsBlock &data);
  327         void writeBlock(const MTPDtlsBlockString &data);
  328         void writeBlock(const MTPDtlsBlockZero &data);
  329         void writeBlock(const MTPDtlsBlockGrease &data);
  330         void writeBlock(const MTPDtlsBlockRandom &data);
  331         void writeBlock(const MTPDtlsBlockDomain &data);
  332         void writeBlock(const MTPDtlsBlockPublicKey &data);
  333         void writeBlock(const MTPDtlsBlockScope &data);
  334         void writeBlock(const MTPDtlsBlockPermutation &data);
  335         void finalize(bytes::const_span key);
  336         [[nodiscard]] QByteArray extractDigest() const;
  337 
  338         [[nodiscard]] bool error() const;
  339         [[nodiscard]] QByteArray take();
  340 
  341     private:
  342         void writePadding();
  343         void writeDigest(bytes::const_span key);
  344         void injectTimestamp();
  345 
  346         bytes::const_span _domain;
  347         const bytes::vector &_greases;
  348         QByteArray _result;
  349         const char *_data = nullptr;
  350         int _digestPosition = -1;
  351         bool _error = false;
  352 
  353     };
  354 
  355     bytes::vector _greases;
  356     Part _result;
  357     QByteArray _digest;
  358 
  359 };
  360 
  361 Generator::Part::Part(
  362     bytes::const_span domain,
  363     const bytes::vector &greases)
  364 : _domain(domain)
  365 , _greases(greases) {
  366     _result.reserve(kClientHelloLength);
  367     _data = _result.constData();
  368 }
  369 
  370 bool Generator::Part::error() const {
  371     return _error;
  372 }
  373 
  374 QByteArray Generator::Part::take() {
  375     Expects(_error || _result.constData() == _data);
  376 
  377     return _error ? QByteArray() : std::move(_result);
  378 }
  379 
  380 bytes::span Generator::Part::grow(int size) {
  381     if (_error
  382         || size <= 0
  383         || _result.size() + size > kClientHelloLength) {
  384         _error = true;
  385         return bytes::span();
  386     }
  387 
  388     const auto offset = _result.size();
  389     _result.resize(offset + size);
  390     return bytes::make_detached_span(_result).subspan(offset);
  391 }
  392 
  393 void Generator::Part::writeBlocks(const QVector<MTPTlsBlock> &blocks) {
  394     for (const auto &block : blocks) {
  395         writeBlock(block);
  396     }
  397 }
  398 
  399 void Generator::Part::writeBlock(const MTPTlsBlock &data) {
  400     data.match([&](const auto &data) {
  401         writeBlock(data);
  402     });
  403 }
  404 
  405 void Generator::Part::writeBlock(const MTPDtlsBlockString &data) {
  406     const auto &bytes = data.vdata().v;
  407     const auto storage = grow(bytes.size());
  408     if (storage.empty()) {
  409         return;
  410     }
  411     bytes::copy(storage, bytes::make_span(bytes));
  412 }
  413 
  414 void Generator::Part::writeBlock(const MTPDtlsBlockZero &data) {
  415     const auto length = data.vlength().v;
  416     const auto already = _result.size();
  417     const auto storage = grow(length);
  418     if (storage.empty()) {
  419         return;
  420     }
  421     if (length == kHelloDigestLength && _digestPosition < 0) {
  422         _digestPosition = already;
  423     }
  424     bytes::set_with_const(storage, bytes::type(0));
  425 }
  426 
  427 void Generator::Part::writeBlock(const MTPDtlsBlockGrease &data) {
  428     const auto seed = data.vseed().v;
  429     if (seed < 0 || seed >= _greases.size()) {
  430         _error = true;
  431         return;
  432     }
  433     const auto storage = grow(2);
  434     if (storage.empty()) {
  435         return;
  436     }
  437     bytes::set_with_const(storage, _greases[seed]);
  438 }
  439 
  440 void Generator::Part::writeBlock(const MTPDtlsBlockRandom &data) {
  441     const auto length = data.vlength().v;
  442     const auto storage = grow(length);
  443     if (storage.empty()) {
  444         return;
  445     }
  446     bytes::set_random(storage);
  447 }
  448 
  449 void Generator::Part::writeBlock(const MTPDtlsBlockDomain &data) {
  450     const auto storage = grow(_domain.size());
  451     if (storage.empty()) {
  452         return;
  453     }
  454     bytes::copy(storage, _domain);
  455 }
  456 
  457 void Generator::Part::writeBlock(const MTPDtlsBlockPublicKey &data) {
  458     const auto key = GeneratePublicKey();
  459     const auto storage = grow(key.size());
  460     if (storage.empty()) {
  461         return;
  462     }
  463     bytes::copy(storage, key);
  464 }
  465 
  466 void Generator::Part::writeBlock(const MTPDtlsBlockScope &data) {
  467     const auto storage = grow(kLengthSize);
  468     if (storage.empty()) {
  469         return;
  470     }
  471     const auto already = _result.size();
  472     writeBlocks(data.ventries().v);
  473     const auto length = qToBigEndian(uint16(_result.size() - already));
  474     bytes::copy(storage, bytes::object_as_span(&length));
  475 }
  476 
  477 void Generator::Part::writeBlock(const MTPDtlsBlockPermutation &data) {
  478     auto list = std::vector<QByteArray>();
  479     list.reserve(data.ventries().v.size());
  480     for (const auto &inner : data.ventries().v) {
  481         auto part = Part(_domain, _greases);
  482         part.writeBlocks(inner.v);
  483         if (part.error()) {
  484             _error = true;
  485             return;
  486         }
  487         list.push_back(part.take());
  488     }
  489     ranges::shuffle(list);
  490     for (const auto &element : list) {
  491         const auto storage = grow(element.size());
  492         if (storage.empty()) {
  493             return;
  494         }
  495         bytes::copy(storage, bytes::make_span(element));
  496     }
  497 }
  498 
  499 void Generator::Part::finalize(bytes::const_span key) {
  500     if (_error) {
  501         return;
  502     } else if (_digestPosition < 0) {
  503         _error = true;
  504         return;
  505     }
  506     writePadding();
  507     writeDigest(key);
  508     injectTimestamp();
  509 }
  510 
  511 QByteArray Generator::Part::extractDigest() const {
  512     if (_digestPosition < 0) {
  513         return {};
  514     }
  515     return _result.mid(_digestPosition, kHelloDigestLength);
  516 }
  517 
  518 void Generator::Part::writePadding() {
  519     Expects(_result.size() <= kClientHelloLength - kLengthSize);
  520 
  521     const auto padding = kClientHelloLength - kLengthSize - _result.size();
  522     writeBlock(MTP_tlsBlockScope(
  523         MTP_vector<MTPTlsBlock>(1, MTP_tlsBlockZero(MTP_int(padding)))));
  524 }
  525 
  526 void Generator::Part::writeDigest(bytes::const_span key) {
  527     Expects(_digestPosition >= 0);
  528 
  529     bytes::copy(
  530         bytes::make_detached_span(_result).subspan(_digestPosition),
  531         openssl::HmacSha256(key, bytes::make_span(_result)));
  532 }
  533 
  534 void Generator::Part::injectTimestamp() {
  535     Expects(_digestPosition >= 0);
  536 
  537     const auto storage = bytes::make_detached_span(_result).subspan(
  538         _digestPosition + kHelloDigestLength - sizeof(int32),
  539         sizeof(int32));
  540     auto already = int32();
  541     bytes::copy(bytes::object_as_span(&already), storage);
  542     already ^= qToLittleEndian(int32(base::unixtime::http_now()));
  543     bytes::copy(storage, bytes::object_as_span(&already));
  544 }
  545 
  546 Generator::Generator(
  547     const MTPTlsClientHello &rules,
  548     bytes::const_span domain,
  549     bytes::const_span key)
  550 : _greases(PrepareGreases())
  551 , _result(domain, _greases) {
  552     _result.writeBlocks(rules.match([&](const MTPDtlsClientHello &data) {
  553         return data.vblocks().v;
  554     }));
  555     _result.finalize(key);
  556 }
  557 
  558 ClientHello Generator::take() {
  559     auto digest = _result.extractDigest();
  560     return { _result.take(), std::move(digest) };
  561 }
  562 
  563 [[nodiscard]] ClientHello PrepareClientHello(
  564         const MTPTlsClientHello &rules,
  565         bytes::const_span domain,
  566         bytes::const_span key) {
  567     return Generator(rules, domain, key).take();
  568 }
  569 
  570 [[nodiscard]] bool CheckPart(bytes::const_span data, QLatin1String check) {
  571     if (data.size() < check.size()) {
  572         return false;
  573     }
  574     return !bytes::compare(
  575         data.subspan(0, check.size()),
  576         bytes::make_span(check.data(), check.size()));
  577 }
  578 
  579 [[nodiscard]] int ReadPartLength(bytes::const_span data, int offset) {
  580     const auto storage = data.subspan(offset, kLengthSize);
  581     return qFromBigEndian(
  582         *reinterpret_cast<const uint16*>(storage.data()));
  583 }
  584 
  585 } // namespace
  586 
  587 TlsSocket::TlsSocket(
  588     not_null<QThread*> thread,
  589     const bytes::vector &secret,
  590     const QNetworkProxy &proxy,
  591     bool protocolForFiles)
  592 : AbstractSocket(thread)
  593 , _secret(secret) {
  594     Expects(_secret.size() >= 21 && _secret[0] == bytes::type(0xEE));
  595 
  596     _socket.moveToThread(thread);
  597     _socket.setProxy(proxy);
  598     if (protocolForFiles) {
  599         _socket.setSocketOption(
  600             QAbstractSocket::SendBufferSizeSocketOption,
  601             kFilesSendBufferSize);
  602         _socket.setSocketOption(
  603             QAbstractSocket::ReceiveBufferSizeSocketOption,
  604             kFilesReceiveBufferSize);
  605     }
  606     const auto wrap = [&](auto handler) {
  607         return [=](auto &&...args) {
  608             InvokeQueued(this, [=] { handler(args...); });
  609         };
  610     };
  611     using Error = QAbstractSocket::SocketError;
  612     connect(
  613         &_socket,
  614         &QTcpSocket::connected,
  615         wrap([=] { plainConnected(); }));
  616     connect(
  617         &_socket,
  618         &QTcpSocket::disconnected,
  619         wrap([=] { plainDisconnected(); }));
  620     connect(
  621         &_socket,
  622         &QTcpSocket::readyRead,
  623         wrap([=] { plainReadyRead(); }));
  624     connect(
  625         &_socket,
  626         &QAbstractSocket::errorOccurred,
  627         wrap([=](Error e) { handleError(e); }));
  628 }
  629 
  630 bytes::const_span TlsSocket::domainFromSecret() const {
  631     return bytes::make_span(_secret).subspan(17);
  632 }
  633 
  634 bytes::const_span TlsSocket::keyFromSecret() const {
  635     return bytes::make_span(_secret).subspan(1, 16);
  636 }
  637 
  638 void TlsSocket::plainConnected() {
  639     if (_state != State::Connecting) {
  640         return;
  641     }
  642 
  643     static const auto kClientHelloRules = PrepareClientHelloRules();
  644     const auto hello = PrepareClientHello(
  645         kClientHelloRules,
  646         domainFromSecret(),
  647         keyFromSecret());
  648     if (hello.data.isEmpty()) {
  649         logError(888, "Could not generate Client Hello.");
  650         _state = State::Error;
  651         _error.fire({});
  652     } else {
  653         _state = State::WaitingHello;
  654         _incoming = hello.digest;
  655         _socket.write(hello.data);
  656     }
  657 }
  658 
  659 void TlsSocket::plainDisconnected() {
  660     _state = State::NotConnected;
  661     _incoming = QByteArray();
  662     _serverHelloLength = 0;
  663     _incomingGoodDataOffset = 0;
  664     _incomingGoodDataLimit = 0;
  665     _disconnected.fire({});
  666 }
  667 
  668 void TlsSocket::plainReadyRead() {
  669     switch (_state) {
  670     case State::WaitingHello: return readHello();
  671     case State::Connected: return readData();
  672     }
  673 }
  674 
  675 bool TlsSocket::requiredHelloPartReady() const {
  676     return _incoming.size() >= kHelloDigestLength + _serverHelloLength;
  677 }
  678 
  679 void TlsSocket::readHello() {
  680     const auto parts1Size = kServerHelloPart1.size() + kLengthSize;
  681     if (!_serverHelloLength) {
  682         _serverHelloLength = parts1Size;
  683     }
  684     while (!requiredHelloPartReady()) {
  685         if (!_socket.bytesAvailable()) {
  686             return;
  687         }
  688         _incoming.append(_socket.readAll());
  689     }
  690     checkHelloParts12(parts1Size);
  691 }
  692 
  693 void TlsSocket::checkHelloParts12(int parts1Size) {
  694     const auto data = bytes::make_span(_incoming).subspan(
  695         kHelloDigestLength,
  696         parts1Size);
  697     const auto part2Size = ReadPartLength(data, parts1Size - kLengthSize);
  698     const auto parts123Size = parts1Size
  699         + part2Size
  700         + kServerHelloPart3.size()
  701         + kLengthSize;
  702     if (_serverHelloLength == parts1Size) {
  703         const auto part1Offset = parts1Size
  704             - kLengthSize
  705             - kServerHelloPart1.size();
  706         if (!CheckPart(data.subspan(part1Offset), kServerHelloPart1)) {
  707             logError(888, "Bad Server Hello part1.");
  708             handleError();
  709             return;
  710         }
  711         _serverHelloLength = parts123Size;
  712         if (!requiredHelloPartReady()) {
  713             readHello();
  714             return;
  715         }
  716     }
  717     checkHelloParts34(parts123Size);
  718 }
  719 
  720 void TlsSocket::checkHelloParts34(int parts123Size) {
  721     const auto data = bytes::make_span(_incoming).subspan(
  722         kHelloDigestLength,
  723         parts123Size);
  724     const auto part4Size = ReadPartLength(data, parts123Size - kLengthSize);
  725     const auto full = parts123Size + part4Size;
  726     if (_serverHelloLength == parts123Size) {
  727         const auto part3Offset = parts123Size
  728             - kLengthSize
  729             - kServerHelloPart3.size();
  730         if (!CheckPart(data.subspan(part3Offset), kServerHelloPart3)) {
  731             logError(888, "Bad Server Hello part.");
  732             handleError();
  733             return;
  734         }
  735         _serverHelloLength = full;
  736         if (!requiredHelloPartReady()) {
  737             readHello();
  738             return;
  739         }
  740     }
  741     checkHelloDigest();
  742 }
  743 
  744 void TlsSocket::checkHelloDigest() {
  745     const auto fulldata = bytes::make_detached_span(_incoming).subspan(
  746         0,
  747         kHelloDigestLength + _serverHelloLength);
  748     const auto digest = fulldata.subspan(
  749         kHelloDigestLength + kServerHelloDigestPosition,
  750         kHelloDigestLength);
  751     const auto digestCopy = bytes::make_vector(digest);
  752     bytes::set_with_const(digest, bytes::type(0));
  753     const auto check = openssl::HmacSha256(keyFromSecret(), fulldata);
  754     if (bytes::compare(digestCopy, check) != 0) {
  755         logError(888, "Bad Server Hello digest.");
  756         handleError();
  757         return;
  758     }
  759     shiftIncomingBy(fulldata.size());
  760     if (!_incoming.isEmpty()) {
  761         InvokeQueued(this, [=] {
  762             if (!checkNextPacket()) {
  763                 handleError();
  764             }
  765         });
  766     }
  767     _incomingGoodDataOffset = _incomingGoodDataLimit = 0;
  768     _state = State::Connected;
  769     _connected.fire({});
  770 }
  771 
  772 void TlsSocket::readData() {
  773     if (!isConnected()) {
  774         return;
  775     }
  776     _incoming.append(_socket.readAll());
  777     if (!checkNextPacket()) {
  778         handleError();
  779     } else if (hasBytesAvailable()) {
  780         _readyRead.fire({});
  781     }
  782 }
  783 
  784 bool TlsSocket::checkNextPacket() {
  785     auto offset = 0;
  786     const auto incoming = bytes::make_span(_incoming);
  787     while (!_incomingGoodDataLimit) {
  788         const auto fullHeader = kServerHeader.size() + kLengthSize;
  789         if (incoming.size() <= offset + fullHeader) {
  790             return true;
  791         }
  792         if (!CheckPart(incoming.subspan(offset), kServerHeader)) {
  793             logError(888, "Bad packet header.");
  794             return false;
  795         }
  796         const auto length = ReadPartLength(
  797             incoming,
  798             offset + kServerHeader.size());
  799         if (length > 0) {
  800             if (offset > 0) {
  801                 shiftIncomingBy(offset);
  802             }
  803             _incomingGoodDataOffset = fullHeader;
  804             _incomingGoodDataLimit = length;
  805         } else {
  806             offset += kServerHeader.size() + kLengthSize + length;
  807         }
  808     }
  809     return true;
  810 }
  811 
  812 void TlsSocket::shiftIncomingBy(int amount) {
  813     Expects(_incomingGoodDataOffset == 0);
  814     Expects(_incomingGoodDataLimit == 0);
  815 
  816     const auto incoming = bytes::make_detached_span(_incoming);
  817     if (incoming.size() > amount) {
  818         bytes::move(incoming, incoming.subspan(amount));
  819         _incoming.chop(amount);
  820     } else {
  821         _incoming.clear();
  822     }
  823 }
  824 
  825 void TlsSocket::connectToHost(const QString &address, int port) {
  826     Expects(_state == State::NotConnected);
  827 
  828     _state = State::Connecting;
  829     _socket.connectToHost(address, port);
  830 }
  831 
  832 bool TlsSocket::isGoodStartNonce(bytes::const_span nonce) {
  833     return true;
  834 }
  835 
  836 void TlsSocket::timedOut() {
  837     _syncTimeRequests.fire({});
  838 }
  839 
  840 bool TlsSocket::isConnected() {
  841     return (_state == State::Connected);
  842 }
  843 
  844 bool TlsSocket::hasBytesAvailable() {
  845     return (_incomingGoodDataLimit > 0)
  846         && (_incomingGoodDataOffset < _incoming.size());
  847 }
  848 
  849 int64 TlsSocket::read(bytes::span buffer) {
  850     auto written = int64(0);
  851     while (_incomingGoodDataLimit) {
  852         const auto available = std::min(
  853             _incomingGoodDataLimit,
  854             int(_incoming.size()) - _incomingGoodDataOffset);
  855         if (available <= 0) {
  856             return written;
  857         }
  858         const auto write = std::min(std::size_t(available), buffer.size());
  859         if (write <= 0) {
  860             return written;
  861         }
  862         bytes::copy(
  863             buffer,
  864             bytes::make_span(_incoming).subspan(
  865                 _incomingGoodDataOffset,
  866                 write));
  867         written += write;
  868         buffer = buffer.subspan(write);
  869         _incomingGoodDataLimit -= write;
  870         _incomingGoodDataOffset += write;
  871         if (_incomingGoodDataLimit) {
  872             return written;
  873         }
  874         shiftIncomingBy(base::take(_incomingGoodDataOffset));
  875         if (!checkNextPacket()) {
  876             _state = State::Error;
  877             InvokeQueued(this, [=] { handleError(); });
  878             return written;
  879         }
  880     }
  881     return written;
  882 }
  883 
  884 void TlsSocket::write(bytes::const_span prefix, bytes::const_span buffer) {
  885     Expects(!buffer.empty());
  886 
  887     if (!isConnected()) {
  888         return;
  889     }
  890     if (!prefix.empty()) {
  891         _socket.write(kClientPrefix.data(), kClientPrefix.size());
  892     }
  893     while (!buffer.empty()) {
  894         const auto write = std::min(
  895             kClientPartSize - prefix.size(),
  896             buffer.size());
  897         _socket.write(kClientHeader.data(), kClientHeader.size());
  898         const auto size = qToBigEndian(uint16(prefix.size() + write));
  899         _socket.write(reinterpret_cast<const char*>(&size), sizeof(size));
  900         if (!prefix.empty()) {
  901             _socket.write(
  902                 reinterpret_cast<const char*>(prefix.data()),
  903                 prefix.size());
  904             prefix = bytes::const_span();
  905         }
  906         _socket.write(
  907             reinterpret_cast<const char*>(buffer.data()),
  908             write);
  909         buffer = buffer.subspan(write);
  910     }
  911 }
  912 
  913 int32 TlsSocket::debugState() {
  914     return _socket.state();
  915 }
  916 
  917 QString TlsSocket::debugPostfix() const {
  918     return u"_ee"_q;
  919 }
  920 
  921 void TlsSocket::handleError(int errorCode) {
  922     if (_state != State::Connected) {
  923         _syncTimeRequests.fire({});
  924     }
  925     if (errorCode) {
  926         logError(errorCode, _socket.errorString());
  927     }
  928     _state = State::Error;
  929     _error.fire({});
  930 }
  931 
  932 } // namespace MTP::details