Соединение TLS 1.3

Каждый байт объяснен и воспроизведен

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

Генерация обмена ключами клиента

Клиент начинает с генерации пары закрытый/открытый ключ для обмена ключами. Обмен ключами - это метод где две стороны могут договориться об одном и том же числе без возможности для злоумышленника узнать, что это за число.

Объяснение обмена ключами можно найти на сайте X25519, но его не нужно понимать глубоко для остальной части этой страницы.

Закрытый ключ выбирается путем выбора целого числа между 0 и 2256-1. Клиент делает это, генерируя 32 байта (256 бит) случайных данных. Закрытый ключ выбран следующий:

202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
Открытый ключ создается из закрытого ключа, как объяснено на сайте X25519. Вычисленный открытый ключ:
358072d6365880d1aeea329adf9121383851ed21a28e3b75e965d0d2cd166254
Вычисление открытого ключа можно подтвердить в командной строке:
### requires openssl 1.1.0 or higher
$ openssl pkey -noout -text < client-ephemeral-private.key

X25519 Private-Key:
priv:
    20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:
    2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:
    3e:3f
pub:
    35:80:72:d6:36:58:80:d1:ae:ea:32:9a:df:91:21:
    38:38:51:ed:21:a2:8e:3b:75:e9:65:d0:d2:cd:16:
    62:54
Client Hello
Сеанс начинается с того, что клиент говорит "Hello". Клиент предоставляет информацию, включающую следующее:
  • случайные данные клиента (используются позже в рукопожатии)
  • список наборов шифров, которые поддерживает клиент
  • список открытых ключей, которые сервер может найти подходящими для обмена ключами
  • версии протокола, которые может поддерживать клиент
Record Header 16 03 01 00 f8
Сеансы TLS разбиты на отправку и получение "записей", которые представляют собой блоки данных с типом, версией протокола, и длиной.
  • 16 - тип 0x16 (запись рукопожатия)
  • 03 01 - версия протокола "3,1" (также известная как TLS 1.0)
  • 00 f8 - 0xF8 (248) байтов сообщения рукопожатия следует далее
Интересно, что версия в этой записи "3,1" (TLS 1.0) вместо "3,4" (TLS 1.3). Это сделано для взаимодействия с более ранними реализациями.
Handshake Header 01 00 00 f4
Каждое сообщение рукопожатия начинается с типа и длины.
  • 01 - тип сообщения рукопожатия 0x01 (client hello)
  • 00 00 f4 - 0xF4 (244) байта данных client hello следует далее
Client Version 03 03
Указана версия протокола "3,3" (означает TLS 1.2). Поскольку были созданы и широко распространены промежуточные устройства, которые не пропускают версии протоколов, которые они не распознают, сеанс TLS 1.3 должен быть замаскирован под сеанс TLS 1.2. Это поле больше не используется для согласования версий и жестко закодировано в версии 1.2. Вместо этого согласование версий выполняется с помощью расширения "Supported Versions" ниже.

Необычный номер версии ("3,3", представляющий TLS 1.2) связано с тем, что TLS 1.0 является незначительным пересмотром протокола SSL 3.0. Следовательно TLS 1.0 представлен как "3,1", TLS 1.1 - "3,2" и так далее.
Client Random 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
Клиент предоставляет 32 байта случайных данных. Эти данные будут использованы позже в сеансе. В этом примере мы сделали случайные данные предсказуемой строкой.
Session ID 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff
В предыдущих версиях TLS клиент мог предоставить ID ранее согласованного сеанса, который позволяет серверу и клиенту пропустить время и затраты на согласование новых ключей.

В TLS 1.3 это "возобновление сеанса" осуществляется через более гибкий механизм PSK (pre-shared keys, предварительно распределенные ключи), поэтому это поле больше не нужно для этой цели. Вместо этого ненулевое значение в этом поле используется для запуска "режима совместимости с промежуточными устройствами" который помогает сеансам TLS 1.3 быть замаскированными под возобновленные сеансы TLS 1.2. Клиент сгенерировал случайные данные для заполнения этого поля.
  • 20 - 0x20 (32) байта ID сеанса следует далее
  • e0 e1 ... fe ff - фальшивый ID сеанса
Cipher Suites 00 08 13 02 13 03 13 01 00 ff
Клиент предоставляет упорядоченный список того, какие наборы шифров он будет поддерживать для шифрования. Список представлен в порядке, предпочитаемом клиентом, с наивысшим приоритетом первым.

В TLS 1.3 список возможных шифров наборы были значительно сокращены. Все остальные наборы - это алгоритмы AEAD, которые предоставляют более сильные гарантии шифрования, чем многие предыдущие наборы с более простой реализацией "все в одном".
  • 00 08 - 8 байтов данных набора шифров
  • 13 02 - назначенное значение для TLS_AES_256_GCM_SHA384
  • 13 03 - назначенное значение для TLS_CHACHA20_POLY1305_SHA256
  • 13 01 - назначенное значение для TLS_AES_128_GCM_SHA256
  • 00 ff - назначенное значение для TLS_EMPTY_RENEGOTIATION_INFO_SCSV
Compression Methods 01 00
Предыдущие версии TLS поддерживали сжатие, которое, как было обнаружено, приводит к утечке информации о зашифрованных данных, что позволяет их прочитать (см. CRIME).

TLS 1.3 больше не разрешает сжатие, поэтому это поле всегда является одной записью с методом сжатия "null", который не выполняет изменение данных.
  • 01 - 1 байт методов сжатия
  • 00 - назначенное значение для сжатия "null"
Extensions Length 00 a3
Клиент предоставил список дополнительных расширений, которые сервер может использовать для выполнения действий или включения новых функций.
  • 00 a3 - расширения займут 0xA3 (163) байта данных
Каждое расширение будет начинаться с двух байтов которые указывают, какое это расширение, за которым следует двухбайтовое поле длины содержимого, за которым следует содержимое расширения.
Extension - Server Name 00 00 00 18 00 16 00 00 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74
Клиент предоставил имя сервера, с которым он связывается, также известное как SNI (Server Name Indication, указание имени сервера).

Без этого расширения сервер HTTPS не смог бы обслуживать несколько имен хостов (виртуальных хостов) на одном IP-адресе потому что он не мог знать, какой сертификат имени хоста отправить, пока сеанс TLS не был согласован, и HTTP-запрос не был сделан.
  • 00 00 - назначенное значение для расширения "server name"
  • 00 18 - 0x18 (24) байта данных расширения "server name" следует далее
  • 00 16 - 0x16 (22) байта первой (и единственной) записи списка следует далее
  • 00 - запись списка имеет тип 0x00 "имя хоста DNS"
  • 00 13 - 0x13 (19) байт имени хоста следует далее
  • 65 78 61 ... 6e 65 74 - "example.ulfheim.net"
Extension - EC Point Formats 00 0b 00 04 03 00 01 02
Клиент указал, что он поддерживает получение точек данных эллиптической кривой в следующих форматах сжатия:
  • 00 0b - назначенное значение для расширения "ec point formats"
  • 00 04 - 4 байта типов формата следует далее
  • 03 - 3 байта типов формата следует далее
  • 00 - назначенное значение для формата "uncompressed"
  • 01 - назначенное значение для формата "ansiX962_compressed_prime"
  • 02 - назначенное значение для формата "ansiX962_compressed_char2"
Extension - Supported Groups 00 0a 00 16 00 14 00 1d 00 17 00 1e 00 19 00 18 01 00 01 01 01 02 01 03 01 04
Клиент указал, что он поддерживает криптографию на эллиптических кривых (EC) для десяти типов кривых. Чтобы сделать это расширение более общим для других типов криптографии, он называет их "поддерживаемыми группами" вместо "поддерживаемых кривых".

Этот список представлен в порядке убывания предпочтения клиента.
  • 00 0a - назначенное значение для расширения "supported groups"
  • 00 16 - 0x16 (22) байта данных расширения "supported group" следует далее
  • 00 14 - 0x14 (20) байтов данных находятся в списке кривых
  • 00 1d - назначенное значение для кривой "x25519"
  • 00 17 - назначенное значение для кривой "secp256r1"
  • 00 1e - назначенное значение для кривой "x448"
  • 00 19 - назначенное значение для кривой "secp521r1"
  • 00 18 - назначенное значение для кривой "secp384r1"
  • 01 00 - назначенное значение для кривой "ffdhe2048"
  • 01 01 - назначенное значение для кривой "ffdhe3072"
  • 01 02 - назначенное значение для кривой "ffdhe4096"
  • 01 03 - назначенное значение для кривой "ffdhe6144"
  • 01 04 - назначенное значение для кривой "ffdhe8192"
Extension - Session Ticket 00 23 00 00
Клиент указывает, что у него нет билета сеанса для предоставления для этого соединения.
  • 00 23 - назначенное значение для расширения "Session Ticket"
  • 00 00 - 0 байтов данных расширения "Session Ticket" следует далее
Extension - Encrypt-Then-MAC 00 16 00 00
Клиент указывает, что он может поддерживать EtM, что предотвращает определенные уязвимости в более ранних версиях TLS. В TLS 1.3 этот механизм всегда используется, поэтому это расширение не окажет никакого влияния на этот сеанс.
  • 00 16 - назначенное значение для расширения "Encrypt Then MAC"
  • 00 00 - 0 байтов данных расширения "Encrypt Then MAC" следует далее
Extension - Extended Master Secret 00 17 00 00
Клиент указывает поддержку дополнительных криптографических операций которые предотвращают уязвимости в более ранних версиях TLS (см. RFC 7627 для подробностей). В TLS 1.3 уязвимости больше не присутствуют, поэтому это расширение не окажет никакого влияния на этот сеанс.
  • 00 17 - назначенное значение для расширения "Extended Master Secret"
  • 00 00 - 0 байтов данных расширения "Extended Master Secret" следует далее
Extension - Signature Algorithms 00 0d 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01
Это расширение указывает, какой алгоритм подписи поддерживает клиент. Это может повлиять на сертификат, который сервер представляет клиенту, а также подпись, отправляемая сервером в записи CertificateVerify.

Этот список представлен в порядке убывания предпочтения клиента.
  • 00 0d - назначенное значение для расширения "Signature Algorithms"
  • 00 1e - 0x1E (30) байтов данных расширения "Signature Algorithms" следует далее
  • 00 1c - 0x1C (28) байтов данных находятся в следующем списке алгоритмов
  • 04 03 - назначенное значение для ECDSA-SECP256r1-SHA256
  • 05 03 - назначенное значение для ECDSA-SECP384r1-SHA384
  • 06 03 - назначенное значение для ECDSA-SECP521r1-SHA512
  • 08 07 - назначенное значение для ED25519
  • 08 08 - назначенное значение для ED448
  • 08 09 - назначенное значение для RSA-PSS-PSS-SHA256
  • 08 0a - назначенное значение для RSA-PSS-PSS-SHA384
  • 08 0b - назначенное значение для RSA-PSS-PSS-SHA512
  • 08 04 - назначенное значение для RSA-PSS-RSAE-SHA256
  • 08 05 - назначенное значение для RSA-PSS-RSAE-SHA384
  • 08 06 - назначенное значение для RSA-PSS-RSAE-SHA512
  • 04 01 - назначенное значение для RSA-PKCS1-SHA256
  • 05 01 - назначенное значение для RSA-PKCS1-SHA384
  • 06 01 - назначенное значение для RSA-PKCS1-SHA512
