c++ ssl boost-asio

c++ - ¿Cuál es la forma correcta de desconectar de forma segura un socket SSL de ASIO?



boost-asio (1)

Se implementa un socket TCP SSL / TLS boost-asio como ssl::stream través de un tcp::socket

boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;

En el protocolo TLS , un cierre criptográficamente seguro implica que las partes intercambien mensajes close_notify . Simplemente cerrar la capa más baja puede hacer que la sesión sea vulnerable a un ataque de truncamiento .

En boost asio ssl async_shutdown siempre termina con un error? @Tanner Sansbury describe el proceso de apagado de SSL en detalle con una serie de escenarios y propone usar un async_shutdown seguido de async_write para desconectar un flujo SSL antes de cerrar el socket:

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

Realizar un async_shutdown en un ssl::stream envía un mensaje SSL close_notify y espera una respuesta del otro extremo. El propósito de escribir en la secuencia después de async_shutdown es ser notificado cuando async_shutdown ha enviado close_notify para que el socket pueda cerrarse sin esperar la respuesta. Sin embargo, en la versión actual (1.59) de boost la llamada a async_write falla ...

En ¿Cómo cerrar con gracia un boost asio ssl client? @maxschlepzig propone cerrar el receptor del socket TCP subyacente:

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

Esto produce un error de short read y se llama a async_shutdown cuando se detecta en el controlador de errores:

// 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(); }

O cancelando las operaciones de lectura / escritura en el socket y luego llamando al apagado asíncrono SSL, es decir:

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

Actualmente estoy usando este último método ya que funciona con la versión actual de boost .

¿Cuál es la forma correcta / mejor de desconectar de forma segura un socket SSL boost-asio ?


Para desconectarse de forma segura, realice una operación de apagado y luego cierre el transporte subyacente una vez que se haya completado el apagado. Por lo tanto, el método que está utilizando actualmente realizará una desconexión segura:

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

Tenga en cuenta que la operación async_shutdown actual se considerará completa cuando:

  • El close_notify ha recibido una close_notify .
  • El par remoto cierra el zócalo.
  • La operación ha sido cancelada.

Por lo tanto, si los recursos están vinculados a la vida útil del socket o la conexión, estos recursos permanecerán vivos esperando que el par remoto tome medidas o hasta que la operación se cancele localmente. Sin embargo, no es necesario esperar una respuesta close_notify para un apagado seguro. Si los recursos están vinculados a la conexión, y localmente la conexión se considera muerta al enviar un apagado, entonces puede valer la pena no esperar a que el par remoto tome medidas:

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

Cuando un cliente envía un mensaje close_notify , el cliente garantiza que no enviará datos adicionales a través de la conexión segura. En esencia, async_write() se está utilizando para detectar cuándo el cliente ha enviado un close_notify , y dentro del controlador de finalización, cerrará el transporte subyacente, haciendo que async_shutdown() complete con boost::asio::error::operation_aborted . Como se señaló en la respuesta vinculada , se espera que la operación async_write() falle.

... como el lado de escritura del flujo SSL de PartyA se ha cerrado, la operación async_write() fallará con un error SSL que indica que el protocolo se ha cerrado.

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

La operación async_write() fallida async_write() explícitamente el transporte subyacente, causando la operación async_shutdown() que está esperando que se cancele el close_notify de close_notify .