"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