"расшифровать ошибку" 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 я получаю "расшифровать ошибку" с сервера(ов) (то же предупреждение независимо,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;

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

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 для указания ошибок заполнения.- этого следовало ожидать.) если я повреждаю client-iv в сообщении от того, что я использовал для шифрования (просто поместите плохой байт в переданную версию), это также дает мне плохую запись MAC. Я ожидал, что это также разрушит расшифровку.

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

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

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

2 ответов


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

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

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

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


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

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

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

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

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

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

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

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

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


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

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

около 30-Sep-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

простой сервер я приехал из простой сервер TLS. Сборки статической библиотеки с:

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

я следовал инструкциям по созданию сертификатов здесь, но изменил AAs на 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. если вы используете неправильную структуру заполнения, вы можете получить ошибку в расшифровке (потому что проверка заполнения не выполняется), но содержимое будет расшифровано правильно.