2015-08-17 17 views
5

Một boost-asio SSL/TLS TCP socket được thực hiện như một ssl::stream hơn một tcp::socket:Cách thích hợp để ngắt kết nối an toàn ổ cắm ASIO SSL là gì?

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

Trong giao thức TLS, ngừng hoạt động mã hóa bảo mật liên quan đến các bên trao đổi close_notify tin nhắn. Chỉ cần đóng lớp thấp nhất có thể làm cho phiên dễ bị tổn thương với một số truncation attack.

Trong boost asio ssl async_shutdown always finishes with an error? @Tanner Sansbury mô tả quá trình shutdown SSL chi tiết với một số kịch bản và đề xuất sử dụng một async_shutdown tiếp theo là một async_write để ngắt kết nối một dòng SSL trước khi đóng socket:

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

Thực hiện một async_shutdown trên số ssl::stream gửi thông báo SSL close_notify và đợi phản hồi từ đầu kia. Mục đích của việc ghi vào luồng sau khi async_shutdown được thông báo khi async_shutdown gửi close_notify để ổ cắm có thể được đóng mà không cần chờ phản hồi. Tuy nhiên, trong hiện tại (1,59) phiên bản của boost cuộc gọi đến async_write thất bại ...

Trong How to gracefully shutdown a boost asio ssl client? @maxschlepzig đề nghị tắt máy thu của socket TCP cơ bản:

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

này tạo ra một lỗi short read, và async_shutdown được gọi khi nó được phát hiện trong xử lý lỗi:

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

Hoặc hủy thao tác đọc/ghi trên ổ cắm và sau đó gọi SSL async tắt máy, tức là .:

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

Tôi hiện đang sử dụng phương pháp cuối cùng này vì nó làm việc với phiên bản hiện tại của boost.

Cách chính xác/tốt nhất để ngắt kết nối an toàn ổ cắm SSL boost-asio là gì?

+1

Điều đó tùy thuộc. Nếu bạn đã nhận được một 'close_notify', bạn không có nghĩa vụ phải gửi một. – EJP

+1

Có, nhưng bạn không phải đợi để nhận được 'close_notify' sau khi bạn đã gửi. – kenba

Trả lời

3

Để ngắt kết nối an toàn, thực hiện thao tác tắt máy và sau đó đóng giao thông cơ bản sau khi tắt máy hoàn tất. Do đó, phương pháp bạn đang sử dụng sẽ thực hiện một ngắt kết nối an toàn:

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

Hãy nhận biết rằng async_shutdown hoạt động hiện tại sẽ được coi là hoàn thành khi một trong hai:

  • Một close_notify đã được nhận bởi các đồng đẳng từ xa .
  • Đồng đẳng từ xa đóng chốt.
  • Thao tác đã bị hủy.

Do đó, nếu tài nguyên bị ràng buộc vào tuổi thọ của ổ cắm hoặc kết nối, thì các tài nguyên này sẽ vẫn hoạt động để chờ cho đồng nghiệp từ xa thực hiện hành động hoặc cho đến khi thao tác bị hủy cục bộ. Tuy nhiên, không cần phải chờ phản hồi close_notify để tắt an toàn.Nếu nguồn tài nguyên đang bị ràng buộc để kết nối, và địa phương kết nối được coi là đã chết khi gửi một shutdown, sau đó nó có thể là đáng giá để không chờ đợi cho các peer từ xa để có hành động:

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

Khi một khách hàng gửi một thông điệp close_notify , khách hàng đảm bảo rằng khách hàng sẽ không gửi thêm dữ liệu qua kết nối an toàn. Về bản chất, async_write() đang được sử dụng để phát hiện khi khách hàng đã gửi close_notify và trong trình xử lý hoàn tất, sẽ đóng phương tiện cơ bản, gây ra async_shutdown() để hoàn tất với boost::asio::error::operation_aborted. Như đã nêu trong số linked answer, hoạt động async_write() được dự kiến ​​sẽ không thành công.

... như ghi bên dòng SSL PartyA 's đã đóng cửa, hoạt động async_write() sẽ thất bại với một lỗi SSL chỉ ra giao thức đã được tắt máy.

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

Các thất bại async_write() hoạt động sau đó sẽ đóng cửa một cách rõ ràng vận tải cơ bản, làm cho hoạt động async_shutdown() rằng đang chờ PartyB 's close_notify được hủy bỏ.

+1

Cảm ơn bạn @Tanner, tôi hoàn toàn đồng ý rằng một khi khách hàng đã gửi một thông báo 'close', nó không cần phải chờ phản hồi và tôi * đã sử dụng' async_shutdown' theo sau là một 'async_write' như bạn đã được mô tả ở đây và trong (câu trả lời được liên kết) tuyệt vời của bạn (http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error/25703699#25703699) Thật không may, bằng cách sử dụng tăng 1.59, cuộc gọi đến 'async_write' hiện không thành công bằng cách đâm vào 'engine.ipp' thay vì gọi lại cuộc gọi lại bằng' SSL_R_PROTOCOL_IS_SHUTDOWN'! Vậy cách tốt nhất ngắt kết nối ổ cắm SSL và không bị hỏng? – kenba

+1

@kenba Tôi sẽ cố gắng tìm thời gian để điều tra. Ứng dụng có đảm bảo rằng tất cả các hoạt động không đồng bộ đang được thực hiện trong cùng một chuỗi ngầm hoặc rõ ràng không? Thông thường, sự cố với Boost.Asio SSL là kết quả của việc vi phạm yêu cầu đồng thời. –

+0

Cảm ơn bạn @Thành công nó sẽ là tuyệt vời nếu bạn có thể tìm thấy nguyên nhân. Các ứng dụng trong câu hỏi là đơn luồng nên không có vấn đề đồng thời. – kenba

Các vấn đề liên quan