OpenSSL SSL_CTX_NEW возвращает «нулевой метод ssl передан»

Код: TIdSSLIOHandlerSocketOpenSSL( ASMTP.IOHandler ).SSLOptions.SSLVersions := [sslvSSLv2,sslvSSLv23,sslvSSLv3,sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2]

Похоже, проблема заключается в методе TIdSSLOptions.SetSSLVersions, если вы устанавливаете что-то кроме одной версии, она устанавливает fMethod := sslvSSLv23. Если он недоступен, TIdSSLContext.SetSSLMethod возвращает nil, и вы получаете эту ошибку.

Indy, декабрь 2015 г., TIdSSLContext.SetSSLMethod может возвращать nil. Решение возвращено.


83
1

Ответ:

Решено

Что за вопрос? Нет, надеюсь, кто-то найдет это полезным.

Это сайт вопросов и ответов. Делиться знаниями — это хорошо, но это должно быть в формате вопросов и ответов. Смотрите Можно я сам отвечу на свой вопрос?

В любом случае, это больше похоже на отчет об ошибке, о котором нужно было сообщить в систему отслеживания проблем Indy, а не на публичный форум.

При этом вам НИКОГДА не следует включать протоколы SSLv2 или SSLv3, так как они больше не являются безопасными и даже больше не доступны во многих выпусках OpenSSL. А SSLv23 — это просто подстановочный знак, он предназначен для использования только в свойстве Method, а не в свойстве SSLVersions (на самом деле, если вы попытаетесь указать его с любой другой версией, он будет просто проигнорирован). Вы должны использовать только протоколы TLSv1+ в SSLVersions, позвольте Indy работать с SSLv23 внутри по мере необходимости.

TIdSSLIOHandlerSocketOpenSSL( ASMTP.IOHandler ).SSLOptions.SSLVersions := [sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2]

Похоже, проблема заключается в методе TIdSSLOptions.SetSSLVersions, если вы установите что-либо, кроме одной версии, он устанавливает fMethod := sslvSSLv23.

Так и должно быть, потому что метод SSLv23 — это то, как OpenSSL обеспечивает динамическое согласование версий во время рукопожатия SSL/TLS, позволяя клиенту и серверу согласовывать самую высокую версию TLS, которую они оба поддерживают. В противном случае, если клиент использует только определенную версию, и если сервер не поддерживает эту версию, рукопожатие TLS завершится ошибкой.

Если он недоступен, TIdSSLContext.SetSSLMethod возвращает nil, и вы получаете эту ошибку.

Во-первых, SetSSLMethod() никогда не вернется nil в SSL_CTX_new(). Если запрошенный метод не поддерживается OpenSSL, SetSSLMethod() вместо этого вызывает EIdOSSLGetMethodError исключение.

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

Самый простой обходной путь - установить метод после настройки SSLVersions.

Свойства Method и SSLVersions являются взаимоисключающими, установка одного из них обновляет другое. Однако Method устарел, вам действительно следует использовать только SSLVersions, даже для одиночных версий TLS.

Этого тоже может не быть, поэтому лучший обходной путь может быть в indy:

Ваш обходной путь полностью отключает согласование версий при запросе SSLv23. Это не лучший вариант для Indy.

Настоящим обходным решением было бы, если бы ваш собственный код перехватывал исключение EIdOSSLGetMethodError, когда SSLv23 недоступен, а затем вы могли бы повторно попытаться подключиться, используя отдельные версии TLS по мере необходимости. Никаких изменений в коде Indy для этого не требуется.