2015-08-17 16 views
5

A/TLS gniazdo TCP boost-asio SSL jest realizowany jako ssl::stream ponad tcp::socket:Jaki jest właściwy sposób bezpiecznego odłączenia gniazda asio SSL?

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

W protokole TLS, zaszyfrowanych zamknięcie wiąże stronom wymianę close_notify wiadomości. Po prostu zamknięcie najniższej warstwy może spowodować, że sesja będzie narażona na ataki na truncation attack.

W boost asio ssl async_shutdown always finishes with an error? @Tanner Sansbury opisuje proces zamykania SSL szczegółowo w wielu sytuacjach i proponuje stosując async_shutdown następnie przez async_write odłączyć strumienia SSL przed zamknięciem gniazdo:

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

Performing an async_shutdown na ssl::stream wysyła komunikat SSL close_notify i czeka na odpowiedź z drugiego końca. Zapisanie do strumienia po async_shutdown należy zgłosić, gdy async_shutdown wysłał close_notify, aby gniazdo mogło zostać zamknięte bez oczekiwania na odpowiedź. Jednak w obecnej (1,59) wersji boost wywołanie async_write zawodzi ...

W How to gracefully shutdown a boost asio ssl client? @maxschlepzig proponuje wyłączania odbiornika bazowego gniazda TCP:

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

To daje błąd short read, i async_shutdown nazywa, kiedy to wykryto u obsługi błędu:

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

lub anulowanie operacji odczytu/zapisu na gnieździe, a następnie wywołanie asynchronicznie SSL shutdown, tj .:

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

obecnie używam tej ostatniej metody, ponieważ pracuje z aktualną wersją boost.

Jaki jest najlepszy/najlepszy sposób bezpiecznego odłączenia gniazda SSL boost-asio?

+1

To zależy. Jeśli otrzymałeś "close_notify", nie musisz go wysyłać. – EJP

+1

Tak, ale nie musisz czekać na otrzymanie "close_notify" po wysłaniu. – kenba

Odpowiedz

3

Aby bezpiecznie odłączyć, wykonaj operację zamknięcia, a następnie zamknij podstawowy transport po zakończeniu procesu zamykania. Stąd metoda używasz wykona bezpieczne odłączyć:

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

mieć świadomość, że obecny async_shutdown operacja zostanie uznana za kompletną, gdy:

  • close_notify został odebrany przez zdalny równorzędnego .
  • Remote peer zamyka gniazdo.
  • Operacja została anulowana.

W związku z tym, jeśli zasoby są powiązane z czasem życia gniazda lub połączenia, zasoby te pozostaną przy życiu, czekając na działanie zdalnego partnera lub do momentu, gdy operacja zostanie anulowana lokalnie. Jednak oczekiwanie na odpowiedź close_notify nie jest wymagane do bezpiecznego wyłączenia.Jeśli zasoby są związane z połączeniem, a lokalnie połączenie jest uważane za martwe na wysłanie zamknięcie, to może warto byłoby, aby nie czekać na zdalne peer to podjęcia działań:

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

Gdy klient wysyła wiadomość close_notify , klient gwarantuje, że klient nie będzie wysyłać dodatkowych danych przez bezpieczne połączenie. Zasadniczo narzędzie async_write() służy do wykrywania, kiedy klient wysłał numer close_notify, a w ramach procedury obsługi zakończenia zamknie podstawowy transport, powodując zakończenie async_shutdown() z boost::asio::error::operation_aborted. Jak zauważono w linked answer, operacja async_write() powinna zakończyć się niepowodzeniem.

... jako strona zapisu PartyA „s strumieniu SSL został zamknięty, operacja async_write() zakończy się niepowodzeniem z błędem wskazującym SSL protokół został wyłączony.

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

Nieudany async_write() operacja następnie jawnie zamknąć transportu bazowych, powodując operację, która czeka na PartyB „s close_notify zostać anulowane async_shutdown().

+1

Dziękuję @Tanner, całkowicie zgadzam się, że gdy klient wysłał 'close notify' nie powinien czekać na odpowiedź, a ja * użyłem' async_shutdown', a po nim 'async_write' opisane tutaj i w twojej (doskonałej) [połączonej odpowiedzi] (http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error/25703699#25703699) Niestety, używając boostu 1.59, wywołanie 'async_write' teraz kończy się niepowodzeniem przez awarię w' engine.ipp' zamiast wywoływać wywołanie zwrotne z 'SSL_R_PROTOCOL_IS_SHUTDOWN'! Jak najlepiej odłączyć gniazdo SSL i nie awarię? – kenba

+1

@kenba Postaram się znaleźć czas na zbadanie tego. Czy aplikacja gwarantuje, że wszystkie operacje asynchroniczne są wykonywane w tym samym niejawnym lub jawnym łańcuchu? Często zdarza się, że awarie z Boost.Asio SSL są wynikiem naruszenia wymogu współbieżności. –

+0

Dziękuję @Tanner byłoby świetnie, gdybyś mógł znaleźć przyczynę. Ta aplikacja ma jeden wątek, więc nie ma problemów z współbieżnością. – kenba

Powiązane problemy