Клиент tls 1.3 не сообщает о неудачном рукопожатии, когда сервер не проверил сертификат клиента - PullRequest
2 голосов
/ 19 июня 2020

У меня есть клиент C, использующий OpenSSL, который не проходит тест при использовании сертификата, не прошедшего проверку на стороне сервера во время вызова SSL_do_handshake () на сервере. Когда приложение использовало TLS 1.2, об ошибке SSL_do_handshake () на сервере будет сообщено клиенту, когда он вызовет SSL_do_handshake () как возвращаемое значение ошибки.

При обновлении моего приложения до OpenSSL 1.1.1 и TLS 1.3 Я заметил, что хотя ошибка проверки все еще возникает на сервере, она больше не сообщается клиенту.

Я знаю, что протокол рукопожатия был полностью переписан как часть TLS 1.3 однако, похоже, что со всеми доступными обратными вызовами я должен каким-то образом на стороне клиента определить, что аутентификация не удалась, без попытки записи данных на сервер.

Кто-нибудь еще сталкивался с этим и могут ли они порекомендовать путь вперед?

1 Ответ

1 голос
/ 19 июня 2020

Сервер и клиент как в TLSv1.2, так и в TLSv1.3 считают, что рукопожатие завершено, когда они оба написали сообщение «Finished» и получили его от однорангового узла. Вот как выглядит рукопожатие в TLSv1.2 (взято из RFC5246):

      Client                                               Server

      ClientHello                  -------->
                                                      ServerHello
                                                     Certificate*
                                               ServerKeyExchange*
                                              CertificateRequest*
                                   <--------      ServerHelloDone
      Certificate*
      ClientKeyExchange
      CertificateVerify*
      [ChangeCipherSpec]
      Finished                     -------->
                                               [ChangeCipherSpec]
                                   <--------             Finished
      Application Data             <------->     Application Data

Итак, здесь вы можете видеть, что клиент отправляет свои сообщения Certificate и Finished во втором этапе связи с сервером. Затем он ожидает получения сообщений ChangeCipherSpe c и Finished от сервера, прежде чем он сочтет рукопожатие «завершенным» и сможет начать отправку данных приложения.

Это эквивалентный поток для TLSv1.3, взятый из RFC8446:

       Client                                           Server

Key  ^ ClientHello
Exch | + key_share*
     | + signature_algorithms*
     | + psk_key_exchange_modes*
     v + pre_shared_key*       -------->
                                                  ServerHello  ^ Key
                                                 + key_share*  | Exch
                                            + pre_shared_key*  v
                                        {EncryptedExtensions}  ^  Server
                                        {CertificateRequest*}  v  Params
                                               {Certificate*}  ^
                                         {CertificateVerify*}  | Auth
                                                   {Finished}  v
                               <--------  [Application Data*]
     ^ {Certificate*}
Auth | {CertificateVerify*}
     v {Finished}              -------->
       [Application Data]      <------->  [Application Data]

Одно из преимуществ TLSv1.3 состоит в том, что он ускоряет время, необходимое для выполнения рукопожатия. В TLSv1.3 клиент получает сообщение «Finished» от сервера перед тем, как он отправляет обратно свои сообщения Certificate и Finished. К тому времени, когда клиент отправляет сообщение «Готово», он уже получил сообщение «Готово», поэтому рукопожатие завершено, и он может немедленно начать отправку данных приложения.

Это, конечно, означает, что клиент не будет знать, принял ли сервер сертификат или нет, пока он в следующий раз не прочитает данные с сервера. Если он был отклонен, следующее, что прочитает клиент, будет предупреждением об ошибке (в противном случае это будут обычные данные приложения).

Я знаю, что протокол рукопожатия полностью переписан однако, как часть TLS 1.3, похоже, что со всеми доступными обратными вызовами я смогу каким-то образом на стороне клиента определить, что аутентификация не удалась, без попытки записи данных на сервер.

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

...