Вопрос или проблема
Этот вопрос уже имеет ответы здесь:
Как выбирается версия TLS между клиентом и сервером? [дубликат]
(2 ответа)
Кто отвечает за выбор набора шифров TLS – клиент или сервер?
(3 ответа)
Что именно определяет, какая версия SSL/TLS используется при доступе к сайту?
(3 ответа)
Закрыто 1 час назад.
Подводя итог моему вопросу:
Как клиент может поддерживать как TLS 1.2, так и 1.3?
Я посмотрел, как браузеры выбирают TLS… В кратком изложении: если клиент подключается к серверу, он проводит переговоры о том, будет ли обрабатываться TLS 1.3 или TLS 1.2. Я знаю, что сервер может ответить: “Хорошо, я обновлю вас до 1.3”, если он поддерживает 1.3.
Тем не менее, это не объясняет мой вопрос в коде OpenSSL. Вот в чем дело.
OpenSSL, кажется, требует, чтобы клиент решил, какую версию TLS использовать, прежде чем пытаться подключиться к серверу, основываясь на этой вещи, которая называется “метод”. Вот как я тестировал.
Это история о двух наборах шифров (хотя их гораздо больше, эти подойдут, чтобы продемонстрировать мой вопрос).
Два набора шифров, которые я использую:
TLS13-AES128-GCM-SHA256
ECDHE-RSA-AES128-GCM-SHA256
Я использую OpenSSL (также WolfSSL, так как он в основном переносим туда и обратно).
Но прежде чем клиент начнет, он еще не знает, что сервер может обрабатывать, так как он знает, какой “метод” загрузить?
Чтобы уточнить это, вот с чем я тестирую:
Я создал SSL-сервер с включенным TLS1.3 и использую это, когда я создаю контекст:
method = TLS_server_method();
И загружает эти два шифра с помощью:
SSL_CTX_set_cipher_list();
С сервера все в порядке.
Клиент загружает “метод” (все еще неясно, что это за вещь) одним из нескольких способов.
Сначала на стороне клиента я использую следующее (вставленные фрагменты, не предназначенные как полный пример). Он загружает только ОДИН шифр за раз:
void InitializeSSL( const char * cipher) {
meth = TLSv1_3_client_method();
if ((m_sslCtx = SSL_CTX_new(meth)) == NULL) {
printf(“ERROR: failed to create SSL CTX\n”);
return 1;
}
result = SSL_CTX_set_cipher_list(m_sslCtx, cipher); // <--- ТОЛЬКО ОДИН ШИФР ЗА ИТЕРАЦИЮ
if (result != SSL_SUCCESS) {
SSLCleanup();
return MISSING_NOT_PRESENT;
}
SSL_CTX_set_verify(m_sslCtx, SSL_VERIFY_NONE, 0); // не беспокоюсь о сертификатах для этого теста
m_socket = ConnectToHost();
m_dataSsl = SSL_new(m_sslCtx);
SSL_set_fd(m_dataSsl, m_socket);
result = SSL_connect(m_dataSsl);
. . .
Затем подключение закрывается и очищается. Затем все повторяется с другим шифром.
Он подключается только с шифром TLS1.3, как можно было ожидать. Другой шифр не работает.
Когда я использую
meth = TLSv1_2_client_method();
он только подключается с шифром TLS 1.2, и шифр TLS1.3 не работает. Хорошо.
Однако, когда я не указываю версию и использую более "универсальные" функции:
meth = TLS_method();
meth = TLS_client_method();
Когда он устанавливает "SSL_CTX_set_cipher_list()" на TLS13-AES128-GCM-SHA256, он подключается. Затем закрывает и освобождает все, как и должно.
Затем он снова выполняет "SSL_CTX_set_cipher_list()" на ECDHE-RSA-AES128-GCM-SHA256. Однако он не может подключиться к серверу. Я получаю то, что выглядит как "ошибка версии уровня записи".
Это подразумевает, что клиент должен знать, что ожидает сервер, и должен загрузить правильный метод ПРЕЖДЕ чем создаст контекст SSL.
Браузер не знает заранее, поддерживает ли сервер TLS 1.2 или 1.3. Так как же он знает, какой "метод" нужно загрузить? Без того чтобы просто отступить и начать заново, выполняя другой
meth = {некоторый альтернативный метод}_method();
Цель состоит в том, чтобы инструмент, который пробивает сервер одним шифром за раз, проверяет, будет ли он принимать конкретные шифры. Потому что клиенты склонны возвращаться и говорить: "Ваш сервер все еще имеет AES128_FRED_FLINTSTONE, который слишком старый и небезопасный". Так что мне нужно знать, как наш встроенный сервер обрабатывает шифры от сторонней библиотеки.
И названия шифров не очень способствуют пониманию, с какой версией TLS они работают, за исключением тех, что начинаются с "TLS_...", которые в основном относятся к TLS 1.3.
Или я что-то совершенно упускаю?
Буду благодарен за любой совет. Заранее спасибо.
-Скотт
Ответ или решение
Вопрос по выбору метода TLS 1.2 и 1.3 в OpenSSL
Ваша озабоченность по поводу выбора версии TLS в сетевых приложениях, использующих OpenSSL, поднимает важную тему, связанную с множеством аспектов протокола и совместимости. Давайте разберем, как клиенты могут поддерживать обе версии и как работает взаимодействие между ними.
1. Основы работы с методами TLS в OpenSSL
При создании SSL-контекста в OpenSSL, клиент должен указать, какой метод TLS он будет использовать. Именно этот метод определяет, какую версию протокола TLS будет использовать клиент. Ваша реализация показывает, как вы загружаете разные методы, такие как TLSv1_3_client_method()
и TLSv1_2_client_method()
, чтобы проверить поддержку конкретной версии TLS.
TLSv1_3_client_method()
: Поддерживает только TLS 1.3.TLSv1_2_client_method()
: Поддерживает только TLS 1.2.TLS_method()
: Поддерживает TLS 1.2 и 1.3 и может выбирать в зависимости от возможности сервера.
Когда вы используете более общие методы, такие как TLS_client_method()
, клиент будет сначала пытаться соединиться с сервером, применяя наиболее безопасный протокол, который поддерживается обеими сторонами. Это именно то, что делает TLS 1.3 предпочтительным, если сервер также его поддерживает.
2. Проблема выбора версии до подключения
Ваше наблюдение о том, что необходимо знать, какую версию TLS использовать перед соединением с сервером, — это сложный аспект. Браузеры и другие клиенты, как правило, не знают заранее, какую версию протокола поддерживает сервер. Вместо этого они используют более универсальные методы, которые допускают взаимную согласованность.
3. Поддержка нескольких шифров
Ваши проблемы с использованием SSL_CTX_set_cipher_list
также связаны с необходимостью согласования шифров, поддерживаемых как клиентом, так и сервером. Для успешного установления соединения необходимо, чтобы и версия TLS, и шифр были согласованы:
- При установлении соединения с использованием разных методов (например,
TLSv1_3_client_method()
иTLSv1_2_client_method()
), вы фактически ограничиваете себя лишь одной версией и набором шифров. - Используя
TLS_method()
, вы можете подключиться к серверу, который поддерживает обе версии, и в этом случае клиент и сервер будут согласовывать наилучший доступный вариант.
4. Рекомендации для вашей задачи
Чтобы создать инструмент для тестирования серверных шифров без необходимости постоянного перезапуска клиента, который самостоятельно выбирает метод, можно следовать следующим рекомендациям:
-
Используйте
TLS_method()
. Это позволит вашему клиенту динамически адаптироваться к возможностям сервера. Этот метод будет пробовать использовать TLS 1.3, но также будет понижен до TLS 1.2, если сервер не поддерживает 1.3. -
Создайте список поддерживаемых шифров для каждой версии TLS. Вы можете заранее определить, какие шифры поддерживаются для каждой версии и динамически проверять их доступность на сервере. Таким образом, вы сможете выбирать среди них в процессе тестирования, избегая проблем с несоответствием версий.
-
Логирование и отчетность. При тестировании серверов фиксируйте, какие шифры были приняты и какие отклонены. Это поможет вам быстро идентифицировать слабые места, и, по сути, устранить либо несовместимости.
-
Планируйте результаты тестирования. Берите во внимание, что не все шифры, предпочтительные для последних версий TLS, могут поддерживаться в предыдущих. Убедитесь, что ваши тесты корректно отображают эту информацию.
Заключение
Таким образом, взаимодействие между клиентским и серверным приложениями в контексте протоколов TLS и OpenSSL требует продуманного подхода к выбору версии, методов и шифров. Использование более универсальных методов, таких как TLS_method()
, позволяет вам элегантнее справляться с различиями и снижает вероятность возникновения ошибок, связанных с версиями протокола.