"дешифровать ошибку" TLS 1.2 change-cipher-spec, но верно считывает MAC

Я пытаюсь довести старую версию TLS 1.0 (я не писал), чтобы говорить о TLS 1.2.

В качестве первого шага я включил изменение TLS 1.1, введя вектор инициализации открытого текста в запись. Это не проблема. Он, казалось, работал достаточно хорошо, чтобы я мог читать https://example.com в TLS 1.1, а также SSL Labs viewMyClient.html.

Затем я адаптировался к изменению псевдослучайной функции TLS 1.2 (для большинства практических целей) P_SHA256 вместо (более сложной и причудливой) половины и половины MD5/SHA1 rigamarole. Я сделал это неправильно в первый раз и получил недопустимую ошибку MAC, но это была более или менее опечатка с моей стороны, и я ее исправил. Затем ошибка MAC недействительна.

Но, несмотря на это, после отправки сообщений ClientKeyExchange-> ChangeCipherSpec, я получаю сообщение "Decrypt Error" с сервера (ов) (то же Alert независимо, https://google.com или что-нибудь, что я пытаюсь). Я понимаю, что сообщение ChangeCipherSpec шифрует только один байт, помещая его в сообщение с заполнением и MAC и т.д.

Если я настраиваю MAC случайно на один байт, он возвращается к жалобе на недействительный MAC. Меня смущает то, что сам MAC зашифрован как часть GenericBlockCipher:

struct {
    opaque IV[SecurityParameters.record_iv_length];
    block-ciphered struct {
        opaque content[TLSCompressed.length];
        opaque MAC[SecurityParameters.mac_length]; // <-- server reads this fine!
        uint8 padding[GenericBlockCipher.padding_length];
        uint8 padding_length;
    };
} GenericBlockCipher;

UPDATE: FWIW, я добавил журнал Wireshark об ошибке 1.2, прочитанный https://example.com, а также журнал функционирующего сеанса 1.1, который работает с тем же кодом, не считая обновления MAC P_SHA256:

http://hostilefork.com/media/shared/stackoverflow/example-com-tls-1.2.pcapng (не удается) http://hostilefork.com/media/shared/stackoverflow/example-com-tls-1.1.pcapng ( успешно)

Итак, что именно это имеет проблемы с расшифровкой? Заполнение кажется правильным, как если бы добавить или вычесть 1 в байт, я получаю недопустимую ошибку MAC. (Спектр говорит: "Приемник ДОЛЖЕН проверять это дополнение и ДОЛЖЕН использовать предупреждение bad_record_mac для указания ошибок заполнения". Это можно ожидать.) Если я испортил клиент-iv в сообщении из того, что я использовал для шифрования (просто поместите плохой байт в переданную версию), делая это также дает мне Bad Record MAC. Я бы ожидал, что и разрушить расшифровку.

Поэтому я озадачен тем, что может быть проблемой:

  • Сервер демонстрирует распознавание действительного MAC-адреса вместо него, поэтому он должен быть расшифрован. Как он получает правильный MAC-адрес и имеет дешифрованную ошибку?
  • Шифрованный набор является старым (TLS_RSA_WITH_AES_256_CBC_SHA), но я просто решаю одну проблему за раз... и если я не ошибаюсь, это не имеет значения.

Кто-нибудь с соответствующим опытом имеет теорию о том, как TLS 1.2 может выбросить ключ в код, который в противном случае работает в TLS 1.1? (Возможно, кто-то, кто сделал подобное обновление для кодовой базы, и должен был изменить больше, чем две вещи, которые я изменил, чтобы заставить ее работать?) Я пропустил еще одно важное техническое изменение? Каким образом я должен узнать, что делает сервер недовольным?

Ответы

Ответ 1

В сообщении ChangeCipherSpec нет ничего плохого. Это действительно сообщение Finished, у которого есть проблема. Он жалуется на дешифрованные verify_data внутри этого сообщения, которые не соответствуют ожидаемому хэшу (несмотря на то, что само шифрование/дешифрование является правильным).

Но что заблуждение в журнале Wireshark заключается в том, что сообщение Finished появляется в одной строке журнала, но под названием " EncryptedHandshakeMessage ". Это делает его похожим на тег или ярлык, описывающий ChangeCipherSpec, но это не так. Это сообщение фактически не зашифровано вообще.

Из второй ссылки:

На практике вы увидите незашифрованные клиентские запросы Hello, Server Hello, Certificate, Server Key Exchange, Certificate Request, Certificate Verify и Client Key Exchange. Сообщение завершенного рукопожатия зашифровывается, поскольку оно возникает после сообщения Spec Change Cipher Spec.


"Надеясь, что у кого-то есть опыт обновления TLS 1.0 или от 1.1 до 1.2, и, возможно, он видел подобную проблему из-за того, что не изменился больше, чем MAC P_SHA256 и натолкнул номер версии"

Они упоминают только два из трех мест, которые вам нужно обновить в комбинации с MD5/SHA1 в разделе "изменения из TLS 1.1" RFC 5246:

  • Комбинация MD5/SHA-1 в псевдослучайной функции (PRF) была заменена спецификациями PRF с набором шифров. В всех наборах шифров в этом документе используется P_SHA256.

  • Комбинация MD5/SHA-1 в элементе с цифровой подписью была заменена одним хэшем. Подписанные элементы теперь включают поле, в котором явно указывается используемый хэш-алгоритм.

(Примечание: второе относится к сертификатам, и если вы еще не получили проверку сертификата, вы еще не были бы на этом этапе.)

То, что они не упоминают в этом разделе, - это третье место изменений комбинации MD5/SHA-1, которое является хешем, используемым в семени для verify_data сообщения Finished. Однако этот момент также является изменением от TLS 1.1, описанным намного дальше по документу в разделе 7.4.9:

"Хэш обозначает хеш сообщений рукопожатия. Для PRF, определенного в разделе 5, Hash ДОЛЖЕН быть хешем, используемым в качестве основы для PRF. Любой набор шифров, который определяет другой PRF, должен также определить хеш для использования в завершенном вычисление ".

Для формальной спецификации они немного расплывчаты в отношении "хеша, используемого в качестве основы для PRF" (это HMAC или просто простой хеш?) Но это простой хеш. Итак, SHA256, если спецификация шифра не говорит иначе.

(Обратите внимание, что шифровой набор может определять длину файла verify_data как более 12 байтов, хотя ни один из упомянутых в спецификации не делает этого.)


"Каким образом я должен узнать, что делает сервер недовольным?"

YMMV. Но я только что создал OpenSSL как статическую библиотеку отладки и связал ее с простым сервером. Затем я добавил точки останова и контрольно-измерительные приборы, чтобы понять, о чем это было расстроено. (По какой-то причине GDB не позволял мне войти в общую библиотеку).

Около 30 сентября 2018 года на простой Linux-машине:

  • git://git.openssl.org/openssl.git
  • ./config no-shared no-asm -g3 -o0 -fno-omit-frame-pointer -fno-inline-functions no-ssl2 no-ssl3
  • make

Простой сервер, который я использовал, приходил с Simple TLS Server. Скомпилируйте статическую библиотеку с помощью:

  • gcc -g -o0 simple.c -o simple -lssl -lcrypto -ldl -lpthread

Я выполнил инструкции для создания сертификатов здесь, но изменил AA на localhost

openSSL подписывает сертификат https_client с CA

Затем я изменил cert.pem => rootCA.pem и key.pem => rootCA.key в простом коде сервера. Я смог:

wget https://localhost:4433 --no-check-certificate

И успешно верните test в ответ. Итак, это было просто вопрос, где мой клиент вызвал сбой.

Ответ 2

Я могу думать о двух разных ситуациях, которые создают эту проблему:

  1. Отправка неправильного IV. IV влияет только на 1-й блок в дешифровке режима CBC, поэтому, если ваше содержимое превышает 16 байт (размер блока AES), MAC часть ваших данных будет дешифрована правильно.
  2. Если вы используете неправильную структуру отступов, вы можете получить ошибку при расшифровке (потому что проверка заполнения не выполняется), но контент будет дешифрован правильно.