Extension - Supported Versions 00 2b 00 03 02 03 04
Клиент указывает свою поддержку TLS 1.3. Это единственное указание в записи Client Hello, которое намекает на то, что клиент поддерживает TLS 1.3, поскольку по соображениям совместимости он в остальном притворялся попыткой соединения TLS 1.2.
  • 00 2b - назначенное значение для расширения "Supported Versions"
  • 00 03 - 3 байта данных расширения "Supported Versions" следует далее
  • 02 - 2 байта версий TLS следует далее
  • 03 04 - назначенное значение для TLS 1.3
Extension - PSK Key Exchange Modes 00 2d 00 02 01 01
Клиент указывает доступные режимы для установления ключей из предварительно распределенных ключей (PSK). Поскольку мы не используем PSK в этом сеансе, это расширение не оказывает никакого влияния.
  • 00 2d - назначенное значение для расширения "PSK Key Exchange Modes"
  • 00 02 - 2 байта данных расширения "PSK Key Exchange Modes" следует далее
  • 01 - 1 байт режимов обмена следует далее
  • 01 - назначенное значение для "PSK with (EC)DHE key establishment"
Extension - Key Share 00 33 00 26 00 24 00 1d 00 20 35 80 72 d6 36 58 80 d1 ae ea 32 9a df 91 21 38 38 51 ed 21 a2 8e 3b 75 e9 65 d0 d2 cd 16 62 54
Клиент отправляет один или несколько эфемерных открытых ключей с использованием алгоритма(ов), которые, по его мнению, сервер будет поддерживать. Это позволяет остальную часть рукопожатия после сообщений ClientHello и ServerHello зашифровать, в отличие от предыдущих версий протокола, где рукопожатие отправлялось в открытом виде.
  • 00 33 - назначенное значение для расширения "Key Share"
  • 00 26 - 0x26 (38) байтов данных расширения "Key Share" следует далее
  • 00 24 - 0x24 (36) байтов данных обмена ключами следует далее
  • 00 1d - назначенное значение для x25519 (обмен ключами через curve25519)
  • 00 20 - 0x20 (32) байта открытого ключа следует далее
  • 35 80 ... 62 54 - открытый ключ из шага "Генерация обмена ключами клиента"
Генерация обмена ключами сервера

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

Объяснение обмена ключами можно найти на сайте X25519, но его не нужно понимать глубоко для остальной части этой страницы.

Закрытый ключ выбирается путем выбора целого числа между 0 и 2256-1. Сервер делает это, генерируя 32 байта (256 бит) случайных данных. Закрытый ключ выбран следующий:

909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf
Открытый ключ создается из закрытого ключа, как объяснено на сайте X25519. Вычисленный открытый ключ:
9fd7ad6dcff4298dd3f96d5b1b2af910a0535b1488d7f8fabb349a982880b615
Вычисление открытого ключа можно подтвердить в командной строке:
### requires openssl 1.1.0 or higher
$ openssl pkey -noout -text < server-ephemeral-private.key

X25519 Private-Key:
priv:
    90:91:92:93:94:95:96:97:98:99:9a:9b:9c:9d:9e:
    9f:a0:a1:a2:a3:a4:a5:a6:a7:a8:a9:aa:ab:ac:ad:
    ae:af
pub:
    9f:d7:ad:6d:cf:f4:29:8d:d3:f9:6d:5b:1b:2a:f9:
    10:a0:53:5b:14:88:d7:f8:fa:bb:34:9a:98:28:80:
    b6:15
Server Hello
Сервер отвечает "Hello". Сервер предоставляет информацию, включающую следующее:
  • случайные данные сервера (используются позже в рукопожатии)
  • выбранный набор шифров
  • открытый ключ для обмена ключами
  • согласованная версия протокола
Record Header 16 03 03 00 7a
Сеансы TLS разбиты на отправку и получение "записей", которые представляют собой блоки данных с типом, версией протокола, и длиной.
  • 16 - тип 0x16 (запись рукопожатия)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 7a - 0x7A (122) байтов сообщения рукопожатия следует далее
Handshake Header 02 00 00 76
Каждое сообщение рукопожатия начинается с типа и длины.
  • 02 - тип сообщения рукопожатия 0x02 (server hello)
  • 00 00 76 - 0x76 (118) байтов данных server hello следует далее
Server Version 03 03
Указана версия протокола "3,3" (означает TLS 1.2). Поскольку были созданы и широко распространены промежуточные устройства, которые не пропускают версии протоколов, которые они не распознают, сеанс TLS 1.3 должен быть замаскирован под сеанс TLS 1.2. Это поле больше не используется для согласования версий и жестко закодировано в версии 1.2. Вместо этого согласование версий выполняется с помощью расширения "Supported Versions" ниже.

Необычный номер версии ("3,3", представляющий TLS 1.2) связано с тем, что TLS 1.0 является незначительным пересмотром протокола SSL 3.0. Следовательно TLS 1.0 представлен как "3,1", TLS 1.1 - "3,2" и так далее.
Server Random 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
Сервер предоставляет 32 байта случайных данных. Эти данные будут использованы позже в сеансе. В этом примере мы сделали случайные данные предсказуемой строкой.
Session ID 20 e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff
Это устаревшее поле больше не используется для идентификации и повторного использования сеансов. Вместо этого сервер повторяет ID сеанса, предоставленный клиентом, если таковой имеется.
  • 20 - 0x20 (32) байта ID сеанса следует далее
  • e0 e1 ... fe ff - ID сеанса скопирован из Client Hello
Cipher Suite 13 02
Сервер выбрал набор шифров 0x1302 (TLS_AES_256_GCM_SHA384) из списка опций, предоставленных клиентом.
Compression Method 00
Сервер выбрал метод сжатия 0x00 ("Null", который не выполняет сжатие) из списка опций, предоставленных клиентом.
Extensions Length 00 2e
Сервер вернул список расширений клиенту. Поскольку серверу запрещено отвечать расширением которое клиент не отправил в своем сообщении hello сервер знает, что клиент понимает и поддерживает все перечисленные расширения.
  • 00 2e - расширения займут 0x2E (46) байтов данных
Extension - Supported Versions 00 2b 00 02 03 04
Сервер указывает согласованную версию TLS 1.3.
  • 00 2b - назначенное значение для расширения "Supported Versions"
  • 00 02 - 2 байта данных расширения "Supported Versions" следует далее
  • 03 04 - назначенное значение для TLS 1.3
Extension - Key Share 00 33 00 24 00 1d 00 20 9f d7 ad 6d cf f4 29 8d d3 f9 6d 5b 1b 2a f9 10 a0 53 5b 14 88 d7 f8 fa bb 34 9a 98 28 80 b6 15
Сервер отправляет открытый ключ, используя алгоритм открытого ключа, отправленного клиентом. Как только это будет отправлено ключи шифрования могут быть рассчитаны, и остальная часть рукопожатие будет зашифровано, в отличие от предыдущих версий протокола, где рукопожатие отправлялось в открытом виде.
  • 00 33 - назначенное значение для расширения "Key Share"
  • 00 24 - 0x24 (36) байтов данных расширения "Key Share" следует далее
  • 00 1d - назначенное значение для x25519 (обмен ключами через curve25519)
  • 00 20 - 0x20 (32) байта открытого ключа следует далее
  • 9f d7 ... b6 15 - открытый ключ из шага "Генерация обмена ключами сервера"
Расчет ключей рукопожатия сервера
Теперь у сервера есть информация для расчета ключей, используемых для шифрования остальной части рукопожатия. Он использует следующие информацию в этом расчете: Во-первых, сервер находит общий секрет, который является результатом обмена ключами, который позволяет клиенту и серверу договориться о числе. Сервер умножает открытый ключ клиента на закрытый ключ сервера, используя алгоритм curve25519(). 32-байтовый результат оказывается следующим:
df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624
Я предоставил инструмент для выполнения этого расчета:
$ cc -o curve25519-mult curve25519-mult.c
$ ./curve25519-mult server-ephemeral-private.key \
                    client-ephemeral-public.key | hexdump

0000000 df 4a 29 1b aa 1e b7 cf a6 93 4b 29 b4 74 ba ad
0000010 26 97 e2 9f 1f 92 0d cc 77 c8 a0 a0 88 44 76 24
Затем мы вычисляем хэш SHA384 всех сообщений рукопожатия к этому моменту (ClientHello и ServerHello). Хэш не включает 5-байтовые заголовки "record". Этот "hello_hash" e05f64fcd082bdb0dce473adf669c2769f257a1c75a51b7887468b5e0e7a7de4f4d34555112077f16e079019d5a845bd:
$ (tail -c +6 clienthello; tail -c +6 serverhello) | openssl sha384
e05f64fcd082bdb0dce473adf669c2769f257a1c75a51b7887468b5e0e7a7de4f4d34555112077f16e079019d5a845bd
Затем мы передаем хэш и общий секрет в набор операций получения ключа, предназначенных для обеспечения целостности процесса рукопожатия и защиты от известных и возможных атак:
early_secret = HKDF-Extract(salt: 00, key: 00...)
empty_hash = SHA384("")
derived_secret = HKDF-Expand-Label(key: early_secret, label: "derived", ctx: empty_hash, len: 48)
handshake_secret = HKDF-Extract(salt: derived_secret, key: shared_secret)
client_secret = HKDF-Expand-Label(key: handshake_secret, label: "c hs traffic", ctx: hello_hash, len: 48)
server_secret = HKDF-Expand-Label(key: handshake_secret, label: "s hs traffic", ctx: hello_hash, len: 48)
client_handshake_key = HKDF-Expand-Label(key: client_secret, label: "key", ctx: "", len: 32)
server_handshake_key = HKDF-Expand-Label(key: server_secret, label: "key", ctx: "", len: 32)
client_handshake_iv = HKDF-Expand-Label(key: client_secret, label: "iv", ctx: "", len: 12)
server_handshake_iv = HKDF-Expand-Label(key: server_secret, label: "iv", ctx: "", len: 12)
Здесь представлены два новых криптографических метода:
  • HKDF-Extract - с учетом соли и некоторых байтов ключевого материала создайте 384 бита (48 байтов) нового ключевого материала, при этом энтропия входного ключевого материала равномерно распределена в выходе.
  • HKDF-Expand-Label - с учетом входных данных ключевого материала, метки и контекстных данных создайте новый ключ запрошенной длины.
