Deep Engineering
Средний·Опубликовано·25 МИН

TLS-рукопожатие: за что платит первое соединение

«Возобновление сессии экономит круг» — фраза про TLS 1.2, которую продолжают говорить про 1.3. Измерено на звене с известной задержкой: полное рукопожатие 1.3 стоит один круг, 1.2 — два, а возобновление в 1.3 не экономит ни одного. Экономит оно другое, и это видно в байтах.

Полное техническое изложение

TL;DR

Перед первым байтом данных стороны договариваются, и договорённость стоит ожидания, а не работы процессора. Клиент убеждается, что сервер тот, за кого себя выдаёт, обе стороны выводят общий ключ — и на каждый такой шаг нужен полёт до сервера и обратно. Платится это один раз за соединение, а не за запрос.

Отсюда главное следствие: «TLS медленный» — утверждение не про шифрование, а про расстояние. Симметричное шифрование самих данных в измеренную цену не попало вовсе: вся она — круги установления и байты сертификата. Измерено: 43,6 мс при круге в 40 мс, то есть один круг на установление; переиспользованное соединение не платит его вовсе, поэтому «первый запрос медленный» — не аномалия, а ровно эта цена.

Дальше — то, что отличает знающего от читавшего. Полное рукопожатие TLS 1.3 стоит один круг, TLS 1.2 — два: измерено на звене с задержкой 20 мс в одну сторону, 43,6 мс против 84,7. Возобновление сессии экономит круг только там, где было что экономить: в TLS 1.2 два круга стали одним (42,3 мс), в TLS 1.3 как был один, так и остался — 43,6 против 42,2, и обе сессии действительно возобновлены. Экономит оно другое — сертификат: в TLS 1.2 сервер прислал 1453 байта при полном рукопожатии и 172 при возобновлённом, в 8,4 раза меньше. Ждать круг перед отправкой данных не заставляет только 0-RTT, и RFC прямо называет цену: гарантий защиты от повтора между соединениями нет, поэтому операцию с побочным эффектом в ранние данные не кладут, пока от повтора не защищает само приложение. И граница самого числа: один круг — это цена рукопожатия поверх уже установленного TCP-соединения, а не всего подключения по HTTPS с нуля.

Порог входа
Перед уроком достаточно понимать
  • данные идут по сети не мгновенно: ответ приходит с задержкой, и она тем больше, чем дальше собеседник;
  • прежде чем говорить с сервером, клиент устанавливает с ним соединение;
  • обмен по сети можно подслушать и подменить, и защищаются от этого шифрованием.
Заранее знать не нужно
  • порядок сообщений рукопожатия и чем версии протокола отличаются друг от друга;
  • возобновление сессии, билет, 0-RTT, ранние данные, прямая секретность.

Что здесь на самом деле спрашивают

Лестница выглядит так:

  1. «Что происходит при установлении TLS-соединения?» — разминка про рукопожатие.
  2. «Сколько это стоит?» — здесь начинается содержание: стоит оно кругами, а не процентами процессора.
  3. «Что даёт возобновление сессии?» — вопрос, на котором чаще всего отвечают формулировкой из времён TLS 1.2.
  4. «Что такое 0-RTT и почему его не включают всем подряд?» — вопрос про цену, названную в самом стандарте.
  5. «Почему первый запрос к сервису медленнее остальных?» — вопрос про то, что рукопожатие платится за соединение.
  6. «Стоит ли выключить TLS внутри периметра ради скорости?» — вопрос- ловушка: измерять надо не то, что кажется.

Числа получены прогоном bench/tls/handshake.py и bench/tls/practice.py. Настоящего сервера в интернете здесь нет: его задержка неизвестна и непостоянна, а измерить надо круги. Вместо него — свой сервер на loopback и звено, которое задерживает каждую порцию ровно на 20 мс в одну сторону. Круг поэтому известен точно, и время рукопожатия читается в кругах.

База: о чём договариваются стороны и из чего состоит подключение

Прежде чем считать круги и сравнивать версии, стоит назвать обычными словами, ради чего этот обмен вообще нужен. Клиент хочет от него три вещи, и ни одна не получается молча:

  1. убедиться, что сервер тот, за кого себя выдаёт — иначе шифроваться не с кем: канал до подставного сервера шифруется ничуть не хуже настоящего;
  2. договориться о ключах, которых до этого разговора не было ни у одной из сторон;
  3. получить из этих ключей шифрование и защиту от подмены — чтобы посредник в сети не мог ни прочитать данные, ни незаметно их исправить.

