Как обращаться с OpenSSL SSL_ERROR_WANT_READ / WANT_WRITE на неблокирующих сокетах - PullRequest
33 голосов
/ 17 октября 2010

Библиотека OpenSSL позволяет читать из нижележащего сокета с SSL_read и записывать в него с SSL_write. Эти функции могут возвращаться с SSL_ERROR_WANT_READ или SSL_ERROR_WANT_WRITE в зависимости от потребностей их протокола ssl (например, при повторном согласовании соединения).

Я не совсем понимаю, что API хочет, чтобы я делал с этими результатами.

Создание образа серверного приложения, которое принимает клиентские подключения, устанавливает новый сеанс ssl, делает неблокируемый основной сокет, а затем добавляет дескриптор файла в цикл select / poll / epoll.

Если клиент отправляет данные, основной цикл отправляет их в ssl_read. Что нужно сделать здесь, если возвращается SSL_ERROR_WANT_READ или SSL_ERROR_WANT_WRITE? WANT_READ может быть простым, потому что следующая итерация основного цикла может просто привести к другому ssl_read. Но если ssl_read возвращает WANT_WRITE, с какими параметрами он должен вызываться? И почему библиотека не выдает сам вызов?

Если сервер хочет отправить клиенту некоторые данные, он будет использовать ssl_write. Опять же, что делать, если возвращены WANT_READ или WANT_WRITE? Можно ли ответить на WANT_WRITE, повторив тот же самый вызов, который только что был вызван? И если WANT_READ возвращается, следует ли вернуться в основной цикл и позволить select / poll / epoll позаботиться об этом? Но как насчет сообщения, которое должно быть написано в первую очередь?

Или чтение должно быть сделано сразу после неудачной записи? Тогда, что защищает от чтения байтов из протокола приложения и необходимости иметь дело с ним где-то на окраине приложения, когда настоящий парсер сидит в основной лупе?

Ответы [ 3 ]

50 голосов
/ 08 ноября 2010

С неблокирующими сокетами SSL_WANT_READ означает "дождитесь, пока сокет не станет читаемым, затем снова вызовите эту функцию." ;и наоборот, SSL_WANT_WRITE означает «дождитесь, пока сокет станет доступным для записи, а затем снова вызовите эту функцию». .Вы можете получить либо SSL_WANT_WRITE, либо SSL_WANT_READ из вызовов SSL_read() или SSL_write().

16 голосов
/ 19 октября 2010

Вы уже прочитали документацию OpenSSL для ssl_read и ssl_get_error ?

ssl_read:

Если базовая BIO блокируетсяSSL_read () будет возвращаться только после завершения операции чтения или возникновения ошибки, за исключением случаев, когда происходит повторное согласование, и в этом случае может возникнуть SSL_ERROR_WANT_READ.Это поведение можно контролировать с помощью флага SSL_MODE_AUTO_RETRY вызова SSL_CTX_set_mode (3).

Если базовый BIO не является блокирующим, SSL_read () также вернется, когда базовый BIO не сможет удовлетворить потребности SSL_read () для продолжения операции.В этом случае вызов SSL_get_error (3) с возвращаемым значением SSL_read () приведет к SSL_ERROR_WANT_READ или SSL_ERROR_WANT_WRITE.Поскольку в любое время возможно повторное согласование, вызов SSL_read () также может вызвать операции записи!Затем вызывающий процесс должен повторить вызов после выполнения соответствующих действий для удовлетворения потребностей SSL_read ().Действие зависит от основной био.При использовании неблокирующего сокета ничего делать не нужно, но можно использовать select () для проверки требуемого условия.

ssl_get_error:

SSL_ERROR_WANT_READ,SSL_ERROR_WANT_WRITE

Операция не завершена;та же функция ввода / вывода TLS / SSL должна быть вызвана позже.Если к тому времени базовый BIO будет иметь данные, доступные для чтения (если код результата - SSL_ERROR_WANT_READ) или разрешит запись данных (SSL_ERROR_WANT_WRITE), то произойдет некоторое продвижение протокола TLS / SSL, то есть, по крайней мере, часть записи TLS / SSLбудет прочитано или написано.Обратите внимание, что повторная попытка может снова привести к условию SSL_ERROR_WANT_READ или SSL_ERROR_WANT_WRITE.Не существует фиксированного верхнего предела для числа итераций, которые могут понадобиться, пока прогресс не станет видимым на уровне протокола приложения.

Для сокетов BIO (например, когда использовался SSL_set_fd ()), select () или poll () на базовом сокете могут использоваться, чтобы узнать, когда следует повторить функцию ввода / вывода TLS / SSL.

Предупреждение: любая функция ввода / вывода TLS / SSL может привести к SSL_ERROR_WANT_READ или SSL_ERROR_WANT_WRITE.В частности, SSL_read () или SSL_peek () могут захотеть записать данные, а SSL_write () может захотеть прочитать данные.Это происходит главным образом потому, что рукопожатия TLS / SSL могут происходить в любое время во время протокола (инициируемого либо клиентом, либо сервером);SSL_read (), SSL_peek () и SSL_write () будут обрабатывать любые ожидающие рукопожатия.

OpenSSL реализован как конечный автомат.SSL_ERROR_WANT_READ означает, что больше входящих данных, а SSL_ERROR_WANT_WRITE означает, что больше исходящих данных требуется для продвижения вперед по соединению.Если вы получили SSL_ERROR_WANT_WRITE для операции ssl_read (), вам нужно отправить исходящие данные или хотя бы дождаться, пока сокет не станет доступным для записи.Если вы получаете SSL_ERROR_WANT_READ для операции ssl_write (), вам необходимо прочитать входящие данные.

Вы должны подписаться на списки рассылки OpenSSL .Этот вопрос часто задают.

5 голосов
/ 17 октября 2010

SSL_WANT_READ означает, что механизм SSL в настоящее время не может зашифровать вас, поскольку он ожидает дополнительных входных данных (либо как часть первоначального рукопожатия, либо как часть повторного согласования), поэтому, когда ваше следующее чтение завершено, и вы ' Если вы передали данные, поступившие через механизм SSL, вы можете повторить операцию записи.

Аналогично, SSL_WANT_WRITE означает, что механизм SSL ждет, пока вы извлечете из него некоторые данные и отправите их равноправному узлу.

Я писал об использовании OpenSSL с неблокирующими и асинхронными сокетами еще в 2002 году для Windows Developer Journal (перепечатано здесь ), и хотя эта статья якобы нацелена на код Windows, принципы для других платформ те же. Статья поставляется с некоторым кодом, который интегрирует OpenSSL с асинхронными сокетами в Windows и имеет дело со всей проблемой SSL_WANT_READ / SSL_WANT_WRITE.

По сути, когда вы получаете SSL_WANT_READ, вам нужно ставить исходящие данные в очередь до тех пор, пока вы не завершите чтение и не передадите новые входящие данные в механизм SSL, а после этого вы можете повторить отправку исходящих данных.

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