Я создал инструмент HKDF для выполнения этих операций в командной строке.
$ hello_hash=e05f64fcd082bdb0dce473adf669c2769f257a1c75a51b7887468b5e0e7a7de4f4d34555112077f16e079019d5a845bd
$ shared_secret=df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624
$ zero_key=000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
$ early_secret=$(./hkdf-384 extract 00 $zero_key)
$ empty_hash=$(openssl sha384 < /dev/null | sed -e 's/.* //')
$ derived_secret=$(./hkdf-384 expandlabel $early_secret "derived" $empty_hash 48)
$ handshake_secret=$(./hkdf-384 extract $derived_secret $shared_secret)
$ csecret=$(./hkdf-384 expandlabel $handshake_secret "c hs traffic" $hello_hash 48)
$ ssecret=$(./hkdf-384 expandlabel $handshake_secret "s hs traffic" $hello_hash 48)
$ client_handshake_key=$(./hkdf-384 expandlabel $csecret "key" "" 32)
$ server_handshake_key=$(./hkdf-384 expandlabel $ssecret "key" "" 32)
$ client_handshake_iv=$(./hkdf-384 expandlabel $csecret "iv" "" 12)
$ server_handshake_iv=$(./hkdf-384 expandlabel $ssecret "iv" "" 12)
$ echo hssec: $handshake_secret
$ echo ssec: $ssecret
$ echo csec: $csecret
$ echo skey: $server_handshake_key
$ echo siv: $server_handshake_iv
$ echo ckey: $client_handshake_key
$ echo civ: $client_handshake_iv

hssec: bdbbe8757494bef20de932598294ea65b5e6bf6dc5c02a960a2de2eaa9b07c929078d2caa0936231c38d1725f179d299
ssec: 23323da031634b241dd37d61032b62a4f450584d1f7f47983ba2f7cc0cdcc39a68f481f2b019f9403a3051908a5d1622
csec: db89d2d6df0e84fed74a2288f8fd4d0959f790ff23946cdf4c26d85e51bebd42ae184501972f8d30c4a3e4a3693d0ef0
skey: 9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
siv: 9563bc8b590f671f488d2da3
ckey: 1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69
civ: 4256d2e0e88babdd05eb2f27
Отсюда мы получаем следующие данные ключа:
  • секрет рукопожатия: bdbbe8757494bef20de932598294ea65b5e6bf6dc5c02a960a2de2eaa9b07c929078d2caa0936231c38d1725f179d299
  • секрет трафика рукопожатия сервера: 23323da031634b241dd37d61032b62a4f450584d1f7f47983ba2f7cc0cdcc39a68f481f2b019f9403a3051908a5d1622.
  • секрет трафика рукопожатия клиента: db89d2d6df0e84fed74a2288f8fd4d0959f790ff23946cdf4c26d85e51bebd42ae184501972f8d30c4a3e4a3693d0ef0.
  • ключ рукопожатия сервера: 9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
  • вектор инициализации рукопожатия сервера: 9563bc8b590f671f488d2da3
  • ключ рукопожатия клиента: 1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69
  • вектор инициализации рукопожатия клиента: 4256d2e0e88babdd05eb2f27
Расчет ключей рукопожатия клиента
Теперь у клиента есть информация для расчета ключей, используемых для шифрования остальной части рукопожатия. Он использует следующие информацию в этом расчете: Во-первых, клиент находит общий секрет, который является результатом обмена ключами, который позволяет клиенту и серверу договориться о числе. Клиент умножает открытый ключ сервера на закрытый ключ клиента, используя алгоритм curve25519(). Свойства умножения на эллиптической кривой приведут к тому, что это приведет к тому же числу, которое было найдено сервером при его умножении. 32-байтовый результат оказывается следующим:
df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624
Я предоставил инструмент для выполнения этого расчета:
$ cc -o curve25519-mult curve25519-mult.c
$ ./curve25519-mult client-ephemeral-private.key \
                    server-ephemeral-public.key | hexdump

0000000 df 4a 29 1b aa 1e b7 cf a6 93 4b 29 b4 74 ba ad
0000010 26 97 e2 9f 1f 92 0d cc 77 c8 a0 a0 88 44 76 24
Поскольку общий секрет выше - это то же самое число, которое было вычислено сервером в "Расчет ключей рукопожатия сервера", остальная часть расчет идентичен, и найдены те же значения:
  • ключ рукопожатия сервера: 9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
  • вектор инициализации рукопожатия сервера: 9563bc8b590f671f488d2da3
  • ключ рукопожатия клиента: 1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69
  • вектор инициализации рукопожатия клиента: 4256d2e0e88babdd05eb2f27
Server Change Cipher Spec
Эта запись служила цели в более ранних версиях TLS, но больше не нужна. В "режиме совместимости с промежуточными устройствами" эта запись отправляется, чтобы помочь замаскировать сеанс под сеанс TLS 1.2.
Record Header 14 03 03 00 01 01
Сеансы TLS разбиты на отправку и получение "записей", которые представляют собой блоки данных с типом, версией протокола, и длиной.
  • 14 - тип 0x14 (запись ChangeCipherSpec)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 01 - длина полезной нагрузки записи составляет 1 байт
  • 01 - полезная нагрузка этого сообщения определяется как байт 0x01
Wrapped Record
Соединение (включая рукопожатие) зашифровано с этого момента. Шифрование данных рукопожатия является новым в TLS 1.3.

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

Эта обернутая запись обсуждается в отдельном разделе ниже.
Record Header 17 03 03 00 17
Записи TLS 1.3 шифруются в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 17 - 0x17 (23) байта обернутых данных следует далее
Encrypted Data 6b e0 2f 9d a7 c2 dc
Эти данные зашифрованы с помощью ключа рукопожатия сервера.
Auth Tag 9d de f5 6f 24 68 b9 0a df a2 51 01 ab 03 44 ae
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа рукопожатия сервера и вектора инициализации рукопожатия сервера, которые были сгенерированы на шаге "Расчет ключей рукопожатия сервера". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 0. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030017
$ authtag=9ddef56f2468b90adfa25101ab0344ae
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "6b e0 2f 9d a7 c2 dc" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  08 00 00 02 00 00 16                              |.......|
Encrypted Extensions 08 00 00 02 00 00
Это сообщение рукопожатия представлено в отдельном разделе ниже.
Record Type 16
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 16 - тип 0x16 (запись рукопожатия)
Server Encrypted Extensions
Любые расширения, которые не нужны для согласования ключей шифрования должны быть перечислены здесь, чтобы их можно было скрыть от злоумышленников и промежуточных устройств.
Handshake Header 08 00 00 02
Каждое сообщение рукопожатия начинается с типа и длины.
  • 08 - тип сообщения рукопожатия 0x08 (зашифрованные расширения)
  • 00 00 02 - 2 байта данных сообщения рукопожатия следует далее
Extensions 00 00
  • 00 00 - 0 байтов данных расширения следует далее
Wrapped Record
Шифрование данных рукопожатия является новым в TLS 1.3.

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

Эта обернутая запись обсуждается в отдельном разделе ниже.
Record Header 17 03 03 03 43
Записи TLS 1.3 шифруются в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 03 43 - 0x343 (835) байтов обернутых данных следует далее
Encrypted Data ba f0 0a 9b e5 0f 3f 23 07 e7 26 ed cb da cb e4 b1 86 16 44 9d 46 c6 20 7a f6 e9 95 3e e5 d2 41 1b a6 5d 31 fe af 4f 78 76 4f 2d 69 39 87 18 6c c0 13 29 c1 87 a5 e4 60 8e 8d 27 b3 18 e9 8d d9 47 69 f7 73 9c e6 76 83 92 ca ca 8d cc 59 7d 77 ec 0d 12 72 23 37 85 f6 e6 9d 6f 43 ef fa 8e 79 05 ed fd c4 03 7e ee 59 33 e9 90 a7 97 2f 20 69 13 a3 1e 8d 04 93 13 66 d3 d8 bc d6 a4 a4 d6 47 dd 4b d8 0b 0f f8 63 ce 35 54 83 3d 74 4c f0 e0 b9 c0 7c ae 72 6d d2 3f 99 53 df 1f 1c e3 ac eb 3b 72 30 87 1e 92 31 0c fb 2b 09 84 86 f4 35 38 f8 e8 2d 84 04 e5 c6 c2 5f 66 a6 2e be 3c 5f 26 23 26 40 e2 0a 76 91 75 ef 83 48 3c d8 1e 6c b1 6e 78 df ad 4c 1b 71 4b 04 b4 5f 6a c8 d1 06 5a d1 8c 13 45 1c 90 55 c4 7d a3 00 f9 35 36 ea 56 f5 31 98 6d 64 92 77 53 93 c4 cc b0 95 46 70 92 a0 ec 0b 43 ed 7a 06 87 cb 47 0c e3 50 91 7b 0a c3 0c 6e 5c 24 72 5a 78 c4 5f 9f 5f 29 b6 62 68 67 f6 f7 9c e0 54 27 35 47 b3 6d f0 30 bd 24 af 10 d6 32 db a5 4f c4 e8 90 bd 05 86 92 8c 02 06 ca 2e 28 e4 4e 22 7a 2d 50 63 19 59 35 df 38 da 89 36 09 2e ef 01 e8 4c ad 2e 49 d6 2e 47 0a 6c 77 45 f6 25 ec 39 e4 fc 23 32 9c 79 d1 17 28 76 80 7c 36 d7 36 ba 42 bb 69 b0 04 ff 55 f9 38 50 dc 33 c1 f9 8a bb 92 85 83 24 c7 6f f1 eb 08 5d b3 c1 fc 50 f7 4e c0 44 42 e6 22 97 3e a7 07 43 41 87 94 c3 88 14 0b b4 92 d6 29 4a 05 40 e5 a5 9c fa e6 0b a0 f1 48 99 fc a7 13 33 31 5e a0 83 a6 8e 1d 7c 1e 4c dc 2f 56 bc d6 11 96 81 a4 ad bc 1b bf 42 af d8 06 c3 cb d4 2a 07 6f 54 5d ee 4e 11 8d 0b 39 67 54 be 2b 04 2a 68 5d d4 72 7e 89 c0 38 6a 94 d3 cd 6e cb 98 20 e9 d4 9a fe ed 66 c4 7e 6f c2 43 ea be bb cb 0b 02 45 38 77 f5 ac 5d bf bd f8 db 10 52 a3 c9 94 b2 24 cd 9a aa f5 6b 02 6b b9 ef a2 e0 13 02 b3 64 01 ab 64 94 e7 01 8d 6e 5b 57 3b d3 8b ce f0 23 b1 fc 92 94 6b bc a0 20 9c a5 fa 92 6b 49 70 b1 00 91 03 64 5c b1 fc fe 55 23 11 ff 73 05 58 98 43 70 03 8f d2 cc e2 a9 1f c7 4d 6f 3e 3e a9 f8 43 ee d3 56 f6 f8 2d 35 d0 3b c2 4b 81 b5 8c eb 1a 43 ec 94 37 e6 f1 e5 0e b6 f5 55 e3 21 fd 67 c8 33 2e b1 b8 32 aa 8d 79 5a 27 d4 79 c6 e2 7d 5a 61 03 46 83 89 19 03 f6 64 21 d0 94 e1 b0 0a 9a 13 8d 86 1e 6f 78 a2 0a d3 e1 58 00 54 d2 e3 05 25 3c 71 3a 02 fe 1e 28 de ee 73 36 24 6f 6a e3 43 31 80 6b 46 b4 7b 83 3c 39 b9 d3 1c d3 00 c2 a6 ed 83 13 99 77 6d 07 f5 70 ea f0 05 9a 2c 68 a5 f3 ae 16 b6 17 40 4a f7 b7 23 1a 4d 94 27 58 fc 02 0b 3f 23 ee 8c 15 e3 60 44 cf d6 7c d6 40 99 3b 16 20 75 97 fb f3 85 ea 7a 4d 99 e8 d4 56 ff 83 d4 1f 7b 8b 4f 06 9b 02 8a 2a 63 a9 19 a7 0e 3a 10 e3 08 41
Эти данные зашифрованы с помощью ключа рукопожатия сервера.
Auth Tag 58 fa a5 ba fa 30 18 6c 6b 2f 23 8e b5 30 c7 3e
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа рукопожатия сервера и вектора инициализации рукопожатия сервера, которые были сгенерированы на шаге "Расчет ключей рукопожатия сервера". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 1. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030343
$ authtag=58faa5bafa30186c6b2f238eb530c73e
$ recordnum=1
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "ba f0 0a 9b e5 0f 3f 23 07 e7 26 ed cb da cb e4 b1 86 16
  ... snip ...
  a9 19 a7 0e 3a 10 e3 08 41" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  08 00 00 02 00 00 0b 00  03 2e 00 00 03 2a 00 03  |.............*..|