Договориться с собеседником на расстоянии нельзя быстрее, чем сообщение долетит до него и вернётся обратно. Поэтому цена рукопожатия — это не работа процессора, а ожидание: столько-то полётов туда и обратно, прежде чем уйдёт первый байт запроса. Такой полёт дальше называется кругом, и весь урок считает именно круги.

И вторая вещь, без которой арифметика урока читается неверно: рукопожатие TLS — не всё подключение, а один его шаг. Новое соединение к серверу по HTTPS складывается из четырёх:

  1. разрешение имени — по имени сервера узнаётся его адрес (этим занимался прошлый урок);
  2. установление TCP-соединения — свой обмен по тому же звену и со своими кругами;
  3. рукопожатие TLS — то, что считает этот урок;
  4. сам запрос и ответ на него — то, ради чего всё затевалось.

Отсюда важное следствие для всех чисел ниже: «TLS 1.3 укладывается в один круг» — утверждение про третий шаг, а не про подключение целиком. Круги первых двух шагов оно не отменяет, и новое соединение по HTTPS платит за все четыре.

Этого уже достаточно, чтобы ответить на базовый вопрос собеседования. Дальше — про то, во сколько кругов обходится третий шаг в разных версиях, что при этом меняет возобновление сессии и чего оно не меняет.

Механизм 1: рукопожатие стоит кругами

наблюдение замераbench/tls/handshake.py. Задержку в 20 мс на сторону задаёт сам ретранслятор, поэтому круг равен 40 мс по построению. Миллисекунды у вас будут другими; отношение времени рукопожатия к кругу — тем же.

Круги из «Базы» — это не образ речи, а единица измерения: в миллисекундах цену рукопожатия называть бессмысленно, потому что она целиком определяется тем, как далеко стоит сервер. Всё остальное на этом фоне мало.

Чтобы увидеть круги, нужно знать их длину. Здесь она задана: между клиентом и сервером стоит ретранслятор, который задерживает каждую порцию на 20 мс в одну сторону.

1. A FULL HANDSHAKE COSTS ROUND TRIPS, AND THE VERSION DECIDES HOW MANY
-----------------------------------------------------------------------
     version   handshake, ms   in round trips   reused
     TLS 1.3            43.6              1.1    False
     TLS 1.2            84.7              2.1    False

Одно и то же звено, один и тот же сертификат, один и тот же сервер. Разница только в версии протокола — и она ровно в один круг.

контракт языкаПорядок полётов задан стандартами, а не замером: RFC 5246 для TLS 1.2 и RFC 8446 для 1.3. Прогон показывает, во сколько кругов это обходится, но не почему их столько.

Почему так. В TLS 1.2 содержимое клиентской части ключевого обмена зависит от того, что выбрал сервер:

The ClientKeyExchange message is now sent, and the content of that message will depend on the public key algorithm selected between the ClientHello and the ServerHello.

перевод

Теперь посылается сообщение ClientKeyExchange, и его содержимое зависит от алгоритма с открытым ключом, выбранного между ClientHello и ServerHello.

RFC 5246, §7.3

Значит, отправить её до ответа сервера нельзя — отсюда и лишний круг. В TLS 1.3 клиент угадывает выбор сервера заранее и посылает свою часть сразу, а сервер отвечает уже готовым ключом.

Слово «угадывает» здесь не оборот речи: если догадка не подошла, сервер просит повторить, и рукопожатие стоит два круга — как в 1.2. В этом замере догадка подошла, отсюда 1,1 круга.

Отсюда практический вывод, за который этот механизм и спрашивают: половина ходячих утверждений про TLS относится к 1.2. Прежде чем повторять цифру, стоит спросить, о какой версии речь.

Механизм 2: возобновление экономит круг не всегда

Теперь сама формулировка. «Возобновление сессии экономит круг» произносят почти всегда. Проверим её на обеих версиях.

2. RESUMPTION SAVES A ROUND TRIP ONLY WHERE THERE WAS ONE TO SAVE
-----------------------------------------------------------------
     version   full, ms   resumed, ms     full   resumed   reused
     TLS 1.3       43.6          42.2      1.1       1.1     True
     TLS 1.2       84.7          42.3      2.1       1.1     True
