| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932 |
- /*
- This file is part of Telegram Desktop,
- the official desktop application for the Telegram messaging service.
- For license and copyright information please follow this link:
- https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
- */
- #include "mtproto/details/mtproto_tls_socket.h"
- #include "mtproto/details/mtproto_tcp_socket.h"
- #include "base/openssl_help.h"
- #include "base/bytes.h"
- #include "base/invoke_queued.h"
- #include "base/unixtime.h"
- #include <QtCore/QtEndian>
- #include <range/v3/algorithm/reverse.hpp>
- namespace MTP::details {
- namespace {
- constexpr auto kMaxGrease = 8;
- constexpr auto kClientHelloLength = 517;
- constexpr auto kHelloDigestLength = 32;
- constexpr auto kLengthSize = sizeof(uint16);
- const auto kServerHelloPart1 = qstr("\x16\x03\x03");
- const auto kServerHelloPart3 = qstr("\x14\x03\x03\x00\x01\x01\x17\x03\x03");
- constexpr auto kServerHelloDigestPosition = 11;
- const auto kServerHeader = qstr("\x17\x03\x03");
- constexpr auto kClientPartSize = 2878;
- const auto kClientPrefix = qstr("\x14\x03\x03\x00\x01\x01");
- const auto kClientHeader = qstr("\x17\x03\x03");
- using BigNum = openssl::BigNum;
- using BigNumContext = openssl::Context;
- [[nodiscard]] MTPTlsClientHello PrepareClientHelloRules() {
- using Scope = QVector<MTPTlsBlock>;
- using Permutation = std::vector<Scope>;
- using StackElement = std::variant<Scope, Permutation>;
- auto stack = std::vector<StackElement>();
- const auto pushToBack = [&](MTPTlsBlock &&block) {
- Expects(!stack.empty());
- if (const auto scope = std::get_if<Scope>(&stack.back())) {
- scope->push_back(std::move(block));
- } else {
- auto &permutation = v::get<Permutation>(stack.back());
- Assert(!permutation.empty());
- permutation.back().push_back(std::move(block));
- }
- };
- const auto S = [&](QByteArray data) {
- pushToBack(MTP_tlsBlockString(MTP_bytes(data)));
- };
- const auto Z = [&](int length) {
- pushToBack(MTP_tlsBlockZero(MTP_int(length)));
- };
- const auto G = [&](int seed) {
- pushToBack(MTP_tlsBlockGrease(MTP_int(seed)));
- };
- const auto R = [&](int length) {
- pushToBack(MTP_tlsBlockRandom(MTP_int(length)));
- };
- const auto D = [&] {
- pushToBack(MTP_tlsBlockDomain());
- };
- const auto K = [&] {
- pushToBack(MTP_tlsBlockPublicKey());
- };
- const auto OpenScope = [&] {
- stack.emplace_back(Scope());
- };
- const auto CloseScope = [&] {
- Expects(stack.size() > 1);
- Expects(v::is<Scope>(stack.back()));
- const auto blocks = std::move(v::get<Scope>(stack.back()));
- stack.pop_back();
- pushToBack(MTP_tlsBlockScope(MTP_vector<MTPTlsBlock>(blocks)));
- };
- const auto OpenPermutation = [&] {
- stack.emplace_back(Permutation());
- };
- const auto ClosePermutation = [&] {
- Expects(stack.size() > 1);
- Expects(v::is<Permutation>(stack.back()));
- const auto list = std::move(v::get<Permutation>(stack.back()));
- stack.pop_back();
- const auto wrapped = list | ranges::views::transform([](
- const QVector<MTPTlsBlock> &elements) {
- return MTP_vector<MTPTlsBlock>(elements);
- }) | ranges::to<QVector<MTPVector<MTPTlsBlock>>>();
- pushToBack(MTP_tlsBlockPermutation(
- MTP_vector<MTPVector<MTPTlsBlock>>(wrapped)));
- };
- const auto StartPermutationElement = [&] {
- Expects(stack.size() > 1);
- Expects(v::is<Permutation>(stack.back()));
- v::get<Permutation>(stack.back()).emplace_back();
- };
- const auto Finish = [&] {
- Expects(stack.size() == 1);
- Expects(v::is<Scope>(stack.back()));
- return v::get<Scope>(stack.back());
- };
- stack.emplace_back(Scope());
- S("\x16\x03\x01\x02\x00\x01\x00\x01\xfc\x03\x03"_q);
- Z(32);
- S("\x20"_q);
- R(32);
- S("\x00\x20"_q);
- G(0);
- S(""
- "\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\x01\x00"
- "\x01\x93"_q);
- G(2);
- S("\x00\x00"_q);
- OpenPermutation(); {
- StartPermutationElement(); {
- S("\x00\x00"_q);
- OpenScope();
- OpenScope();
- S("\x00"_q);
- OpenScope();
- D();
- CloseScope();
- CloseScope();
- CloseScope();
- }
- StartPermutationElement(); {
- S("\x00\x05\x00\x05\x01\x00\x00\x00\x00"_q);
- }
- StartPermutationElement(); {
- S("\x00\x0a\x00\x0a\x00\x08"_q);
- G(4);
- S("\x00\x1d\x00\x17\x00\x18"_q);
- }
- StartPermutationElement(); {
- S("\x00\x0b\x00\x02\x01\x00"_q);
- }
- StartPermutationElement(); {
- S(""
- "\x00\x0d\x00\x12\x00\x10\x04\x03\x08\x04\x04\x01\x05\x03"
- "\x08\x05\x05\x01\x08\x06\x06\x01"_q);
- }
- StartPermutationElement(); {
- S(""
- "\x00\x10\x00\x0e\x00\x0c\x02\x68\x32\x08\x68\x74\x74\x70"
- "\x2f\x31\x2e\x31"_q);
- }
- StartPermutationElement(); {
- S("\x00\x12\x00\x00"_q);
- }
- StartPermutationElement(); {
- S("\x00\x17\x00\x00"_q);
- }
- StartPermutationElement(); {
- S("\x00\x1b\x00\x03\x02\x00\x02"_q);
- }
- StartPermutationElement(); {
- S("\x00\x23\x00\x00"_q);
- }
- StartPermutationElement(); {
- S("\x00\x2b\x00\x07\x06"_q);
- G(6);
- S("\x03\x04\x03\x03"_q);
- }
- StartPermutationElement(); {
- S("\x00\x2d\x00\x02\x01\x01"_q);
- }
- StartPermutationElement(); {
- S("\x00\x33\x00\x2b\x00\x29"_q);
- G(4);
- S("\x00\x01\x00\x00\x1d\x00\x20"_q);
- K();
- }
- StartPermutationElement(); {
- S("\x44\x69\x00\x05\x00\x03\x02\x68\x32"_q);
- }
- StartPermutationElement(); {
- S("\xff\x01\x00\x01\x00"_q);
- }
- } ClosePermutation();
- G(3);
- S("\x00\x01\x00\x00\x15"_q);
- return MTP_tlsClientHello(MTP_vector<MTPTlsBlock>(Finish()));
- }
- [[nodiscard]] bytes::vector PrepareGreases() {
- auto result = bytes::vector(kMaxGrease);
- bytes::set_random(result);
- for (auto &byte : result) {
- byte = bytes::type((uchar(byte) & 0xF0) + 0x0A);
- }
- static_assert(kMaxGrease % 2 == 0);
- for (auto i = 0; i != kMaxGrease; i += 2) {
- if (result[i] == result[i + 1]) {
- result[i + 1] = bytes::type(uchar(result[i + 1]) ^ 0x10);
- }
- }
- return result;
- }
- // Returns y^2 = x^3 + 486662 * x^2 + x.
- [[nodiscard]] BigNum GenerateY2(
- const BigNum &x,
- const BigNum &mod,
- const BigNumContext &context) {
- auto coef = BigNum(486662);
- auto y = BigNum::ModAdd(x, coef, mod, context);
- y.setModMul(y, x, mod, context);
- coef.setWord(1);
- y.setModAdd(y, coef, mod, context);
- return BigNum::ModMul(y, x, mod, context);
- }
- // Returns x_2 = (x^2 - 1)^2/(4*y^2).
- [[nodiscard]] BigNum GenerateX2(
- const BigNum &x,
- const BigNum &mod,
- const BigNumContext &context) {
- auto denominator = GenerateY2(x, mod, context);
- auto coef = BigNum(4);
- denominator.setModMul(denominator, coef, mod, context);
- auto numerator = BigNum::ModMul(x, x, mod, context);
- coef.setWord(1);
- numerator.setModSub(numerator, coef, mod, context);
- numerator.setModMul(numerator, numerator, mod, context);
- denominator.setModInverse(denominator, mod, context);
- return BigNum::ModMul(numerator, denominator, mod, context);
- }
- [[nodiscard]] bytes::vector GeneratePublicKey() {
- const auto context = BigNumContext();
- const char modBytes[] = ""
- "\x7f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
- "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xed";
- const char powBytes[] = ""
- "\x3f\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
- "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xf6";
- const auto mod = BigNum(bytes::make_span(modBytes).subspan(0, 32));
- const auto pow = BigNum(bytes::make_span(powBytes).subspan(0, 32));
- auto x = BigNum();
- do {
- while (true) {
- auto random = bytes::vector(32);
- bytes::set_random(random);
- random[31] &= bytes::type(0x7FU);
- x.setBytes(random);
- x.setModMul(x, x, mod, context);
- auto y = GenerateY2(x, mod, context);
- if (BigNum::ModExp(y, pow, mod, context).isOne()) {
- break;
- }
- }
- for (auto i = 0; i != 3; ++i) {
- x = GenerateX2(x, mod, context);
- }
- const auto xBytes = x.getBytes();
- Assert(!xBytes.empty());
- Assert(xBytes.size() <= 32);
- } while (x.bytesSize() == 32);
- const auto xBytes = x.getBytes();
- auto result = bytes::vector(32, bytes::type());
- bytes::copy(
- bytes::make_span(result).subspan(32 - xBytes.size()),
- xBytes);
- ranges::reverse(result);
- //auto string = QString();
- //string.reserve(64);
- //for (const auto byte : result) {
- // const auto code = uchar(byte);
- // const auto hex = [](uchar value) -> char {
- // if (value >= 0 && value <= 9) {
- // return '0' + value;
- // } else if (value >= 10 && value <= 15) {
- // return 'a' + (value - 10);
- // }
- // return '-';
- // };
- // string.append(hex(code / 16)).append(hex(code % 16));
- //}
- //LOG(("KEY: %1").arg(string));
- return result;
- }
- struct ClientHello {
- QByteArray data;
- QByteArray digest;
- };
- class Generator {
- public:
- Generator(
- const MTPTlsClientHello &rules,
- bytes::const_span domain,
- bytes::const_span key);
- [[nodiscard]] ClientHello take();
- private:
- class Part final {
- public:
- explicit Part(
- bytes::const_span domain,
- const bytes::vector &greases);
- [[nodiscard]] bytes::span grow(int size);
- void writeBlocks(const QVector<MTPTlsBlock> &blocks);
- void writeBlock(const MTPTlsBlock &data);
- void writeBlock(const MTPDtlsBlockString &data);
- void writeBlock(const MTPDtlsBlockZero &data);
- void writeBlock(const MTPDtlsBlockGrease &data);
- void writeBlock(const MTPDtlsBlockRandom &data);
- void writeBlock(const MTPDtlsBlockDomain &data);
- void writeBlock(const MTPDtlsBlockPublicKey &data);
- void writeBlock(const MTPDtlsBlockScope &data);
- void writeBlock(const MTPDtlsBlockPermutation &data);
- void finalize(bytes::const_span key);
- [[nodiscard]] QByteArray extractDigest() const;
- [[nodiscard]] bool error() const;
- [[nodiscard]] QByteArray take();
- private:
- void writePadding();
- void writeDigest(bytes::const_span key);
- void injectTimestamp();
- bytes::const_span _domain;
- const bytes::vector &_greases;
- QByteArray _result;
- const char *_data = nullptr;
- int _digestPosition = -1;
- bool _error = false;
- };
- bytes::vector _greases;
- Part _result;
- QByteArray _digest;
- };
- Generator::Part::Part(
- bytes::const_span domain,
- const bytes::vector &greases)
- : _domain(domain)
- , _greases(greases) {
- _result.reserve(kClientHelloLength);
- _data = _result.constData();
- }
- bool Generator::Part::error() const {
- return _error;
- }
- QByteArray Generator::Part::take() {
- Expects(_error || _result.constData() == _data);
- return _error ? QByteArray() : std::move(_result);
- }
- bytes::span Generator::Part::grow(int size) {
- if (_error
- || size <= 0
- || _result.size() + size > kClientHelloLength) {
- _error = true;
- return bytes::span();
- }
- const auto offset = _result.size();
- _result.resize(offset + size);
- return bytes::make_detached_span(_result).subspan(offset);
- }
- void Generator::Part::writeBlocks(const QVector<MTPTlsBlock> &blocks) {
- for (const auto &block : blocks) {
- writeBlock(block);
- }
- }
- void Generator::Part::writeBlock(const MTPTlsBlock &data) {
- data.match([&](const auto &data) {
- writeBlock(data);
- });
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockString &data) {
- const auto &bytes = data.vdata().v;
- const auto storage = grow(bytes.size());
- if (storage.empty()) {
- return;
- }
- bytes::copy(storage, bytes::make_span(bytes));
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockZero &data) {
- const auto length = data.vlength().v;
- const auto already = _result.size();
- const auto storage = grow(length);
- if (storage.empty()) {
- return;
- }
- if (length == kHelloDigestLength && _digestPosition < 0) {
- _digestPosition = already;
- }
- bytes::set_with_const(storage, bytes::type(0));
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockGrease &data) {
- const auto seed = data.vseed().v;
- if (seed < 0 || seed >= _greases.size()) {
- _error = true;
- return;
- }
- const auto storage = grow(2);
- if (storage.empty()) {
- return;
- }
- bytes::set_with_const(storage, _greases[seed]);
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockRandom &data) {
- const auto length = data.vlength().v;
- const auto storage = grow(length);
- if (storage.empty()) {
- return;
- }
- bytes::set_random(storage);
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockDomain &data) {
- const auto storage = grow(_domain.size());
- if (storage.empty()) {
- return;
- }
- bytes::copy(storage, _domain);
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockPublicKey &data) {
- const auto key = GeneratePublicKey();
- const auto storage = grow(key.size());
- if (storage.empty()) {
- return;
- }
- bytes::copy(storage, key);
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockScope &data) {
- const auto storage = grow(kLengthSize);
- if (storage.empty()) {
- return;
- }
- const auto already = _result.size();
- writeBlocks(data.ventries().v);
- const auto length = qToBigEndian(uint16(_result.size() - already));
- bytes::copy(storage, bytes::object_as_span(&length));
- }
- void Generator::Part::writeBlock(const MTPDtlsBlockPermutation &data) {
- auto list = std::vector<QByteArray>();
- list.reserve(data.ventries().v.size());
- for (const auto &inner : data.ventries().v) {
- auto part = Part(_domain, _greases);
- part.writeBlocks(inner.v);
- if (part.error()) {
- _error = true;
- return;
- }
- list.push_back(part.take());
- }
- ranges::shuffle(list);
- for (const auto &element : list) {
- const auto storage = grow(element.size());
- if (storage.empty()) {
- return;
- }
- bytes::copy(storage, bytes::make_span(element));
- }
- }
- void Generator::Part::finalize(bytes::const_span key) {
- if (_error) {
- return;
- } else if (_digestPosition < 0) {
- _error = true;
- return;
- }
- writePadding();
- writeDigest(key);
- injectTimestamp();
- }
- QByteArray Generator::Part::extractDigest() const {
- if (_digestPosition < 0) {
- return {};
- }
- return _result.mid(_digestPosition, kHelloDigestLength);
- }
- void Generator::Part::writePadding() {
- Expects(_result.size() <= kClientHelloLength - kLengthSize);
- const auto padding = kClientHelloLength - kLengthSize - _result.size();
- writeBlock(MTP_tlsBlockScope(
- MTP_vector<MTPTlsBlock>(1, MTP_tlsBlockZero(MTP_int(padding)))));
- }
- void Generator::Part::writeDigest(bytes::const_span key) {
- Expects(_digestPosition >= 0);
- bytes::copy(
- bytes::make_detached_span(_result).subspan(_digestPosition),
- openssl::HmacSha256(key, bytes::make_span(_result)));
- }
- void Generator::Part::injectTimestamp() {
- Expects(_digestPosition >= 0);
- const auto storage = bytes::make_detached_span(_result).subspan(
- _digestPosition + kHelloDigestLength - sizeof(int32),
- sizeof(int32));
- auto already = int32();
- bytes::copy(bytes::object_as_span(&already), storage);
- already ^= qToLittleEndian(int32(base::unixtime::http_now()));
- bytes::copy(storage, bytes::object_as_span(&already));
- }
- Generator::Generator(
- const MTPTlsClientHello &rules,
- bytes::const_span domain,
- bytes::const_span key)
- : _greases(PrepareGreases())
- , _result(domain, _greases) {
- _result.writeBlocks(rules.match([&](const MTPDtlsClientHello &data) {
- return data.vblocks().v;
- }));
- _result.finalize(key);
- }
- ClientHello Generator::take() {
- auto digest = _result.extractDigest();
- return { _result.take(), std::move(digest) };
- }
- [[nodiscard]] ClientHello PrepareClientHello(
- const MTPTlsClientHello &rules,
- bytes::const_span domain,
- bytes::const_span key) {
- return Generator(rules, domain, key).take();
- }
- [[nodiscard]] bool CheckPart(bytes::const_span data, QLatin1String check) {
- if (data.size() < check.size()) {
- return false;
- }
- return !bytes::compare(
- data.subspan(0, check.size()),
- bytes::make_span(check.data(), check.size()));
- }
- [[nodiscard]] int ReadPartLength(bytes::const_span data, int offset) {
- const auto storage = data.subspan(offset, kLengthSize);
- return qFromBigEndian(
- *reinterpret_cast<const uint16*>(storage.data()));
- }
- } // namespace
- TlsSocket::TlsSocket(
- not_null<QThread*> thread,
- const bytes::vector &secret,
- const QNetworkProxy &proxy,
- bool protocolForFiles)
- : AbstractSocket(thread)
- , _secret(secret) {
- Expects(_secret.size() >= 21 && _secret[0] == bytes::type(0xEE));
- _socket.moveToThread(thread);
- _socket.setProxy(proxy);
- if (protocolForFiles) {
- _socket.setSocketOption(
- QAbstractSocket::SendBufferSizeSocketOption,
- kFilesSendBufferSize);
- _socket.setSocketOption(
- QAbstractSocket::ReceiveBufferSizeSocketOption,
- kFilesReceiveBufferSize);
- }
- const auto wrap = [&](auto handler) {
- return [=](auto &&...args) {
- InvokeQueued(this, [=] { handler(args...); });
- };
- };
- using Error = QAbstractSocket::SocketError;
- connect(
- &_socket,
- &QTcpSocket::connected,
- wrap([=] { plainConnected(); }));
- connect(
- &_socket,
- &QTcpSocket::disconnected,
- wrap([=] { plainDisconnected(); }));
- connect(
- &_socket,
- &QTcpSocket::readyRead,
- wrap([=] { plainReadyRead(); }));
- connect(
- &_socket,
- &QAbstractSocket::errorOccurred,
- wrap([=](Error e) { handleError(e); }));
- }
- bytes::const_span TlsSocket::domainFromSecret() const {
- return bytes::make_span(_secret).subspan(17);
- }
- bytes::const_span TlsSocket::keyFromSecret() const {
- return bytes::make_span(_secret).subspan(1, 16);
- }
- void TlsSocket::plainConnected() {
- if (_state != State::Connecting) {
- return;
- }
- static const auto kClientHelloRules = PrepareClientHelloRules();
- const auto hello = PrepareClientHello(
- kClientHelloRules,
- domainFromSecret(),
- keyFromSecret());
- if (hello.data.isEmpty()) {
- logError(888, "Could not generate Client Hello.");
- _state = State::Error;
- _error.fire({});
- } else {
- _state = State::WaitingHello;
- _incoming = hello.digest;
- _socket.write(hello.data);
- }
- }
- void TlsSocket::plainDisconnected() {
- _state = State::NotConnected;
- _incoming = QByteArray();
- _serverHelloLength = 0;
- _incomingGoodDataOffset = 0;
- _incomingGoodDataLimit = 0;
- _disconnected.fire({});
- }
- void TlsSocket::plainReadyRead() {
- switch (_state) {
- case State::WaitingHello: return readHello();
- case State::Connected: return readData();
- }
- }
- bool TlsSocket::requiredHelloPartReady() const {
- return _incoming.size() >= kHelloDigestLength + _serverHelloLength;
- }
- void TlsSocket::readHello() {
- const auto parts1Size = kServerHelloPart1.size() + kLengthSize;
- if (!_serverHelloLength) {
- _serverHelloLength = parts1Size;
- }
- while (!requiredHelloPartReady()) {
- if (!_socket.bytesAvailable()) {
- return;
- }
- _incoming.append(_socket.readAll());
- }
- checkHelloParts12(parts1Size);
- }
- void TlsSocket::checkHelloParts12(int parts1Size) {
- const auto data = bytes::make_span(_incoming).subspan(
- kHelloDigestLength,
- parts1Size);
- const auto part2Size = ReadPartLength(data, parts1Size - kLengthSize);
- const auto parts123Size = parts1Size
- + part2Size
- + kServerHelloPart3.size()
- + kLengthSize;
- if (_serverHelloLength == parts1Size) {
- const auto part1Offset = parts1Size
- - kLengthSize
- - kServerHelloPart1.size();
- if (!CheckPart(data.subspan(part1Offset), kServerHelloPart1)) {
- logError(888, "Bad Server Hello part1.");
- handleError();
- return;
- }
- _serverHelloLength = parts123Size;
- if (!requiredHelloPartReady()) {
- readHello();
- return;
- }
- }
- checkHelloParts34(parts123Size);
- }
- void TlsSocket::checkHelloParts34(int parts123Size) {
- const auto data = bytes::make_span(_incoming).subspan(
- kHelloDigestLength,
- parts123Size);
- const auto part4Size = ReadPartLength(data, parts123Size - kLengthSize);
- const auto full = parts123Size + part4Size;
- if (_serverHelloLength == parts123Size) {
- const auto part3Offset = parts123Size
- - kLengthSize
- - kServerHelloPart3.size();
- if (!CheckPart(data.subspan(part3Offset), kServerHelloPart3)) {
- logError(888, "Bad Server Hello part.");
- handleError();
- return;
- }
- _serverHelloLength = full;
- if (!requiredHelloPartReady()) {
- readHello();
- return;
- }
- }
- checkHelloDigest();
- }
- void TlsSocket::checkHelloDigest() {
- const auto fulldata = bytes::make_detached_span(_incoming).subspan(
- 0,
- kHelloDigestLength + _serverHelloLength);
- const auto digest = fulldata.subspan(
- kHelloDigestLength + kServerHelloDigestPosition,
- kHelloDigestLength);
- const auto digestCopy = bytes::make_vector(digest);
- bytes::set_with_const(digest, bytes::type(0));
- const auto check = openssl::HmacSha256(keyFromSecret(), fulldata);
- if (bytes::compare(digestCopy, check) != 0) {
- logError(888, "Bad Server Hello digest.");
- handleError();
- return;
- }
- shiftIncomingBy(fulldata.size());
- if (!_incoming.isEmpty()) {
- InvokeQueued(this, [=] {
- if (!checkNextPacket()) {
- handleError();
- }
- });
- }
- _incomingGoodDataOffset = _incomingGoodDataLimit = 0;
- _state = State::Connected;
- _connected.fire({});
- }
- void TlsSocket::readData() {
- if (!isConnected()) {
- return;
- }
- _incoming.append(_socket.readAll());
- if (!checkNextPacket()) {
- handleError();
- } else if (hasBytesAvailable()) {
- _readyRead.fire({});
- }
- }
- bool TlsSocket::checkNextPacket() {
- auto offset = 0;
- const auto incoming = bytes::make_span(_incoming);
- while (!_incomingGoodDataLimit) {
- const auto fullHeader = kServerHeader.size() + kLengthSize;
- if (incoming.size() <= offset + fullHeader) {
- return true;
- }
- if (!CheckPart(incoming.subspan(offset), kServerHeader)) {
- logError(888, "Bad packet header.");
- return false;
- }
- const auto length = ReadPartLength(
- incoming,
- offset + kServerHeader.size());
- if (length > 0) {
- if (offset > 0) {
- shiftIncomingBy(offset);
- }
- _incomingGoodDataOffset = fullHeader;
- _incomingGoodDataLimit = length;
- } else {
- offset += kServerHeader.size() + kLengthSize + length;
- }
- }
- return true;
- }
- void TlsSocket::shiftIncomingBy(int amount) {
- Expects(_incomingGoodDataOffset == 0);
- Expects(_incomingGoodDataLimit == 0);
- const auto incoming = bytes::make_detached_span(_incoming);
- if (incoming.size() > amount) {
- bytes::move(incoming, incoming.subspan(amount));
- _incoming.chop(amount);
- } else {
- _incoming.clear();
- }
- }
- void TlsSocket::connectToHost(const QString &address, int port) {
- Expects(_state == State::NotConnected);
- _state = State::Connecting;
- _socket.connectToHost(address, port);
- }
- bool TlsSocket::isGoodStartNonce(bytes::const_span nonce) {
- return true;
- }
- void TlsSocket::timedOut() {
- _syncTimeRequests.fire({});
- }
- bool TlsSocket::isConnected() {
- return (_state == State::Connected);
- }
- bool TlsSocket::hasBytesAvailable() {
- return (_incomingGoodDataLimit > 0)
- && (_incomingGoodDataOffset < _incoming.size());
- }
- int64 TlsSocket::read(bytes::span buffer) {
- auto written = int64(0);
- while (_incomingGoodDataLimit) {
- const auto available = std::min(
- _incomingGoodDataLimit,
- int(_incoming.size()) - _incomingGoodDataOffset);
- if (available <= 0) {
- return written;
- }
- const auto write = std::min(std::size_t(available), buffer.size());
- if (write <= 0) {
- return written;
- }
- bytes::copy(
- buffer,
- bytes::make_span(_incoming).subspan(
- _incomingGoodDataOffset,
- write));
- written += write;
- buffer = buffer.subspan(write);
- _incomingGoodDataLimit -= write;
- _incomingGoodDataOffset += write;
- if (_incomingGoodDataLimit) {
- return written;
- }
- shiftIncomingBy(base::take(_incomingGoodDataOffset));
- if (!checkNextPacket()) {
- _state = State::Error;
- InvokeQueued(this, [=] { handleError(); });
- return written;
- }
- }
- return written;
- }
- void TlsSocket::write(bytes::const_span prefix, bytes::const_span buffer) {
- Expects(!buffer.empty());
- if (!isConnected()) {
- return;
- }
- if (!prefix.empty()) {
- _socket.write(kClientPrefix.data(), kClientPrefix.size());
- }
- while (!buffer.empty()) {
- const auto write = std::min(
- kClientPartSize - prefix.size(),
- buffer.size());
- _socket.write(kClientHeader.data(), kClientHeader.size());
- const auto size = qToBigEndian(uint16(prefix.size() + write));
- _socket.write(reinterpret_cast<const char*>(&size), sizeof(size));
- if (!prefix.empty()) {
- _socket.write(
- reinterpret_cast<const char*>(prefix.data()),
- prefix.size());
- prefix = bytes::const_span();
- }
- _socket.write(
- reinterpret_cast<const char*>(buffer.data()),
- write);
- buffer = buffer.subspan(write);
- }
- }
- int32 TlsSocket::debugState() {
- return _socket.state();
- }
- QString TlsSocket::debugPostfix() const {
- return u"_ee"_q;
- }
- void TlsSocket::handleError(int errorCode) {
- if (_state != State::Connected) {
- _syncTimeRequests.fire({});
- }
- if (errorCode) {
- logError(errorCode, _socket.errorString());
- }
- _state = State::Error;
- _error.fire({});
- }
- } // namespace MTP::details
|