00000010  25 30 82 03 21 30 82 02  09 a0 03 02 01 02 02 08  |58..!0..........|
00000020  15 5a 92 ad c2 04 8f 90  30 0d 06 09 2a 86 48 86  |.Z......0...*.H.|
00000000  0b 00 03 2e 00 00 03 2a  00 03 25 30 82 03 21 30  |.......*..58..!0|
00000010  82 02 09 a0 03 02 01 02  02 08 15 5a 92 ad c2 04  |...........Z....|
00000020  8f 90 30 0d 06 09 2a 86  48 86 f7 0d 01 01 0b 05  |..0...*.H.......|
00000030  00 30 22 31 0b 30 09 06  03 55 04 06 13 02 55 53  |.0"1.0...U....US|
00000040  31 13 30 11 06 03 55 04  0a 13 0a 45 78 61 6d 70  |1.0...U....Examp|
... snip ...
Server Certificate 0b 00 03 2e 00 00 03 2a 00 03 25 30 82 03 21 30 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0 00 00
Это сообщение рукопожатия представлено в отдельном разделе ниже.
Record Type 16
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 16 - тип 0x16 (запись рукопожатия)
Server Certificate
Сервер отправляет один или несколько сертификатов:
  • сертификат для этого хоста, содержащий имя хоста, открытый ключ и подпись от третьей стороны, подтверждающую что владелец имени хоста сертификата владеет закрытым ключом для этого сертификата
  • необязательный список дополнительных сертификатов, каждый из которых подписывает предыдущий сертификат, и которые образуют цепочку доверия ведущую от сертификата хоста к доверенному сертификату который был предустановлен на клиенте
В целях сохранения небольшого размера этого примера мы отправляем только сертификат хоста. Сертификаты находятся в двоичном формате называемом DER который вы можете изучить здесь.
Handshake Header 0b 00 03 2e
Каждое сообщение рукопожатия начинается с типа и длины.
  • 0b - тип сообщения рукопожатия 0x0B (certificate)
  • 00 03 2e - 0x32E (814) байтов полезной нагрузки сертификата следует далее
Request Context 00
Эта запись пуста, потому что этот сертификат не был отправлен в ответ на запрос сертификата.
  • 00 - 0 байтов контекста запроса следует далее
Certificates Length 00 03 2a
  • 00 03 2a - 0x32A (810) байтов сертификатов следует далее
Certificate Length 00 03 25
Длина первого (и единственного) сертифика та.
  • 00 03 25 - 0x325 (805) байтов сертификата следует далее
Certificate 30 82 03 21 30 82 02 09 a0 03 02 01 02 02 08 15 5a 92 ad c2 04 8f 90 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 22 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 13 30 11 06 03 55 04 0a 13 0a 45 78 61 6d 70 6c 65 20 43 41 30 1e 17 0d 31 38 31 30 30 35 30 31 33 38 31 37 5a 17 0d 31 39 31 30 30 35 30 31 33 38 31 37 5a 30 2b 31 0b 30 09 06 03 55 04 06 13 02 55 53 31 1c 30 1a 06 03 55 04 03 13 13 65 78 61 6d 70 6c 65 2e 75 6c 66 68 65 69 6d 2e 6e 65 74 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 01 00 c4 80 36 06 ba e7 47 6b 08 94 04 ec a7 b6 91 04 3f f7 92 bc 19 ee fb 7d 74 d7 a8 0d 00 1e 7b 4b 3a 4a e6 0f e8 c0 71 fc 73 e7 02 4c 0d bc f4 bd d1 1d 39 6b ba 70 46 4a 13 e9 4a f8 3d f3 e1 09 59 54 7b c9 55 fb 41 2d a3 76 52 11 e1 f3 dc 77 6c aa 53 37 6e ca 3a ec be c3 aa b7 3b 31 d5 6c b6 52 9c 80 98 bc c9 e0 28 18 e2 0b f7 f8 a0 3a fd 17 04 50 9e ce 79 bd 9f 39 f1 ea 69 ec 47 97 2e 83 0f b5 ca 95 de 95 a1 e6 04 22 d5 ee be 52 79 54 a1 e7 bf 8a 86 f6 46 6d 0d 9f 16 95 1a 4c f7 a0 46 92 59 5c 13 52 f2 54 9e 5a fb 4e bf d7 7a 37 95 01 44 e4 c0 26 87 4c 65 3e 40 7d 7d 23 07 44 01 f4 84 ff d0 8f 7a 1f a0 52 10 d1 f4 f0 d5 ce 79 70 29 32 e2 ca be 70 1f df ad 6b 4b b7 11 01 f4 4b ad 66 6a 11 13 0f e2 ee 82 9e 4d 02 9d c9 1c dd 67 16 db b9 06 18 86 ed c1 ba 94 21 02 03 01 00 01 a3 52 30 50 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 02 06 08 2b 06 01 05 05 07 03 01 30 1f 06 03 55 1d 23 04 18 30 16 80 14 89 4f de 5b cc 69 e2 52 cf 3e a3 00 df b1 97 b8 1d e1 c1 46 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 82 01 01 00 59 16 45 a6 9a 2e 37 79 e4 f6 dd 27 1a ba 1c 0b fd 6c d7 55 99 b5 e7 c3 6e 53 3e ff 36 59 08 43 24 c9 e7 a5 04 07 9d 39 e0 d4 29 87 ff e3 eb dd 09 c1 cf 1d 91 44 55 87 0b 57 1d d1 9b df 1d 24 f8 bb 9a 11 fe 80 fd 59 2b a0 39 8c de 11 e2 65 1e 61 8c e5 98 fa 96 e5 37 2e ef 3d 24 8a fd e1 74 63 eb bf ab b8 e4 d1 ab 50 2a 54 ec 00 64 e9 2f 78 19 66 0d 3f 27 cf 20 9e 66 7f ce 5a e2 e4 ac 99 c7 c9 38 18 f8 b2 51 07 22 df ed 97 f3 2e 3e 93 49 d4 c6 6c 9e a6 39 6d 74 44 62 a0 6b 42 c6 d5 ba 68 8e ac 3a 01 7b dd fc 8e 2c fc ad 27 cb 69 d3 cc dc a2 80 41 44 65 d3 ae 34 8c e0 f3 4a b2 fb 9c 61 83 71 31 2b 19 10 41 64 1c 23 7f 11 a5 d6 5c 84 4f 04 04 84 99 38 71 2b 95 9e d6 85 bc 5c 5d d6 45 ed 19 90 94 73 40 29 26 dc b4 0e 34 69 a1 59 41 e8 e2 cc a8 4b b6 08 46 36 a0
Сертификат находится в кодировке ASN.1 DER. Подробности этого формата и содержимое этой двоичной полезной нагрузки документированы на другой странице. Сертификат можно преобразовать в двоичные данные в этом сообщении в командной строке:
$ openssl x509 -outform der < server.crt | hexdump

0000000 30 82 03 21 30 82 02 09 a0 03 02 01 02 02 08 15
0000010 5a 92 ad c2 04 8f 90 30 0d 06 09 2a 86 48 86 f7
... snip ...
Certificate Extensions 00 00
Сервер может предоставить данные расширения для сертификата.
  • 00 00 - 0 байтов данных расширения следует далее
Wrapped Record
Шифрование данных рукопожатия является новым в TLS 1.3.

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

Эта обернутая запись обсуждается в отдельном разделе ниже.
Record Header 17 03 03 01 19
Записи TLS 1.3 шифруются в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 01 19 - 0x119 (281) байтов обернутых данных следует далее
Encrypted Data 73 71 9f ce 07 ec 2f 6d 3b ba 02 92 a0 d4 0b 27 70 c0 6a 27 17 99 a5 33 14 f6 f7 7f c9 5c 5f e7 b9 a4 32 9f d9 54 8c 67 0e be ea 2f 2d 5c 35 1d d9 35 6e f2 dc d5 2e b1 37 bd 3a 67 65 22 f8 cd 0f b7 56 07 89 ad 7b 0e 3c ab a2 e3 7e 6b 41 99 c6 79 3b 33 46 ed 46 cf 74 0a 9f a1 fe c4 14 dc 71 5c 41 5c 60 e5 75 70 3c e6 a3 4b 70 b5 19 1a a6 a6 1a 18 fa ff 21 6c 68 7a d8 d1 7e 12 a7 e9 99 15 a6 11 bf c1 a2 be fc 15 e6 e9 4d 78 46 42 e6 82 fd 17 38 2a 34 8c 30 10 56 b9 40 c9 84 72 00 40 8b ec 56 c8 1e a3 d7 21 7a b8 e8 5a 88 71 53 95 89 9c 90 58 7f 72 e8 dd d7 4b 26 d8 ed c1 c7 c8 37 d9 f2 eb bc 26 09 62 21 90 38 b0 56 54 a6 3a 0b 12 99 9b 4a 83 06 a3 dd cc 0e 17 c5 3b a8 f9 c8 03 63 f7 84 13 54 d2 91 b4 ac e0 c0 f3 30 c0 fc d5 aa 9d ee f9 69 ae 8a b2 d9 8d a8 8e bb 6e a8 0a 3a 11 f0 0e a2
Эти данные зашифрованы с помощью ключа рукопожатия сервера.
Auth Tag 96 a3 23 23 67 ff 07 5e 1c 66 dd 9c be dc 47 13
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа рукопожатия сервера и вектора инициализации рукопожатия сервера, которые были сгенерированы на шаге "Расчет ключей рукопожатия сервера". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 2. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030119
$ authtag=96a3232367ff075e1c66dd9cbedc4713
$ recordnum=2
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "73 71 9f ce 07 ec 2f 6d 3b ba 02 92 a0 d4 0b 27 70 c0 6a 27
  ... snip ...
  d9 8d a8 8e bb 6e a8 0a 3a 11 f0 0e a2" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  0f 00 01 04 08 04 01 00  5c bb 24 c0 40 93 32 da  |........\.$.@.2.|