наблюдение замераbench/tls/handshake.py. Колонка reused — это ответ библиотеки на вопрос «сессия действительно возобновлена?». В обеих строках True, то есть возобновление состоялось и в 1.3 тоже.

В TLS 1.2 формулировка верна: два круга стали одним, 84,7 мс превратились в 42,3.

В TLS 1.3 она неверна: как был один круг, так и остался — 43,6 против 42,2. Экономить было нечего.

И самое важное — колонка reused. В обеих строках стоит True: сессия действительно возобновлена, и в 1.3 тоже. То есть дело не в том, что возобновление не сработало, а в том, что экономить круг ему больше не на чем.

Отсюда ответ, который отличает измерявшего от пересказавшего: «в 1.3 возобновление круга не экономит, потому что полное рукопожатие и так стоит один; оно экономит другое».

Механизм 3: что возобновление экономит на самом деле

Другое — это байты, и главный из них сертификат. Тот же ретранслятор считает поток в обе стороны:

3. WHAT RESUMPTION ACTUALLY SAVES: THE CERTIFICATE
--------------------------------------------------
     version    handshake   client -> server   server -> client
     TLS 1.3         full                620               1871
     TLS 1.3      resumed                659                520
     TLS 1.2         full                640               1453
     TLS 1.2      resumed                598                172
наблюдение замераbench/tls/handshake.py. Сертификат здесь самоподписанный, RSA-2048, ровно один в цепочке. Абсолютные байты у вас будут другими — их меняют длина ключа и длина цепочки; направление разницы останется.

Смотреть надо на правую колонку. Сертификат в обеих версиях посылает сервер — RFC 5246 говорит это прямо: Following the hello messages, the server will send its certificate in a Certificate message if it is to be authenticated (После сообщений hello сервер пошлёт свой сертификат в сообщении Certificate, если он должен быть аутентифицирован). Поэтому меняется именно его поток, а замер показывает, насколько. В TLS 1.2 он падает с 1453 байт до 172 — в 8,4 раза. В TLS 1.3 с 1871 до 520.

Поток от клиента при этом почти не меняется: ему и в полном рукопожатии отправлять нечего крупного.

Практический вывод. Настоящая цепочка сертификатов — это не один самоподписанный сертификат, а два-три реальных, то есть килобайты. Возобновление убирает их целиком. На быстром звене это незаметно, а на медленном или дорогом — это может быть больше, чем сэкономленный круг.

И обратная сторона, о которой стоит сказать самому: возобновление требует состояния. Клиент должен хранить билет, сервер — уметь его принять. Билет выдаёт конкретный сервер, поэтому балансировщик, раздающий соединения на разные серверы, возвращает возобновление в полное рукопожатие всюду, где у серверов нет общего секрета для билетов — общей базы или общего ключа, которым билет зашифрован. Замера этого в уроке нет: это следствие того, что билет выдаёт одна сторона, а принимает другая. Заметит его только тот, кто смотрит на долю возобновлённых рукопожатий, а не на среднее время.

Механизм 4: платится это за соединение, а не за запрос

Последний механизм — про то, куда девается вся арифметика в настоящей системе. Блок прогона здесь четвёртый и последний.

4. WHAT ENCRYPTION COSTS AGAINST NO ENCRYPTION AT ALL
-----------------------------------------------------
              connection   connect, ms   handshake, ms   exchange, ms
               plain TCP           0.3               -           41.6
           TLS 1.3, full           2.1            43.6           81.6
        TLS 1.3, resumed           0.8            42.2           61.3

  the handshake alone, round trips               1.1
наблюдение замераbench/tls/handshake.py. Колонка exchange под TLS больше круга не из-за шифрования: в TLS 1.3 сервер присылает билет на возобновление уже после рукопожатия, и звено задерживает этот полёт тоже. Отдельным числом этот полёт в прогоне не выделен, поэтому колонка exchange здесь не предмет, а фон: смотреть надо на handshake.

Читать здесь надо колонку handshake: один круг, и это вся цена шифрования на этом уровне. Симметричное шифрование самих данных в измеренную разницу не попало вовсе — оно на этих объёмах не видно.

А теперь главное: этот круг платится один раз за соединение. Не за запрос, не за килобайт. Клиент, который держит соединение открытым и шлёт в него сто запросов, платит рукопожатие один раз из ста.

