Что означает, что SSL_library_init не реентерабелен для практических целей?

Я использую библиотеку openssl, чтобы открыть соединение TLS с некоторым сервером. Читая документацию библиотеки (да, некоторые люди все еще читают документацию и справочные страницы), я наткнулся на предложение «SSL_libary_init () is not реентерабельность".

Я понимаю, в общем, что такое нереентерабельная функция: то есть некоторая функция, которая сохраняет внутреннее состояние таким образом, что вызов ее дважды в одно и то же время или ее прерывание во время выполнения может вызвать хаос (функция не выполняет то, что ожидают вызывающие абоненты) .

Но в конкретном случае SSL_library_init () мне интересно, что это на самом деле означает.

  • Означает ли это, что если при вызове SSL_library_init () произойдет какое-то прерывание, оно не будет правильно инициализировать библиотеку SSL? Следовательно, я должен отключить все доступные прерывания перед его вызовом и снова включить необходимые в дальнейшем?

  • означает ли это, что поток небезопасен, и что я должен убедиться, что два потока не могут вызывать его одновременно? (выглядит вероятным, даже если безопасность потоков не означает то же самое, что и реентерабельность).

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

Поскольку я работаю над прокси-сервером, один конец которого является клиентом, а другой - сервером, оба конца потенциально могут использовать службы TLS (но я также мог быть только одним концом или ни одним). Должен ли я управлять библиотекой SSL как общесистемным синглтоном? Если это так, им достаточно легко управлять, но это не совсем проблема повторного входа, как я понимаю это слово.

Я не знаю короткого слова для функции, которую следует вызывать только один раз ...

У меня тоже есть аналогичный вопрос для SSL_CTX_new (). В документации указано, что его следует вызывать только один раз за время существования программы. Это раздражает, поскольку кажется, что сервер и клиент (или несколько независимых экземпляров сервера или клиента, работающие в одном процессе) ограничиваются использованием одного и того же SSL_METHOD, и это кажется неправильным, но я все же надеюсь, что в этом случае это просто некоторая неточность документации .

Есть ли у кого-нибудь достаточно опыта работы с openSSL, чтобы объяснить, что я должен или не должен делать с кодом инициализации OpenSSL, чтобы оставаться в безопасности?


person kriss    schedule 28.03.2013    source источник
comment
Я не знаю SSL, поэтому не держите меня за то, что я скажу дальше, но чаще всего, когда они говорят, что эта функция не является реентерабельной, они говорят так, потому что они обращаются к некоторой глобальной переменной. Поскольку это функция init, имеет смысл просто вызвать ее один раз в main и покончить с ней (так что вам не нужно беспокоиться о безопасности потоков или повторном входе!). SSL_CTX_new также звучит так, как будто он инициализирует глобальные переменные, поэтому его многократный вызов ничего не дает (кроме, возможно, утечки памяти). Опять же, я не знаю SSL, так что это все лишь предположения.   -  person Shahbaz    schedule 28.03.2013
comment
@Shahbaz: да, наверное, ты прав. Не имеет большого отношения к повторному входу, но, вероятно, это значит. Второй более раздражает, если он на самом деле глобален, потому что он устанавливает некоторую таблицу диспетчеризации (но я все же надеюсь, что она не будет действительно глобальной: если это, где, зачем ему выделять память?   -  person kriss    schedule 28.03.2013
comment
опять же, я понятия не имею, что такое SSL, но смотрю документацию SSL_CTX_new, Я не вижу никаких упоминаний о необходимости вызывать только один раз за время существования программы. Где ты это видел?   -  person Shahbaz    schedule 28.03.2013
comment
Я просто надеюсь, что это означает, что он должен вызываться хотя бы один раз для каждой программы. Если это означает один раз и только один раз, это проблема, потому что тогда все открытые SSL-соединения должны будут использовать один и тот же уровень протокола (таблица отправки SSL_METHOD).   -  person kriss    schedule 29.03.2013
comment
Я понимаю. На самом деле, поскольку он возвращает SSL_CTX *, я подозреваю, что это нормально, если вы вызовете его несколько раз; Вы получите несколько контекстов. Он говорит, что один раз за время жизни программы, вероятно, потому что они не подозревали, что кто-то захочет иметь несколько контекстов в одной программе, поэтому они говорят, что одного достаточно (не то, чтобы больше было вредно). Вы можете получить лучшее представление, если спросите в их списке рассылки (если он у них есть) или посмотрите исходный код.   -  person Shahbaz    schedule 29.03.2013


Ответы (1)


Я могу дать вам подсказку, основываясь на том, что вижу. У меня есть веб-сервер CentOS 7 / Django 1.9.3 / Apache 2.4 / mod_ssl / Python 3.4, который получает https: соединения от пользователей. Во время обработки запросов серверу необходимо запрашивать у серверной части информацию, необходимую для удовлетворения запроса. Бэкэнд-запрос отлично работает при автономном запуске, но генерирует:

OSError(0, 'Error')
Line 810, /lib64/python3.4/ssl.py

803  def do_handshake(self, block=False):
804      """Perform a TLS/SSL handshake."""
805      self._check_connected()
806      timeout = self.gettimeout()
807      try:
808          if timeout == 0.0 and block:
809              self.settimeout(None)
810          self._sslobj.do_handshake()          # <<<-------

при запуске в контексте Apache WSGI.

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

Несомненно, двухуровневые веб-серверы являются зрелым шаблоном проектирования, поэтому должен быть обходной путь. Спасибо, что опубликовали эту статью о невозможности повторного входа - это была первая подсказка, которую я обнаружил, которая может быть причиной моей проблемы.

Для справки, мой код вызывает службу RESTful, которая берет отличительное имя пользователя, извлеченное из SSL_CLIENT_CERT, и возвращает атрибуты пользователя в формате JSON:

import requests, urllib

URL = 'https://example.com/rest/user_info/'

def get_user_info(dn)
    query = URL + urllib.parse.quote(dn)
    return requests.get(query, cert=('server.crt', 'server.key'), verify='ca_bundle.crt').json()

Этот код отлично работает при запуске из командной строки на веб-сервере (в каталоге WSGI как пользовательский apache), но взрывается при запуске самим Apache.

person Dave    schedule 05.04.2016