00000010  a9 20 bb ab bd b9 bd 50  17 0b e4 9c fb e0 a4 10  |. .....P........|
00000020  7f ca 6f fb 10 68 e6 5f  96 9e 6d e7 d4 f9 e5 60  |..o..h._..m....`|
... snip ...
Server Certificate Verify 0f 00 01 04 08 04 01 00 5c bb 24 c0 40 93 32 da a9 20 bb ab bd b9 bd 50 17 0b e4 9c fb e0 a4 10 7f ca 6f fb 10 68 e6 5f 96 9e 6d e7 d4 f9 e5 60 38 d6 7c 69 c0 31 40 3a 7a 7c 0b cc 86 83 e6 57 21 a0 c7 2c c6 63 40 19 ad 1d 3a d2 65 a8 12 61 5b a3 63 80 37 20 84 f5 da ec 7e 63 d3 f4 93 3f 27 22 74 19 a6 11 03 46 44 dc db c7 be 3e 74 ff ac 47 3f aa ad de 8c 2f c6 5f 32 65 77 3e 7e 62 de 33 86 1f a7 05 d1 9c 50 6e 89 6c 8d 82 f5 bc f3 5f ec e2 59 b7 15 38 11 5e 9c 8c fb a6 2e 49 bb 84 74 f5 85 87 b1 1b 8a e3 17 c6 33 e9 c7 6c 79 1d 46 62 84 ad 9c 4f f7 35 a6 d2 e9 63 b5 9b bc a4 40 a3 07 09 1a 1b 4e 46 bc c7 a2 f9 fb 2f 1c 89 8e cb 19 91 8b e4 12 1d 7e 8e d0 4c d5 0c 9a 59 e9 87 98 01 07 bb bf 29 9c 23 2e 7f db e1 0a 4c fd ae 5c 89 1c 96 af df f9 4b 54 cc d2 bc 19 d3 cd aa 66 44 85 9c
Это сообщение рукопожатия представлено в отдельном разделе ниже.
Record Type 16
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 16 - тип 0x16 (запись рукопожатия)
Server Certificate Verify
Сервер предоставляет информацию, которая связывает открытый ключ сгенерированный во время "Генерации обмена ключами сервера", с владением закрытым ключом сертификата.
Handshake Header 0f 00 01 04
Каждое сообщение рукопожатия начинается с типа и длины.
  • 0f - тип сообщения рукопожатия 0x0f (certificate verify)
  • 00 01 04 - 0x104 (260) байтов данных сообщения рукопожатия следует далее
Signature 08 04 01 00 5c bb 24 c0 40 93 32 da a9 20 bb ab bd b9 bd 50 17 0b e4 9c fb e0 a4 10 7f ca 6f fb 10 68 e6 5f 96 9e 6d e7 d4 f9 e5 60 38 d6 7c 69 c0 31 40 3a 7a 7c 0b cc 86 83 e6 57 21 a0 c7 2c c6 63 40 19 ad 1d 3a d2 65 a8 12 61 5b a3 63 80 37 20 84 f5 da ec 7e 63 d3 f4 93 3f 27 22 74 19 a6 11 03 46 44 dc db c7 be 3e 74 ff ac 47 3f aa ad de 8c 2f c6 5f 32 65 77 3e 7e 62 de 33 86 1f a7 05 d1 9c 50 6e 89 6c 8d 82 f5 bc f3 5f ec e2 59 b7 15 38 11 5e 9c 8c fb a6 2e 49 bb 84 74 f5 85 87 b1 1b 8a e3 17 c6 33 e9 c7 6c 79 1d 46 62 84 ad 9c 4f f7 35 a6 d2 e9 63 b5 9b bc a4 40 a3 07 09 1a 1b 4e 46 bc c7 a2 f9 fb 2f 1c 89 8e cb 19 91 8b e4 12 1d 7e 8e d0 4c d5 0c 9a 59 e9 87 98 01 07 bb bf 29 9c 23 2e 7f db e1 0a 4c fd ae 5c 89 1c 96 af df f9 4b 54 cc d2 bc 19 d3 cd aa 66 44 85 9c
Поскольку сервер генерирует эфемерные ключи для каждого сеанса (необязательно в TLS 1.2, обязательно в TLS 1.3) сеанс не неразрывно связан с сертификатом, как это было в предыдущих версиях TLS, когда открытый/закрытый ключ сертификата использовались для обмена ключами.

Чтобы доказать что сервер владеет сертификатом сервера (что придает сертификату действительность в этом сеансе TLS), он подписывает хэш сообщений рукопожатия, используя закрытый ключ, связанный с сертификатом. Подпись может быть подтверждена клиентом с помощью открытого ключа, включенного в сертификат.
  • 08 04 - зарезервированное значение для подписи RSA-PSS-RSAE-SHA256
  • 01 00 - 0x100 (256) байтов данных подписи следует далее
  • 5c bb 24 ... 44 85 9c - подпись хэша этого рукопожатия
Процесс подписи не может быть воспроизведен побайтно в командной строке, поскольку инструмент подписи вносит случайные или изменяющиеся данные в подпись.

Мы можем проверить подпись, используя сертификат сервера в командной строке:
### find the hash of the conversation to this point, excluding
### 5-byte record headers or 1-byte wrapped record trailers
$ handshake_hash=$((
   tail -c +6 clienthello;
   tail -c +6 serverhello;
   perl -pe 's/.$// if eof' serverextensions;
   perl -pe 's/.$// if eof' servercert) | openssl sha384)

### build the data that was signed:
### 1. add 64 space characters
$ echo -n '                                ' > /tmp/tosign
$ echo -n '                                ' >> /tmp/tosign
### 2. add this fixed string
$ echo -n 'TLS 1.3, server CertificateVerify' >> /tmp/tosign
### 3. add a single null character
$ echo -en '\0' >> /tmp/tosign
### 4. add hash of handshake to this point
$ echo $handshake_hash | xxd -r -p >> /tmp/tosign

### copy the signature that we want to verify
$ echo "5c bb 24 c0 40 93 32 da a9 20 bb ab bd b9 bd 50 17 0b e4 9c
  fb e0 a4 10 7f ca 6f fb 10 68 e6 5f 96 9e 6d e7 d4 f9 e5 60 38 d6
  7c 69 c0 31 40 3a 7a 7c 0b cc 86 83 e6 57 21 a0 c7 2c c6 63 40 19
  ad 1d 3a d2 65 a8 12 61 5b a3 63 80 37 20 84 f5 da ec 7e 63 d3 f4
  93 3f 27 22 74 19 a6 11 03 46 44 dc db c7 be 3e 74 ff ac 47 3f aa
  ad de 8c 2f c6 5f 32 65 77 3e 7e 62 de 33 86 1f a7 05 d1 9c 50 6e
  89 6c 8d 82 f5 bc f3 5f ec e2 59 b7 15 38 11 5e 9c 8c fb a6 2e 49
  bb 84 74 f5 85 87 b1 1b 8a e3 17 c6 33 e9 c7 6c 79 1d 46 62 84 ad
  9c 4f f7 35 a6 d2 e9 63 b5 9b bc a4 40 a3 07 09 1a 1b 4e 46 bc c7
  a2 f9 fb 2f 1c 89 8e cb 19 91 8b e4 12 1d 7e 8e d0 4c d5 0c 9a 59
  e9 87 98 01 07 bb bf 29 9c 23 2e 7f db e1 0a 4c fd ae 5c 89 1c 96
  af df f9 4b 54 cc d2 bc 19 d3 cd aa 66 44 85 9c" | xxd -r -p > /tmp/sig

### extract the public key from the certificate
$ openssl x509 -pubkey -noout -in server.crt > server.pub

### verify the signature
$ cat /tmp/tosign | openssl dgst -verify server.pub -sha256 \
    -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:-1 -signature /tmp/sig

Verified OK
Wrapped Record
Шифрование данных рукопожатия является новым в TLS 1.3.

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

Эта обернутая запись обсуждается в отдельном разделе ниже.
Record Header 17 03 03 00 45
Записи TLS 1.3 шифруются в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 45 - 0x45 (69) байтов обернутых данных следует далее
Encrypted Data 10 61 de 27 e5 1c 2c 9f 34 29 11 80 6f 28 2b 71 0c 10 63 2c a5 00 67 55 88 0d bf 70 06 00 2d 0e 84 fe d9 ad f2 7a 43 b5 19 23 03 e4 df 5c 28 5d 58 e3 c7 62 24
Эти данные зашифрованы с помощью ключа рукопожатия сервера.
Auth Tag 07 84 40 c0 74 23 74 74 4a ec f2 8c f3 18 2f d0
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа рукопожатия сервера и вектора инициализации рукопожатия сервера, которые были сгенерированы на шаге "Расчет ключей рукопожатия сервера". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 3. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Server Handshake Keys Calc" step
$ key=9f13575ce3f8cfc1df64a77ceaffe89700b492ad31b4fab01c4792be1b266b7f
$ iv=9563bc8b590f671f488d2da3
### from this record
$ recdata=1703030045
$ authtag=078440c0742374744aecf28cf3182fd0
$ recordnum=3
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "10 61 de 27 e5 1c 2c 9f 34 29 11 80 6f 28 2b 71 0c 10 63 2c a5 00 67 55 88 0d bf 70 06 00 2d 0e 84 fe d9 ad f2 7a 43 b5 19
  23 03 e4 df 5c 28 5d 58 e3 c7 62 24" | xxd -r -p > /tmp/msg1
$ cat /tmp/msg1 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  14 00 00 30 7e 30 ee cc  b6 b2 3b e6 c6 ca 36 39  |...0~0....;...69|
00000010  92 e8 42 da 87 7e e6 47  15 ae 7f c0 cf 87 f9 e5  |..B..~.G........|
00000020  03 21 82 b5 bb 48 d1 e3  3f 99 79 05 5a 16 0c 8d  |.!...H..?.y.Z...|
00000030  bb b1 56 9c 16                                    |..V..|
Server Finished 14 00 00 30 7e 30 ee cc b6 b2 3b e6 c6 ca 36 39 92 e8 42 da 87 7e e6 47 15 ae 7f c0 cf 87 f9 e5 03 21 82 b5 bb 48 d1 e3 3f 99 79 05 5a 16 0c 8d bb b1 56 9c
Это сообщение рукопожатия представлено в отдельном разделе ниже.
Record Type 16
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 16 - тип 0x16 (запись рукопожатия)
Server Handshake Finished
Чтобы убедиться, что рукопожатие прошло успешно и не было изменено, сервер вычисляет данные проверки, с которыми клиент согласится. Данные проверки строятся из хэша всех сообщений рукопожатия.
Handshake Header 14 00 00 30
Каждое сообщение рукопожатия начинается с типа и длины.
  • 14 - тип сообщения рукопожатия 0x14 (finished)
  • 00 00 30 - 0x30 (48) байтов данных handshake finished следует далее
Verify Data 7e 30 ee cc b6 b2 3b e6 c6 ca 36 39 92 e8 42 da 87 7e e6 47 15 ae 7f c0 cf 87 f9 e5 03 21 82 b5 bb 48 d1 e3 3f 99 79 05 5a 16 0c 8d bb b1 56 9c
Данные verify_data строятся с использованием server_secret из шага "Расчет ключей рукопожатия сервера" и хэша SHA384 каждой записи рукопожатия до этого момента (от Client Hello до Server Certificate Verify).
finished_key = HKDF-Expand-Label(key: server_secret, label: "finished", ctx: "", len: 48)
finished_hash = SHA384(Client Hello ... Server Cert Verify)
verify_data = HMAC-SHA384(key: finished_key, msg: finished_hash)
Мы можем использовать инструмент HKDF для воспроизведения этого в командной строке.
### find the hash of the conversation to this point, excluding
### 5-byte record headers or 1-byte wrapped record trailers
$ fin_hash=$((
    tail -c +6 clienthello;
    tail -c +6 serverhello;
    perl -pe 's/.$// if eof' serverextensions;
    perl -pe 's/.$// if eof' servercert;
    perl -pe 's/.$// if eof' servercertverify) | openssl sha384)
$ sht_secret=23323da031634b241dd37d61032b62a4f450584d1f7f47983ba2f7cc0cdcc39a68f481f2b019f9403a3051908a5d1622
$ fin_key=$(./hkdf-384 expandlabel $sht_secret "finished" "" 48)
$ echo $fin_hash | xxd -r -p \
    | openssl dgst -sha384 -mac HMAC -macopt hexkey:$fin_key

7e30eeccb6b23be6c6ca363992e842da877ee64715ae7fc0cf87f9e5032182b5bb48d1e33f9979055a160c8dbbb1569c
Расчет ключей приложения сервера
Теперь у сервера есть информация для расчета ключей, используемых для шифрования трафика приложений. Он использует следующие информацию в этом расчете:
  • Секрет рукопожатия (из "Расчет ключей рукопожатия сервера")
  • Хэш SHA384 каждого сообщения рукопожатия от Client Hello до Server Handshake Finished
Мы вычисляем хэш SHA384 всех сообщений рукопожатия к этому моменту (Client Hello, Server Hello, [распакованные] Encrypted Extensions, [распакованные] Server Certificate, [распакованные] Server Certificate Verify, [распакованные] Server Finished). Входные данные хэша не включают 5-байтовые заголовки "record" ClientHello и ServerHello. Он также не включает в себя завершающий 1-байтовый "тип записи" распакованных записей. Этот "handshake_hash" - fa6800169a6baac19159524fa7b9721b41be3c9db6f3f93fa5ff7e3db3ece204d2b456c51046e40ec5312c55a86126f5:
# strip first 5 bytes of hello records, and trailing byte of unwrapped records
$ (tail -c +6 clienthello; tail -c +6 serverhello; \
   perl -pe 's/.$// if eof' serverextensions; \
   perl -pe 's/.$// if eof' servercert; \
   perl -pe 's/.$// if eof' servercertverify; \
   perl -pe 's/.$// if eof' serverfinished) | openssl sha384

fa6800169a6baac19159524fa7b9721b41be3c9db6f3f93fa5ff7e3db3ece204d2b456c51046e40ec5312c55a86126f5
    
Затем мы передаем хэш и секрет рукопожатия в набор операций получения ключа, предназначенных для обеспечения целостности процесса рукопожатия и защиты от известных и возможных атак:
empty_hash = SHA384("")
derived_secret = HKDF-Expand-Label(key: handshake_secret, label: "derived", ctx: empty_hash, len: 48)
master_secret = HKDF-Extract(salt: derived_secret, key: 00...)
client_secret = HKDF-Expand-Label(key: master_secret, label: "c ap traffic", ctx: handshake_hash, len: 48)
server_secret = HKDF-Expand-Label(key: master_secret, label: "s ap traffic", ctx: handshake_hash, len: 48)
client_application_key = HKDF-Expand-Label(key: client_secret, label: "key", ctx: "", len: 32)
server_application_key = HKDF-Expand-Label(key: server_secret, label: "key", ctx: "", len: 32)
client_application_iv = HKDF-Expand-Label(key: client_secret, label: "iv", ctx: "", len: 12)
server_application_iv = HKDF-Expand-Label(key: server_secret, label: "iv", ctx: "", len: 12)
Я создал инструмент HKDF для выполнения этих операций в командной строке.
$ handshake_hash=fa6800169a6baac19159524fa7b9721b41be3c9db6f3f93fa5ff7e3db3ece204d2b456c51046e40ec5312c55a86126f5
$ handshake_secret=bdbbe8757494bef20de932598294ea65b5e6bf6dc5c02a960a2de2eaa9b07c929078d2caa0936231c38d1725f179d299
$ zero_key=000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
$ empty_hash=$(openssl sha384 < /dev/null | sed -e 's/.* //')
$ derived_secret=$(./hkdf-384 expandlabel $handshake_secret "derived" $empty_hash 48)
$ master_secret=$(./hkdf-384 extract $derived_secret $zero_key)
$ csecret=$(./hkdf-384 expandlabel $master_secret "c ap traffic" $handshake_hash 48)
$ ssecret=$(./hkdf-384 expandlabel $master_secret "s ap traffic" $handshake_hash 48)
$ client_application_key=$(./hkdf-384 expandlabel $csecret "key" "" 32)
$ server_application_key=$(./hkdf-384 expandlabel $ssecret "key" "" 32)
$ client_application_iv=$(./hkdf-384 expandlabel $csecret "iv" "" 12)
$ server_application_iv=$(./hkdf-384 expandlabel $ssecret "iv" "" 12)
$ echo skey: $server_application_key
$ echo siv: $server_application_iv
$ echo ckey: $client_application_key
$ echo civ: $client_application_iv

skey: 01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
siv: 196a750b0c5049c0cc51a541
ckey: de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc
civ: bb007956f474b25de902432f
Отсюда мы получаем следующие данные ключа:
  • ключ приложения сервера: 01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
  • вектор инициализации приложения сервера: 196a750b0c5049c0cc51a541
  • ключ приложения клиента: de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc
  • вектор инициализации приложения клиента: bb007956f474b25de902432f
Расчет ключей приложения клиента
Теперь у клиента есть информация для расчета ключей, используемых для шифрования трафика приложений. Он выполняет тот же расчет, что показан в "Расчет ключей приложения сервера", и находит те же значения:
  • ключ приложения сервера: 01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
  • вектор инициализации приложения сервера: 196a750b0c5049c0cc51a541
  • ключ приложения клиента: de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc
  • вектор инициализации приложения клиента: bb007956f474b25de902432f
Client Change Cipher Spec
Эта запись служила цели в более ранних версиях TLS, но больше не нужна. В "режиме совместимости с промежуточными устройствами" эта запись отправляется, чтобы помочь замаскировать сеанс под сеанс TLS 1.2.
Record Header 14 03 03 00 01 01
Сеансы TLS разбиты на отправку и получение "записей", которые представляют собой блоки данных с типом, версией протокола, и длиной.
  • 14 - тип 0x14 (запись ChangeCipherSpec)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 01 - длина полезной нагрузки записи составляет 1 байт
  • 01 - полезная нагрузка этого сообщения определяется как байт 0x01
Wrapped Record
Чтобы уменьшить количество проблем с промежуточными устройствами, которые блокируют нераспознанные протоколы TLS, записи TLS 1.3 маскируются под TLS 1.2 записи данных приложения.

Обернутая запись обсуждается в отдельном разделе ниже.
Record Header 17 03 03 00 45
Запись TLS 1.3 зашифрована в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 45 - 0x45 (69) байтов обернутых данных следует далее
Encrypted Data 9f f9 b0 63 17 51 77 32 2a 46 dd 98 96 f3 c3 bb 82 0a b5 17 43 eb c2 5f da dd 53 45 4b 73 de b5 4c c7 24 8d 41 1a 18 bc cf 65 7a 96 08 24 e9 a1 93 64 83 7c 35
Эти данные зашифрованы с помощью ключа рукопожатия клиента.
Auth Tag 0a 69 a8 8d 4b f6 35 c8 5e b8 74 ae bc 9d fd e8
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа рукопожатия клиента и вектора инициализации рукопожатия клиента, которые были сгенерированы на шаге "Расчет ключей рукопожатия клиента". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 0. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Client Handshake Keys Calc" step
$ key=1135b4826a9a70257e5a391ad93093dfd7c4214812f493b3e3daae1eb2b1ac69
$ iv=4256d2e0e88babdd05eb2f27
### from this record
$ recdata=1703030045
$ authtag=0a69a88d4bf635c85eb874aebc9dfde8
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "9f f9 b0 63 17 51 77 32 2a 46 dd 98 96 f3 c3 bb 82 0a b5
  17 43 eb c2 5f da dd 53 45 4b 73 de b5 4c c7 24 8d 41 1a 18 bc
  cf 65 7a 96 08 24 e9 a1 93 64 83 7c 35" | xxd -r -p > /tmp/msg2
$ cat /tmp/msg2 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  14 00 00 30 bf f5 6a 67  1b 6c 65 9d 0a 7c 5d d1  |...0..jg.le..|].|
00000010  84 28 f5 8b dd 38 b1 84  a3 ce 34 2d 9f de 95 cb  |.(...8....4-....|
00000020  d5 05 6f 7d a7 91 8e e3  20 ea b7 a9 3a bd 8f 1c  |..o}.... ...:...|
00000030  02 45 4d 27 16                                    |.EM'.|
Client Handshake Finished 14 00 00 30 bf f5 6a 67 1b 6c 65 9d 0a 7c 5d d1 84 28 f5 8b dd 38 b1 84 a3 ce 34 2d 9f de 95 cb d5 05 6f 7d a7 91 8e e3 20 ea b7 a9 3a bd 8f 1c 02 45 4d 27
Это сообщение рукопожатия представлено в отдельном разделе ниже.
Record Type 16
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний ненулевой байт который указывает ее фактический тип записи.
  • 16 - тип 0x16 (запись рукопожатия)
Client Handshake Finished
Чтобы убедиться, что рукопожатие прошло успешно и не было изменено, клиент вычисляет данные проверки, с которыми сервер согласится, и шифрует их с помощью ключа рукопожатия клиента. Данные проверки строятся из хэша всех сообщений рукопожатия.
Handshake Header 14 00 00 30
Каждое сообщение рукопожатия начинается с типа и длины.
  • 14 - тип сообщения рукопожатия 0x14 (finished)
  • 00 00 30 - 0x30 (48) байтов данных handshake finished следует далее
Verify Data bf f5 6a 67 1b 6c 65 9d 0a 7c 5d d1 84 28 f5 8b dd 38 b1 84 a3 ce 34 2d 9f de 95 cb d5 05 6f 7d a7 91 8e e3 20 ea b7 a9 3a bd 8f 1c 02 45 4d 27
Данные verify_data строятся с использованием client_secret из шага "Расчет ключей рукопожатия сервера" и хэша SHA384 каждой записи рукопожатия до этого момента (от Client Hello до Server Finished).
finished_key = HKDF-Expand-Label(key: client_secret, label: "finished", ctx: "", len: 48)
finished_hash = SHA384(Client Hello ... Server Finished)
verify_data = HMAC-SHA384(key: finished_key, msg: finished_hash)
Мы можем использовать инструмент HKDF для воспроизведения этого в командной строке.
### find the hash of the conversation to this point, excluding
### 5-byte record headers or 1-byte wrapped record trailers
$ fin_hash=$((
    tail -c +6 clienthello;
    tail -c +6 serverhello;
    perl -pe 's/.$// if eof' serverextensions;
    perl -pe 's/.$// if eof' servercert;
    perl -pe 's/.$// if eof' servercertverify;
    perl -pe 's/.$// if eof' serverfinished) | openssl sha384)
$ cht_secret=db89d2d6df0e84fed74a2288f8fd4d0959f790ff23946cdf4c26d85e51bebd42ae184501972f8d30c4a3e4a3693d0ef0
$ fin_key=$(./hkdf-384 expandlabel $cht_secret "finished" "" 48)
$ echo $fin_hash | xxd -r -p \
    | openssl dgst -sha384 -mac HMAC -macopt hexkey:$fin_key

bff56a671b6c659d0a7c5dd18428f58bdd38b184a3ce342d9fde95cbd5056f7da7918ee320eab7a93abd8f1c02454d27
Wrapped Record
Чтобы уменьшить количество проблем с промежуточными устройствами, которые блокируют нераспознанные протоколы TLS, записи TLS 1.3 маскируются под TLS 1.2 записи данных приложения.

Обернутая запись обсуждается в отдельном разделе ниже.
Record Header 17 03 03 00 15
Запись TLS 1.3 зашифрована в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 15 - длина полезной нагрузки записи составляет 0x15 (21) байт
Все данные, следующие за этим заголовком, являются зашифрованной формой фактической записи.
Encrypted Data 82 81 39 cb 7b
Эти данные зашифрованы с помощью ключа приложения клиента.

Расшифрованные данные см. ниже.
Auth Tag 73 aa ab f5 b8 2f bf 9a 29 61 bc de 10 03 8a 32
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа приложения клиента и вектора инициализации приложения клиента, которые были сгенерированы на шаге "Расчет ключей приложения клиента". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 0. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Client Application Keys Calc" step
$ key=de2f4c7672723a692319873e5c227606691a32d1c59d8b9f51dbb9352e9ca9cc
$ iv=bb007956f474b25de902432f
### from this record
$ recdata=1703030015
$ authtag=73aaabf5b82fbf9a2961bcde10038a32
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "82 81 39 cb 7b" | xxd -r -p > /tmp/msg3
$ cat /tmp/msg3 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  70 69 6e 67 17                                    |ping.|
Client Application Data 70 69 6e 67
Эти данные приложения представлены в отдельном разделе ниже.
Record Type 17
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 17 - тип 0x17 (данные приложения)
Client Application Data
Клиент отправляет данные "ping".
Application Data 70 69 6e 67
Байты "ping".
Wrapped Record
Чтобы уменьшить количество проблем с промежуточными устройствами, которые блокируют нераспознанные протоколы TLS, записи TLS 1.3 маскируются под TLS 1.2 записи данных приложения.

Обернутые записи обсуждаются в отдельных разделах ниже.
Record Header 17 03 03 00 ea
Запись TLS 1.3 зашифрована в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 ea - длина полезной нагрузки записи составляет 0xEA (234) байт
Все данные, следующие за этим заголовком, являются зашифрованной формой фактической записи.
Encrypted Data 38 2d 8c 19 a4 7f 4e 8d 9b 0c 51 0b c3 48 db 2c c9 9b 24 1c d0 d1 8b 31 d0 ca 1a c1 2d c1 e3 03 c5 8d 0c 7e 9e 27 29 4c 6b 0e 31 98 f7 d3 19 eb 14 62 2e c4 8b 6a c8 f8 66 d7 49 4f a7 75 c8 80 ff 43 ad 4b 1a f5 3a 03 ca 19 77 95 77 8f ff 2f fe 1d 3b 99 b3 4d e7 82 a7 6a bf a8 40 e6 36 6c d7 34 9d 9b cf f6 41 f5 e0 df f9 5e 40 d7 2e 09 ef fe 18 ee 64 67 2c b9 60 05 40 44 88 ad 18 96 c4 4a 5f d1 74 99 8e 9b 00 94 d8 e6 d8 4d 29 29 b7 88 3d c9 a3 c3 c7 31 3a 87 29 3f 31 b6 1d 24 d9 90 97 c8 85 3b fb eb 95 d1 d0 1f 99 ca 05 b0 50 18 59 cf 63 40 e8 37 70 75 97 01 52 fa 94 f5 f5 be 29 06 e7 2a 15 e4 08 36 a4 1f 4c d3 db e7 d5 13 c1 6e 88 61 1d 3e ae 93
Эти данные зашифрованы с помощью ключа приложения сервера.

Расшифрованные данные см. ниже.
Auth Tag 38 d9 db 1f 91 ca 3d 58 42 60 2a 61 0b 43 a4 63
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа приложения сервера и вектора инициализации приложения сервера, которые были сгенерированы на шаге "Расчет ключей приложения сервера". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 0. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Server Application Keys Calc" step
$ key=01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
$ iv=196a750b0c5049c0cc51a541
### from this record
$ recdata=17030300ea
$ authtag=38d9db1f91ca3d5842602a610b43a463
$ recordnum=0
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "38 2d 8c 19 a4 7f 4e 8d 9b 0c 51 0b c3 48 db 2c c9 9b 24
  ... snip ...
  13 c1 6e 88 61 1d 3e ae 93" | xxd -r -p > /tmp/msg5
$ cat /tmp/msg5 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  04 00 00 d5 00 00 1c 20  00 00 00 00 08 00 00 00  |....... ........|
00000010  00 00 00 00 00 00 c0 41  42 43 44 45 46 47 48 49  |.......ABCDEFGHI|
... snip ...
Server New Session Ticket 1 04 00 00 d5 00 00 1c 20 00 00 00 00 08 00 00 00 00 00 00 00 00 00 c0 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41 45 53 cb 11 9d 4d bd 2a 21 ec c2 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5 14 62 5c 0c 21 c5 0f 03 26 1d c4 2c e7 c5 97 0c 4c 01 ea 33 1c ff c8 99 66 ef 54 8b e4 df 9a 8b a4 38 5b eb 86 80 fd 0b 78 df b8 e9 8e fc 8f cc d8 14 fe cd 1d 9b ce 89 ca 05 dc 28 c2 49 e5 bd 61 d0 3a 56 8f 9a 0a 46 fb fd 05 30 2d b6 b2 f7 a3 13 e3 32 67 bf 0b cb dc ec fb 04 a4 d8 2f 5a 69 45 1f 56 7a b5 19 9b b2 6c 5c f2 00 72 f0 45 03 73 02 8f e0 71 d4 f4 1d 8f 61 ae 02 4d 69 bb ae 4c 00 00
Это сообщение рукопожатия представлено в отдельном разделе ниже.
Record Type 16
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 16 - тип 0x16 (данные рукопожатия)
Server New Session Ticket 1
Сервер предоставляет билет сеанса, который клиент может использовать для запуска нового сеанса позже. Успешное возобновление соединения таким образом позволит пропустить большую часть вычислений и сетевую задержку при запуске сеанса.

Поскольку каждый билет сеанса предназначен для однократного использования, и поскольку сервер ожидает, что браузер откроет несколько соединений, он принимает решение о размере и скорости, чтобы предоставить клиенту два билета сеанса для каждого согласованного сеанса. Это первый билет.
Handshake Header 04 00 00 d5
Каждое сообщение рукопожатия начинается с типа и длины.
  • 04 - тип сообщения рукопожатия 0x04 (new session ticket)
  • 00 00 d5 - 0xD5 (213) байтов данных билета сеанса следует далее
Ticket Lifetime 00 00 1c 20
Время жизни билета 0x1C20 (7200) секунд или 2 часа.
Ticket Age Add 00 00 00 00
При отправке этого билета обратно на сервер, он должен добавить это количество миллисекунд к отметке времени, указывающей, когда билет был сгенерирован. Это мешает злоумышленникам сопоставить возобновленный сеанс с сеансом, который сгенерировал этот билет.
Ticket Nonce 08 00 00 00 00 00 00 00 00
Значение для каждого билета, уникальное для каждого билета, сгенерированного во время этого сеанса.
  • 08 - 8 байтов данных nonce следует далее
  • 00 00 00 00 00 00 00 00 - значение nonce
Session Ticket 00 c0 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41 45 53 cb 11 9d 4d bd 2a 21 ec c2 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5 14 62 5c 0c 21 c5 0f 03 26 1d c4 2c e7 c5 97 0c 4c 01 ea 33 1c ff c8 99 66 ef 54 8b e4 df 9a 8b a4 38 5b eb 86 80 fd 0b 78 df b8 e9 8e fc 8f cc d8 14 fe cd 1d 9b ce 89 ca 05 dc 28 c2 49 e5 bd 61 d0 3a 56 8f 9a 0a 46 fb fd 05 30 2d b6 b2 f7 a3 13 e3 32 67 bf 0b cb dc ec fb 04 a4 d8 2f 5a 69 45 1f 56 7a b5 19 9b b2 6c 5c f2 00 72 f0 45 03 73 02 8f e0 71 d4 f4 1d 8f 61 ae 02 4d 69 bb ae 4c
Это билет, который можно отправить на сервер для возобновления сеанса. Данные внутри имеют значение для сервера, и могут содержать достаточно информации для сервера, чтобы безопасно возобновить соединение без сохранения какой-либо информации на сервере (например, в памяти). Эта информация не имеет смысла и не понятна для клиента.
  • 00 c0 - 0xC0 (192) байтов данных билета следует далее
  • 41 42 ... ae 4c - билет сеанса
Ticket Extensions 00 00
Сервер предоставляет расширения для предоставления дополнительной информации о билете или для запроса изменения поведения от клиента.

  • 00 00 - 0 байтов данных расширения "Ticket Extensions" следует далее
Wrapped Record
Чтобы уменьшить количество проблем с промежуточными устройствами, которые блокируют нераспознанные протоколы TLS, записи TLS 1.3 маскируются под TLS 1.2 записи данных приложения.

Обернутые записи обсуждаются в отдельных разделах ниже.
Record Header 17 03 03 00 ea
Запись TLS 1.3 зашифрована в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 ea - длина полезной нагрузки записи составляет 0xEA (234) байт
Все данные, следующие за этим заголовком, являются зашифрованной формой фактической записи.
Encrypted Data 38 ad fb 1d 01 fd 95 a6 03 85 e8 bb f1 fd 8d cb 46 70 98 97 e7 d6 74 c2 f7 37 0e c1 1d 8e 33 eb 4f 4f e7 f5 4b f4 dc 0b 92 fa e7 42 1c 33 c6 45 3c eb c0 73 15 96 10 a0 97 40 ab 2d 05 6f 8d 51 cf a2 62 00 7d 40 12 36 da fc 2f 72 92 ff 0c c8 86 a4 ef 38 9f 2c ed 12 26 c6 b4 dc f6 9d 99 4f f9 14 8e f9 69 bc 77 d9 43 3a b1 d3 a9 32 54 21 82 82 9f 88 9a d9 5f 04 c7 52 f9 4a ce 57 14 6a 5d 84 b0 42 bf b3 48 5a 64 e7 e9 57 b0 89 80 cd 08 ba f9 69 8b 89 29 98 6d 11 74 d4 aa 6d d7 a7 e8 c0 86 05 2c 3c 76 d8 19 34 bd f5 9b 96 6e 39 20 31 f3 47 1a de bd dd db e8 4f cf 1f f4 08 84 6a e9 b2 8c a4 a9 e7 28 84 4a 49 3d 80 45 5d 6e af f2 05 b4 0a 1e f1 85 74 ef
Эти данные зашифрованы с помощью ключа приложения сервера.

Расшифрованные данные см. ниже.
Auth Tag c0 b9 6a d3 83 af bd 8d fc 86 f8 08 7c 1f 7d c8
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа приложения сервера и вектора инициализации приложения сервера, которые были сгенерированы на шаге "Расчет ключей приложения сервера". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 1. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Server Application Keys Calc" step
$ key=01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
$ iv=196a750b0c5049c0cc51a541
### from this record
$ recdata=17030300ea
$ authtag=c0b96ad383afbd8dfc86f8087c1f7dc8
$ recordnum=1
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "38 ad fb 1d 01 fd 95 a6 03 85 e8 bb f1 fd 8d cb 46 70
  ... snip ...
  b4 0a 1e f1 85 74 ef" | xxd -r -p > /tmp/msg5
$ cat /tmp/msg5 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  04 00 00 d5 00 00 1c 20  00 00 00 00 08 00 00 00  |....... ........|
00000010  00 00 00 00 01 00 c0 41  42 43 44 45 46 47 48 49  |.......ABCDEFGHI|
... snip ...
Server New Session Ticket 2 04 00 00 d5 00 00 1c 20 00 00 00 00 08 00 00 00 00 00 00 00 01 00 c0 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41 45 53 cb 11 9d 4d bd 2a 21 ec c2 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5 14 62 5c 0c 21 c5 0f 03 26 1d c4 2c e7 c5 97 0c 4c 01 16 06 fb 99 8a 86 c3 fa 30 e5 5e ea 91 f1 ff f3 18 fc 7b d5 88 31 bf 49 c8 8d 7b 59 05 91 a6 5c 7d e8 cf c6 77 46 8a 54 fd be c0 d8 53 be 20 21 c8 bb fc db e5 1f 5d 9a 0c 70 85 84 1a 01 e4 95 85 f6 8b 4a fe e1 d7 07 e2 cb b1 a0 b4 23 aa 7e 32 d5 60 7b d9 9d d4 db 3c 9a aa ed 43 d3 5d 26 b4 b1 c6 84 71 71 ea a0 7a 9b c8 cb f7 58 49 9a 00 00
Это сообщение рукопожатия представлено в отдельном разделе ниже.
Record Type 16
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 16 - тип 0x16 (данные рукопожатия)
Server New Session Ticket 2
Сервер предоставляет билет сеанса, который клиент может использовать для запуска нового сеанса позже. Успешное возобновление соединения таким образом позволит пропустить большую часть вычислений и сетевую задержку при запуске сеанса.

Поскольку каждый билет сеанса предназначен для однократного использования, и поскольку сервер ожидает, что браузер откроет несколько соединений, он принимает решение о размере и скорости, чтобы предоставить клиенту два билета сеанса для каждого согласованного сеанса. Это второй билет.
Handshake Header 04 00 00 d5
Каждое сообщение рукопожатия начинается с типа и длины.
  • 04 - тип сообщения рукопожатия 0x04 (new session ticket)
  • 00 00 d5 - 0xD5 (213) байтов данных билета сеанса следует далее
Ticket Lifetime 00 00 1c 20
Время жизни билета 0x1C20 (7200) секунд или 2 часа.
Ticket Age Add 00 00 00 00
При отправке этого билета обратно на сервер, он должен добавить это количество миллисекунд к отметке времени, указывающей, когда билет был сгенерирован. Это мешает злоумышленникам сопоставить возобновленный сеанс с сеансом, который сгенерировал этот билет.
Ticket Nonce 08 00 00 00 00 00 00 00 01
Значение для каждого билета, уникальное для каждого билета, сгенерированного во время этого сеанса.
  • 08 - 8 байтов данных nonce следует далее
  • 00 00 00 00 00 00 00 01 - значение nonce
Session Ticket 00 c0 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 00 49 56 44 41 54 41 49 56 44 41 54 41 00 41 45 53 cb 11 9d 4d bd 2a 21 ec c2 26 a6 09 0e e8 ca 58 df 09 03 9b 35 96 f4 de 79 98 0e a3 25 d5 14 62 5c 0c 21 c5 0f 03 26 1d c4 2c e7 c5 97 0c 4c 01 16 06 fb 99 8a 86 c3 fa 30 e5 5e ea 91 f1 ff f3 18 fc 7b d5 88 31 bf 49 c8 8d 7b 59 05 91 a6 5c 7d e8 cf c6 77 46 8a 54 fd be c0 d8 53 be 20 21 c8 bb fc db e5 1f 5d 9a 0c 70 85 84 1a 01 e4 95 85 f6 8b 4a fe e1 d7 07 e2 cb b1 a0 b4 23 aa 7e 32 d5 60 7b d9 9d d4 db 3c 9a aa ed 43 d3 5d 26 b4 b1 c6 84 71 71 ea a0 7a 9b c8 cb f7 58 49 9a
Это билет, который можно отправить на сервер для возобновления сеанса. Данные внутри имеют значение для сервера, и могут содержать достаточно информации для сервера, чтобы безопасно возобновить соединение без сохранения какой-либо информации на сервере (например, в памяти). Эта информация не имеет смысла и не понятна для клиента.
  • 00 c0 - 0xC0 (192) байтов данных билета следует далее
  • 41 42 ... 49 9a - билет сеанса
Ticket Extensions 00 00
Сервер предоставляет расширения для предоставления дополнительной информации о билете или для запроса изменения поведения от клиента.

  • 00 00 - 0 байтов данных расширения "Ticket Extensions" следует далее
Wrapped Record
Чтобы уменьшить количество проблем с промежуточными устройствами, которые блокируют нераспознанные протоколы TLS, записи TLS 1.3 маскируются под TLS 1.2 записи данных приложения.

Обернутая запись обсуждается в отдельном разделе ниже.
Record Header 17 03 03 00 15
Запись TLS 1.3 зашифрована в "обертку" записи TLS 1.2, которая выглядит как данные приложения.
  • 17 - тип 0x17 (данные приложения)
  • 03 03 - устаревшая версия протокола "3,3" (TLS 1.2)
  • 00 15 - длина полезной нагрузки записи составляет 0x15 (21) байт
Все данные, следующие за этим заголовком, являются зашифрованной формой фактической записи.
Encrypted Data 0c da 85 f1 44
Эти данные зашифрованы с помощью ключа приложения сервера.

Расшифрованные данные см. ниже.
Auth Tag 7a e2 3f a6 6d 56 f4 c5 40 84 82 b1 b1 d4 c9 98
Это тег аутентификации AEAD который защищает целостность зашифрованных данных и заголовка записи.
Decryption
Эти данные зашифрованы с использованием ключа приложения сервера и вектора инициализации приложения сервера, которые были сгенерированы на шаге "Расчет ключей приложения сервера". Вектор инициализации будет изменен путем применения к нему операции XOR со счетчиком записей, которые уже были зашифрованы этим ключом, который в данном случае равен 2. Процесс также принимает в качестве входных данных 5-байтовый заголовок записи с которого начинается эта запись, как аутентифицированные данные, которые должны совпадать для успешной расшифровки .

Поскольку инструмент командной строки openssl еще не поддерживает шифры AEAD, Я написал инструменты командной строки для расшифровки и шифрования этих данных.
### from the "Server Application Keys Calc" step
$ key=01f78623f17e3edcc09e944027ba3218d57c8e0db93cd3ac419309274700ac27
$ iv=196a750b0c5049c0cc51a541
### from this record
$ recdata=1703030015
$ authtag=7ae23fa66d56f4c5408482b1b1d4c998
$ recordnum=2
### may need to add -I and -L flags for include and lib dirs
$ cc -o aes_256_gcm_decrypt aes_256_gcm_decrypt.c -lssl -lcrypto
$ echo "0c da 85 f1 44" | xxd -r -p > /tmp/msg4
$ cat /tmp/msg4 \
  | ./aes_256_gcm_decrypt $iv $recordnum $key $recdata $authtag \
  | hexdump -C

00000000  70 6f 6e 67 17                                    |pong.|
Server Application Data 70 6f 6e 67
Эти данные приложения представлены в отдельном разделе ниже.
Record Type 17
Каждая запись TLS 1.3, замаскированная под TLS 1.2 данные приложения, имеет последний байт который указывает ее фактический тип записи.
  • 17 - тип 0x17 (данные приложения)
Server Application Data
Сервер отвечает данными "pong".
Application Data 70 6f 6e 67
Байты "pong".

Код для этого проекта, включая захват пакетов, можно найти на GitHub.

[print]