Отсюда и правильная реакция на «первый запрос медленный»: это не аномалия и не повод чинить TLS. Это ровно та цена, которую видно в таблице, и убирается она не отключением шифрования, а переиспользованием соединения — вместе с разрешением имени из прошлого урока, которого переиспользованное соединение тоже не делает.

И здесь же видно границу самого числа, ради которой в таблице стоит строка обычного TCP. Колонка connect — это подключение к звену, стоящему на той же машине: 0,3 мс, никаких кругов в ней нет. То есть «один круг» — цена рукопожатия поверх уже установленного TCP-соединения, а не цена подключения с нуля. Настоящее новое соединение сначала разрешает имя, потом устанавливает TCP — со своими кругами по тому же звену, — и только потом начинает рукопожатие. Читать строку TLS 1.3, full как «HTTPS-соединение обходится в один круг» нельзя: в 43,6 мс входит только третий шаг из четырёх, названных в «Базе».

Глубже: круг перед данными убирает только 0-RTT, и цена названа

контракт языкаСвойства 0-RTT описаны в RFC 8446. Замера 0-RTT в этом уроке нет: библиотека, на которой сняты остальные числа, отправку ранних данных не поддерживает.

Раз в TLS 1.3 полное рукопожатие стоит круг, а возобновление — тоже круг, остаётся вопрос: а можно ли не ждать этот круг перед отправкой данных? Можно: само рукопожатие круг всё равно займёт, но часть данных приложения уходит с первым же сообщением. Стандарт называет режим и цену в одном предложении:

A zero round-trip time (0-RTT) mode was added, saving a round trip at connection setup for some application data, at the cost of certain security properties.

перевод

Добавлен режим нулевого времени кругового обхода (0-RTT), экономящий круг при установлении соединения для части данных приложения ценой определённых свойств безопасности.

RFC 8446, §1.2

«Ценой определённых свойств безопасности» — и вот каких именно:

There are no guarantees of non-replay between connections.

перевод

Гарантий защиты от повтора между соединениями нет.

RFC 8446, §2.3

Это и есть ответ на вопрос «почему 0-RTT не включают всем подряд». Ранние данные можно перехватить и отправить повторно, и протокол не обещает, что сервер это заметит: меры против повтора он оставляет на усмотрение реализации. Рассчитывать поэтому надо на худший случай. Для запроса «покажи страницу» это ничего не значит. Для запроса «спиши деньги» — значит всё.

Отсюда правило, которое стоит формулировать от риска, а не от списка разрешённых методов: самое первое сообщение может быть воспроизведено, поэтому операцию с побочным эффектом в ранние данные не кладут — до тех пор, пока от повтора не защищает само приложение. Это ровно та же граница, что и в уроке про повторы: там повтор делал клиент, здесь — злоумышленник, а защита одна и та же.

Стандарт называет и вторую цену, которую упоминают реже:

This data is not forward secret, as it is encrypted solely under keys derived using the offered PSK.

перевод

Эти данные не обладают прямой секретностью, так как шифруются исключительно на ключах, выведенных из предложенного PSK.

RFC 8446, §2.3

То есть перехваченные ранние данные расшифровываются позже, если противник добудет тот самый ключ. Обычные данные соединения этим свойством не обладают.

Как отвечать на собеседовании

Короткий ответ: рукопожатие стоит не работой процессора, а кругами — полётами до сервера и обратно, — и платится оно один раз за соединение, а не за запрос. Сколько именно кругов, зависит от версии: TLS 1.3 — один, TLS 1.2 — два. Измерено на звене с известным кругом: 43,6 мс против 84,7 мс при полном рукопожатии. Поэтому «первый запрос медленный» лечится переиспользованием соединения, а не отключением шифрования.

Этого достаточно, чтобы ответить верно. Дальше — то, что добавляют, если собеседник копает.

Если интервьюер копает глубже

Хороший ответ отличают три вещи. Первая — вы знаете, что даёт возобновление сессии в каждой версии: круг оно убирает только в 1.2 — 84,7 мс превращаются в 42,3, — а в 1.3 убирать нечего, 43,6 против 42,2. Экономит оно там другое, сертификат: в 1.2 поток от сервера падает с 1453 байт до 172. Вторая — вы называете цену 0-RTT словами стандарта: гарантий защиты от повтора между соединениями нет, поэтому операцию с побочным эффектом в ранние данные не кладут, пока от повтора не защищает само приложение. Третья — вы упоминаете, что возобновление требует состояния на обеих сторонах, и что за балансировщиком оно работает только там, где у серверов есть общий секрет для билетов.

