Каков правильный способ безопасного отключения сокета SSL asio?

Сокет SSL с поддержкой TCP / boost-asio TLS реализован как ssl::stream поверх tcp::socket :

 boost::asio::ssl::stream ssl_socket; 

В протоколе TLS криптографически безопасное завершение включает стороны, обменивающиеся сообщениями close_notify . Простое закрытие самого низкого уровня может сделать сеанс уязвимым для атаки усечения .

В boost asio ssl async_shutdown всегда заканчивается с ошибкой? @Tanner Sansbury подробно описывает процесс выключения SSL с несколькими сценариями и предлагает использовать async_shutdown за которым следует async_write чтобы отключить stream SSL до закрытия сокета:

 ssl_socket.async_shutdown(...); const char buffer[] = ""; async_write(ssl_socket, buffer, [](...) { ssl_socket.close(); }) 

Выполнение async_shutdown в ssl::stream отправляет сообщение SSL close_notify и ожидает ответа с другого конца. Назначение записи в stream после async_shutdown должно быть уведомлено, когда async_shutdown отправил close_notify чтобы сокет можно было закрыть, не дожидаясь ответа. Однако в текущей (1.59) версии boost вызов async_write завершается с ошибкой …

В Как изящно закрыть клиент asio ssl boost? @maxschlepzig предлагает отключить приемник базового сокета TCP:

 ssl_socket.lowest_layer()::shutdown(tcp::socket::shutdown_receive); 

Это приводит к short read ошибке short read , и async_shutdown вызывается, когда он обнаруживается в обработчике ошибок:

 // const boost::system::error_code &ec if (ec.category() == asio::error::get_ssl_category() && ec.value() == ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ)) { // -> not a real error: do_ssl_async_shutdown(); } 

Или отмените операции чтения / записи в сокете, а затем вызовите выключение SSL async, то есть:

 boost::system::error_code ec; ssl_socket.cancel(ec); ssl_socket.async_shutdown([](...) { ssl_socket.close(); }; 

В настоящее время я использую этот последний метод, так как он работает с текущей версией boost .

Каков правильный / лучший способ безопасного отключения SSL-сокета boost-asio ?

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

 boost::system::error_code ec; ssl_socket.cancel(ec); ssl_socket.async_shutdown([](...) { ssl_socket.close(); }; 

Имейте в async_shutdown что текущая операция async_shutdown будет считаться завершенной, если:

  • Точка close_notify была получена удаленным одноранговым close_notify .
  • Удаленный одноранговый узел закрывает гнездо.
  • Операция отменена.

Следовательно, если ресурсы привязаны к времени жизни сокета или соединения, то эти ресурсы будут оставаться в живых, ожидая, когда удаленный одноранговый узел предпримет действие или пока операция не будет отменена локально. Тем не менее, ожидание ответа close_notify не требуется для безопасного отключения. Если ресурсы связаны с соединением, и локально соединение считается мертвым при отправке выключения, тогда может быть полезно не дождаться, когда удаленный одноранговый узел предпримет действие:

 ssl_socket.async_shutdown(...); const char buffer[] = ""; async_write(ssl_socket, boost::asio::buffer(buffer), [](...) { ssl_socket.close(); }) 

Когда клиент отправляет сообщение close_notify , клиент гарантирует, что клиент не будет отправлять дополнительные данные через безопасное соединение. По сути, async_write() используется для обнаружения, когда клиент отправил close_notify и в обработчике завершения, закроет базовый транспорт, в результате чего async_shutdown() завершит boost::asio::error::operation_aborted , Как отмечено в связанном ответе , async_write() операция async_write() завершится с ошибкой.

… по мере того, как сторона записи streamа SSL PartyA закрыта, async_write() завершится с ошибкой SSL, указывающей, что протокол был остановлен.

 if ((error.category() == boost::asio::error::get_ssl_category()) && (SSL_R_PROTOCOL_IS_SHUTDOWN == ERR_GET_REASON(error.value()))) { ssl_stream.lowest_layer().close(); } 

async_write() операция async_write() затем явно закрывает базовый транспорт, вызывая async_shutdown() которая ожидает закрытия close_notify .

  • Проблемы с подключением через HTTPS / SSL через собственный клиент Java
  • Можно ли заменить обычный разъем на SSLSocket?
  • Создание libcurl с поддержкой SSL в Windows
  • Trust Anchor не найден для подключения SSL для Android
  • Как искать не ssl google?
  • C # Игнорировать ошибки сертификата?
  • Предупреждение о подтверждении SSL: ошибка unrecognized_name с момента обновления до версии 1.7.7
  • Использовать самоподписанный сертификат cURL?
  • почему Java не отправляет сертификат клиента во время подтверждения SSL?
  • Что делает Subversion для своего списка CA?
  • Java SSL подключиться, добавить серверный сертификат в хранилище ключей программно
  • Давайте будем гением компьютера.