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 unaclose_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()
fallidaasync_write()
explícitamente el transporte subyacente, causando la operaciónasync_shutdown()
que está esperando que se cancele elclose_notify
declose_notify
.