И одна вещь, на которой легко переусердствовать. Сказать «новое соединение по HTTPS обходится в один круг» — значит распространить измеренное число дальше, чем оно доходит. Один круг — это рукопожатие TLS поверх уже установленного TCP-соединения; подключение с нуля платит ещё за разрешение имени и за установление TCP, и на дальнем звене эти шаги стоят своих кругов. Точная формулировка: один круг — цена третьего шага из четырёх, а не всего подключения.

Чего говорить не стоит: «TLS добавляет столько-то процентов». Это число ни о чём: цена рукопожатия зависит от круга до сервера, а не от объёма данных, и на разных звеньях отличается на порядки.

Дальше спросят

Спросят дальше

Помогает ли отключение TLS внутри периметра?

Короткий ответ

Меньше, чем кажется, и не там, где кажется. Измеренная цена — один круг на соединение. Внутри дата-центра круг измеряется десятками микросекунд, и один круг на соединение, которое живёт минуты, не виден вовсе.

Заметным он становится в двух случаях: когда соединения короткие и новые устанавливаются на каждый запрос, и когда круг большой. Первый случай чинится переиспользованием соединения, второй — размещением, а не отключением шифрования.

Спросят дальше

Почему возобновление иногда не срабатывает?

Короткий ответ

Потому что для него нужно состояние на обеих сторонах: клиент хранит билет, сервер должен уметь его принять. Клиент, создающий новый контекст на каждый запрос, теряет билет и каждый раз делает полное рукопожатие.

На стороне сервера то же самое ломает балансировка: если билет выдал один сервер, а следующее соединение попало на другой, у которого нет общего с ним секрета для билетов, билет не примут. Наблюдать это надо не по среднему времени, а по доле возобновлённых рукопожатий — в замере это колонка reused.

Спросят дальше

Что дороже: рукопожатие или проверка сертификата?

Короткий ответ

В этом замере — не сравнить: клиент здесь сертификат не проверяет вовсе. Предмет замера — круги и байты, стоимость проверки подписи в него не входит.

Но направление известно из устройства: круг — это задержка звена, она измеряется миллисекундами и растёт с расстоянием; проверка подписи — работа процессора, она измеряется десятками микросекунд и от расстояния не зависит. Поэтому на межконтинентальном звене круги решают всё, а на loopback заметна уже проверка. Своё соотношение стоит померить, а не предполагать.

Спросят дальше

Что именно передаётся при возобновлении вместо сертификата?

Короткий ответ

Билет, выданный сервером в прошлом соединении, — по сути ссылка на уже согласованный секрет. Поэтому поток от сервера и падает в разы: подтверждать свою личность заново не нужно.

Важная деталь для TLS 1.3, на которой легко ошибиться: билет присылается после рукопожатия, отдельным сообщением. Клиент, который закроет соединение сразу после рукопожатия, билета не получит и в следующий раз сделает полное рукопожатие, ничего об этом не сообщив.

Частые заблуждения

Утверждение

Возобновление сессии экономит круг

На самом деле

Только в TLS 1.2. Измерено: там два круга стали одним (84,7 мс против 42,3), а в TLS 1.3 как был один, так и остался — 43,6 против 42,2. Колонка reused в обеих строках True: возобновление сработало, экономить круг ему просто не на чем.

Утверждение

TLS медленный, потому что шифрование дорогое

На самом деле

Измеренная цена — один круг на соединение, то есть задержка звена, а не работа процессора. Симметричное шифрование самих данных в разницу не попало вовсе. «Медленно» здесь означает «далеко», и лечится это переиспользованием соединения, а не отключением шифрования.

Утверждение

0-RTT — это просто более быстрый режим

На самом деле

Это режим с другими гарантиями, и RFC 8446 называет их прямо: There are no guarantees of non-replay between connections (гарантий защиты от повтора между соединениями нет). Самое первое сообщение можно перехватить и отправить повторно, и протокол не обещает, что сервер это заметит, — поэтому операцию с побочным эффектом в ранние данные не кладут, пока от повтора не защищает само приложение.

Утверждение

Новое соединение по HTTPS обходится в один круг

