Повышение ASIO: SSL рукопожатие () никогда не заканчивается - PullRequest
13 голосов
/ 04 марта 2012

У меня есть клиентское приложение C ++, которое использует Boost ASIO для установления SSL-соединений с различными серверами.Но для двух конкретных серверов соединение SSL не может быть установлено.Он зависает при вызове boost::asio::ssl::stream::handshake().

. Я использовал Wireshark для наблюдения за разговором между клиентом и сервером.Работающее SSL-соединение, кажется, делает это:

sslsocket.lowest_layer().connect( endpoint, ec );
C ->    SYN    -> S
C <-  SYN ACK  <- S
C ->    ACK    -> S
sslsocket.handshake( SSLSocket::client, ec );
C -> 209 bytes -> S
C <- 690 bytes <- S
C -> 198 bytes -> S
C <- 415 bytes <- S

... и в этот момент возвращается вызов ASIO handshake(), указывающий, что все в порядке, и соединение через сокет SSL работает нормально.

Но на 2 разных серверах [*] рукопожатие выглядит так:

sslsocket.lowest_layer().connect( endpoint, ec );
C ->    SYN    -> S
C <-  SYN ACK  <- S
C ->    ACK    -> S
sslsocket.handshake( SSLSocket::client, ec );
C -> 209 bytes -> S
...2 minute pause...
C <-    RST    <- S

Глядя на файлы журналов на этих серверах, кажется, что после того, как начальные 209 байтов отправлены в рукопожатие, серверсчитается, что SSL-соединение полностью установлено.Но клиент все еще сидит в вызове Boost ASIO handshake () и в конечном итоге возвращает ec = 104 при сбросе соединения.

Так что я думаю, что, возможно, существуют различные типы рукопожатий SSL, и, возможно, есть«проще» я должен использовать?

[*] Я знаю, что кто-то захочет узнать: один из серверов, вызывающих эту проблему с клиентским приложением, - это FileZilla Server for Windows, использующий SSL / TLS.[FTPS], а другой - проприетарная служба, работающая в Linux.)


ОБНОВЛЕНИЕ: Сэм Миллер попросил меня опубликовать мой код, описывающий настройку контекста ssl:

Класс(.hpp файл) содержит это:

typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> SSLSocket;
boost::asio::io_service    ioservice;
boost::asio::ssl::context  sslcontext;
SSLSocket                  sslDataSocket;
boost::system::error_code  ec;

Конструктор имеет следующие инициализаторы:

ioservice      ( 2 ),
sslcontext     ( ioservice, boost::asio::ssl::context::sslv23 ),
sslDataSocket  ( ioservice, sslcontext ),

... и этот код:

sslcontext.set_options( boost::asio::ssl::context::default_workarounds |
                        boost::asio::ssl::context::verify_none         );

И этокод, где установлен сокет SSL и зависает рукопожатие:

std::cout << "connecting SSL socket to endpoint " << buffer << std::endl;
sslDataSocket.lowest_layer().connect( tcpEndpoint, ec );
std::cout << "connect() done, ec=" << ec.value() << std::endl;
if ( ec ) throw "test 1";

std::cout << "starting ssl handshake" << std::endl;
sslDataSocket.handshake( SSLSocket::client, ec );
std::cout << "handshake done, ec=" << ec.value() << std::endl;
if ( ec ) throw "test 2";

1 Ответ

9 голосов
/ 08 марта 2012

Я понял это. Этот учебник SSL (http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04s03.html) содержал ключ, который, наконец, заставил меня работать. Цитата:

Вы можете повторно использовать информацию из уже установленного сеанса SSL создать новое соединение SSL. Потому что новое соединение SSL повторное использование одного и того же главного секрета, можно выполнить рукопожатие SSL быстрее. В результате возобновление сеанса SSL может снизить нагрузку сервера, который принимает много соединений SSL.

Итак, вот как у меня получилось работать с Boost ASIO:

  • установить обычный сокет управления SSL (множество примеров, включая этот вопрос)
  • когда вам нужно настроить второй сокет данных SSL, сделайте следующее:

    sslSocket2.lowest_layer().connect( tcpEndpoint, ec );
    SSLSocket::impl_type impl1 = sslSocket1.impl();
    SSLSocket::impl_type impl2 = sslSocket2.impl();
    SSL_SESSION *savedSession = SSL_get1_session( impl1->ssl );
    SSL_set_session( impl2->ssl, savedSession );
    SSL_connect( impl2->ssl );

Вот и все. На этом этапе нет необходимости вызывать sslSocket2.handshake (). Просто прочитайте и напишите в сокет, зная, что соединение установлено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...