На самом деле

В один круг укладывается рукопожатие TLS 1.3 — и то поверх уже установленного TCP-соединения. Подключение с нуля состоит из четырёх шагов: разрешение имени, установление TCP, рукопожатие TLS и сам запрос, — и первые два платят свои круги по тому же звену. В измеренные 43,6 мс они не входят: колонка connect в замере — это подключение к звену на той же машине, 0,3 мс.

Утверждение

Рукопожатие платится за каждый запрос

На самом деле

За соединение. Измерено: рукопожатие — 43,6 мс при круге в 40 мс, то есть один круг на установление. Клиент, который держит соединение и шлёт в него сто запросов, платит рукопожатие один раз из ста — поэтому «первый запрос медленный» это не аномалия, а ровно эта цена.

Утверждение

Возобновление ничего не стоит и работает само

На самом деле

Оно требует состояния с обеих сторон: клиент хранит билет, сервер умеет его принять. Клиент с новым контекстом на каждый запрос билет теряет; балансировщик отдаёт соединение серверу, у которого нет общего с выдавшим секрета для билетов, и билет не примут. И то и другое видно только по доле возобновлённых рукопожатий, а не по среднему времени.

Практика

Две задачи. Сначала ответьте, потом сверьтесь с настоящим выводом: в обеих правильный ответ печатает сам скрипт замера.

Практика · что напечатает

Между клиентом и сервером стоит звено с известным кругом. Печатаются три числа: время полного рукопожатия TLS 1.3 в кругах, время полного рукопожатия TLS 1.2 в кругах и время возобновлённого рукопожатия TLS 1.3 в кругах. Что напечатает этот код?
full13, resumed13, _ = pair(key, crt, ssl.TLSVersion.TLSv1_3)
full12, resumed12, _ = pair(key, crt, ssl.TLSVersion.TLSv1_2)
print(f"{full13['handshake_ms'] / RTT_MS:.1f}")
print(f"{full12['handshake_ms'] / RTT_MS:.1f}")
print(f"{resumed13['handshake_ms'] / RTT_MS:.1f}")

Практика · оцените

TLS 1.2, одно и то же соединение, один и тот же сертификат. Во сколько раз меньше байт присылает сервер при возобновлённом рукопожатии по сравнению с полным?
раз

Проверка знаний

Вопрос 1 из 5

Сколько кругов стоит полное рукопожатие TLS 1.3?

Источники и что читать дальше

2 ИСТОЧНИКА

  1. RFC 8446, The Transport Layer Security (TLS) Protocol Version 1.3Источник. Откуда известно, что 0-RTT экономит ожидание перед отправкой данных и чем за это платят. Что других режимов, экономящих круг, в TLS 1.3 не осталось, — вывод нашего замера, а не утверждение стандарта. Из перечня отличий от TLS 1.2: «A zero round-trip time (0-RTT) mode was added, saving a round trip at connection setup for some application data, at the cost of certain security properties» (Добавлен режим нулевого времени кругового обхода (0-RTT), экономящий круг при установлении соединения для части данных приложения ценой определённых свойств безопасности). Какие именно свойства — сказано там же, в разделе про 0-RTT: «This data is not forward secret, as it is encrypted solely under keys derived using the offered PSK» (Эти данные не обладают прямой секретностью, так как шифруются исключительно на ключах, выведенных из предложенного PSK) и «There are no guarantees of non-replay between connections» (Гарантий защиты от повтора между соединениями нет).https://www.rfc-editor.org/rfc/rfc8446.html
  2. RFC 5246, The Transport Layer Security (TLS) Protocol Version 1.2Источник. Откуда известно, что в TLS 1.2 клиент отправляет свою часть ключевого обмена только после выбора сервера — то есть откуда берётся лишний круг: «The ClientKeyExchange message is now sent, and the content of that message will depend on the public key algorithm selected between the ClientHello and the ServerHello» (Теперь посылается сообщение ClientKeyExchange, и его содержимое зависит от алгоритма с открытым ключом, выбранного между ClientHello и ServerHello). И откуда известно, что сертификат посылает сервер: «Following the hello messages, the server will send its certificate in a Certificate message if it is to be authenticated» (После сообщений hello сервер пошлёт свой сертификат в сообщении Certificate, если он должен быть аутентифицирован).https://www.rfc-editor.org/rfc/rfc5246.html