38. Шифрование соединений с использованием TLS/SSL
Перевод выполнен Алексеем Паутовым в рамках некоммерческого проекта RussianLDP (http://www.rldp.ru/). Именно на этом сайте и надлежит искать новые версии, если таковые будут.
38. Шифрование соединений с использованием TLS/SSL
Поддержка для TLS (Transport Layer Security), прежде известной как SSL (Secure Sockets Layer), осуществлена с использованием библиотек OpenSSL или GnuTLS (exim требует GnuTLS релиза 1.0 или более позднего). В дистрибутиве exim нет никакого кода для непосредственного осуществления TLS. Для его использования Вы должны инсталлировать OpenSSL или GnuTLS, а затем собрать версию exim в который включена поддержка TLS (смотрите раздел 4.6). Также Вы должны понимать базовые концепции шифрования на организационном уровне и, в частности, способы использования публичных ключей, частных ключей и сертификатов.
RFC 3207 задаёт, как SMTP-соединения могут использовать шифрование. Как только установлено подключение, клиент даёт команду STARTTLS. Если сервер её принимает, клиент и сервер договариваются о механизме шифрования. Если договорённость успешна, данные, впоследствии передаваемые между ними, зашифрованы.
ACL exim позволяют детектировать, зашифрован текущий сеанс или нет, и, таким образом, какой метод шифрования используется, предоставил ли клиент сертификат, и был ли сертификат проверен. Это позволяет серверу exim принимать или отклонять определённые команды, основанные на состоянии шифрования. Внимание: Определённые типы файрволлов и антивирусных систем могут прерывать TLS-соединения. Вам необходимо выключить SMTP-сканирование для этих продуктов, чтобы TLS заработал.
38.1. Поддержка для наследственного ssmtp (или smtps) протокола
Ранние воплощения шифрованного SMTP использовали иной порт TCP вместо обычного и ожидали, что переговоры о шифровании начнутся немедленно вместо ожидания команды клиента STARTTLS, использующего стандартный SMTP-порт. Протокол назывался ssmtp или smtps, и для этой цели был выделен 465-й порт.
Этот подход был оставлен, когда было стандартизовано шифрованное SMTP, но всё ещё есть клиенты, использующие его по наследству. Exim поддерживает этих клиентов путём глобальной опции tls_on_connect_ports. Её значение должно быть списком номеров портов, обычное использование таково:
tls_on_connect_ports = 465 |
Номер порта, определяемый этой опцией, применяется ко всем SMTP-соединениям через демона и через inetd. Вам всё ещё необходимо задавать все порты, используемые демоном (путём установки daemon_smtp_ports или local_interfaces или опцией командной строки -oX), поскольку tls_on_connect_ports не добавляет дополнительного порта, скорее, она определяет иное поведение на порту, определённом в другом месте.
Также, есть опция командной строки -tls-on-connect. Она переопределяет tls_on_connect_ports: она вызывает наследование поведения для всех портов.
38.2. OpenSSL против GnuTLS
Первая поддержка TLS в exim была осуществлена с использованием OpenSSL. Поддержка GnuTLS последовала позднее, когда была выпущена первая версия GnuTLS. Для сборки exim с использованием GnuTLS необходимо установить:
USE_GNUTLS=yes |
SUPPORT_TLS=yes |
Также Вы должны установить TLS_LIBS и TLS_INCLUDE соответственно так, чтобы были найдены включаемые файлы и библиотеки GnuTLS. Есть некоторые отличия при использовании GnuTLS вместо OpenSSL:
- Опция tls_verify_certificates должна содержать имя файла, а не имя каталога (для OpenSSL это может быть любым).
- Опция tls_dhparam игнорируется, поскольку ранние версии GnuTLS не имели средств для изменения параметров Diffie-Hellman. Я понимаю, что это изменилось, но exim не был обновлён для предоставления этого средства.
- Строка выдающегося имени (DN), сообщаемая библиотекой OpenSSL, использует слэш для разделения полей. GnuTLS использует запятые в соответствии с RFC 2253. Это вызываeтся значением переменной $tls_peerdn.
- OpenSSL идентифицирует шифр, используя дефисы как разделители, например: DES-CBC3-SHA. GnuTLS использует подчёркивания, например: RSA_ARCFOUR_SHA. Что хуже, OpenSSL жалуется на присутствие символов подчёркивания в списке шифров. Чтобы упростить жизнь, exim заменяет подчёркивания на дефисы для OpenSSL, а дефисы на подчёркивания для GnuTLS при обработке списков шифров в опциях tls_require_ciphers (глобальная опция и транспортная опция smtp).
- Опции tls_require_ciphers работают не так, как описано в разделах 38.4 и 38.5.
38.3. Вычисление параметра GnuTLS
GnuTLS использует параметры RSA и D-H, которые требуют для вычисления существенного времени. Неблагоразумно вычислять их заново для каждой сессии TLS. Поэтому exim сохраняет эти данные в файле в своем каталоге спула, называемом gnutls-params. Файл принадлежит пользователю exim и читаем лишь его владельцем. Каждый процесс exim, который запускает GnuTLS, читает параметры RSA и D-H из этого файла. Если файл не существует, первый процесс exim, которому он нужен, вычисляет данные и записывает их во временный файл, переименовываемый по завершении. Не имеет значения, если несколько процессов exim делают это одновременно (кроме траты некоторых ресурсов). Как только файл помещён на место, новые процессы exim немедленно начинают его использовать. Для максимальной безопасности, параметры, которые сохраняются в этом файле, периодически, должны быть повторно вычислены, частота зависит от уровня Вашей параноидальности. Упорядочивание этого принципиально просто: просто удалите файл, когда хотите вычислить новое значение. Однако, могут быть проблемы. Для вычисления новых параметров необходимы случайные числа, а они берутся из /dev/random. Если система не очень активна, /dev/random может задержать возврат данных, пока не будет доступно достаточно хаоса. Это может вызывать зависание exim на довольно существенное время, вызывая таймауты для входящих соединений. Решение: генерировать параметры вне exim. Они сохраняются в gnutls-params в формате PEM, что означает, что они могут быть сгенерированы внешне, используя команду certtool, которая является частью GnuTLS. Для замены параметров новыми, вместо удаления файла и разрешения exim пересоздать его, Вы можете генерировать новые параметры, используя certtool, а после завершения заменить файл кэша exim путём переименования. Уместные команды что-то типа этого:
# rm -f new-params # touch new-params # chown exim:exim new-params # chmod 0400 new-params # certtool --generate-privkey --bits 512 >new-params # echo "" >>new-params # certtool --generate-dh-params --bits 1024 >> new-params # mv new-params gnutls-params |
38.4. Требование специфических шифров в OpenSSL
В библиотеке OpenSSL есть функция, которая может передавать список наборов шифров до того, как имеет место переговор о шифре. Этим определяется, какие шифры доступны. Список разделён двоеточиями и может содержать имена типа DES-CBC3-SHA. Exim передаёт раскрытое значение tls_require_ciphers напрямую этому вызову функции. Следующее цитирование документации OpenSSL определяет, какие формы элементов допустимы в строке шифра:
- Он может состоять из одного шифра, типа RC4-SHA.
- Он может представлять список шифров содержащих определённый алгоритм или шифры определённого типа. Например, SHA1 представляет все шифры, используя алгоритм SHA1, а SSLv3 представляет все алгоримы SSL v3.
- Списки наборов шифров могут быть объединены в одну строку шифра, используя символ +. Это используется как логическая операция И. Например, SHA1+DES представляет все наборы шифров, содержащие алгоритмы SHA1 и DES. Каждой строке шифра произвольно может предшествовать один из символов !, - или +.
- Если используется !, шифр удаляется из списка. Удалённые шифры не могут вновь появляться в списке, даже если они явно заявлены.
- Если используется -, шифр удаляется из списка, но некоторые или все шифры могут быть добавлены последующими позднее опциями.
- Если используется +, шифр перемещается в конец списка.
Эта опция не добавляет новых шифров: она лишь перемещает существующие.
Если не присутствует ни один из этих символов, строка интерпретируется как
список шифров, который будет добавлен к текущему привелигированному списку.
Если список включает какие-то шифры, которые уже пристутсвуют,
они будут проигнорированы: то есть, они не будут перемещены в конец списка.
38.5. Специфические шифры, требующиеся в GnuTLS
Библиотека GnuTLS не имеет комбинированной функции, как OpenSSL. Вместо этого, она позволяет вызывающему задать отдельные списки методов обмена ключей, главных алгоритмов шифрования и алгоритмов MAC. К сожалению, эти списки числовые, и библиотека не имеет функции для превращения имён в номера. Следовательно, список распознаваемых имён должен быть встроен в приложение.
В настоящее время exim разрешает изменять лишь список главных алгоритмов шифрования. Опция tls_require_ciphers имет такой же формат, что и у OpenSSL. Exim ищет каждый элемент для имени доступного алгоритма. Например, если список содержит RSA_AES_SHA, тогда распознаётся AES. Список шифровальных алгоритмов отправляется с установкой алгоритмов по умолчанию. Если первый элемент в tls_require_ciphers не начинается с восклицательного знака, все элементы по умолчанию удаляются. Таким образом, могут использоваться лишь заданные значения. Если первый элемент в tls_require_ciphers действительно начинается с восклицательного знака, значения по умолчанию остаются в списке. Тогда любой элемент, начинающийся с восклицательного знака, вызывает удаление релевантных алгоритмов из списка, а любой элемент, не начинающийся с восклицательного знака, вызывает добавление релевантных алгоритмов в список. Таким образом,
разрешает все значения по умолчанию, кроме использующих ARCFOUR, тогда какtls_require_ciphers = !RSA_ARCFOUR_SHA
разрешает лишь шифрование, использующее AES и 3DES. В настоящее время распознаются алгоритмы: AES_256, AES_128, AES (оба из предшествовавших), 3DES и ARCFOUR_128. Нераспознанные алгоритмы игнорируются. В сервере порядок списка не имеет значения: сервер будет извещать о доступности всех имеющихся методов шифрования. Однако, в клиенте порядок списка определяет порядок для использования алгоритмов. Первым пробуется первый из клиентского списка, о котором извещал сервер. Порядок значений по умолчанию перечислен выше.tls_require_ciphers = AES : 3DES
38.6. Конфигурирование сервера exim для использования TLS
Когда exim собран с поддержкой TLS, он извещает клиентские хосты, совпадающие с tls_advertise_hosts, о доступности команды STARTTLS, но не какие-либо другие хосты. Значение этой опции по умолчанию не задано, что означает, что о STARTTLS никто не извещается. Такое значение по умолчанию выбрано поскольку Вы должны привести в порядок некоторые другие опции, чтобы сделать доступным TLS, а также это разумно для систем, которые хотят использовать TLS лишь в роли клиента.
Если клиент выдаёт команду STARTTLS, и на сервере существует какая-то конфигурационная проблема, команда отклоняется с ошибкой 454. Если клиент упорствует в попытках подавать команды SMTP, все они, кроме QUIT, отклоняются с ошибкой:
554 Security failure
Если команда STARTTLS подаётся в пределах существующей TLS-сессии, она отклоняется с кодом ошибки 554. Для включения операций TLS на сервере, Вы должны установить опцию tls_advertise_hosts в соответствие каким-то хостам. Вы можете, разумеется, установить её в * для соответствия всем хостам. Однако, это не всё, что Вы должны сделать. TLS-сессии на сервере не будут работать без некоторого дальнейшего конфигурирования в конце сервера.
По слухам известно, что все существующие клиенты, которые поддерживают TLS/SSL, используют шифрование RSA. Чтобы это работало, Вам необходимо установить в сервере:
tls_certificate =/some/file/name tls_privatekey =/some/file/name
Фактически, эти опции представляют собой раскрываемые строки, таким образом, Вы можете сделать их зависимыми от подключенного клиента, если захотите. Первый файл содержит серверный сертификат X509, второй содержит частный ключ, который с ним идёт. Эти файлы должны быть читаемы пользователем exim и всегда должны быть заданы с полным путём. Это может быть один и тот же файл, если в нём содержатся сертификат и ключ. Если опция tls_privatekey не задана, раскрытие принудительно неудачно или результат пустая строка, предполагается такой случай. Файл сертификата также может содержать промежутчные сертификаты, которые необходимы для отсылки клиенту с целью аутентифицировать сертификаты сервера.
Если Вы не понимаете чего-то о ключах и сертификатах, пожалуйста, попробуйте найти источник этой вводной информации, которая не является специфической для exim. Есть несколько комментариев ниже, в разделе 38.11. Отметьте: Эти опции не применяются, когда exim работает как клиент, они применяются лишь в случае сервера. Если необходимо использовать сертификат в exim в роли клиента, Вы должны установить опции с теми же самыми названиями в транспорте smtp.
Только с этими опциями сервер exim способен использовать TLS. Этим не требуется, чтобы клиент обладал сертификатом (но смотрите ниже, как настоять на этом). Существует одна опция, которая бывает необходима в других ситуациях. Если опция
установлена, библиотека SSL инициализируется для использования шифрования Diffie-Hellman с параметрами, содержащимися в файле. Это увеличивает набор методов шифрования, поддерживаемых сервером. Смотрите командуtls_dhparam = /some/file/name
для способа генерации этих данных. В настоящее время tls_dhparam используется, лишь когда exim скомпонован с OpenSSL. При использовании GnuTLS она игнорируется. Строки, предоставляемые для этих трёх опций, раскрываются при каждом подключении клиентского хоста. Поэтому возможно использовать различные сертификаты и ключи для разных хостов, если Вы этого желаете, для управления раскрытием, путём использования клиентского IP-адреса в переменной $sender_host_address. Если строка раскрытия принудительно неудачна, exim ведёт себя так, будто эта опция не установлена. В переменную $tls_cipher устанавливается метод шифрования, о котором договорились для входящего соединения TLS. Это включается в заголовок Received: входящего сообщения (по умолчанию, разумеется, Вы можете это изменить), а также включается в строку протокола прибывающего сообщения с ключом X=, если не выключен селектор протоколов tls_cipher. Выражение encrypted может использоваться для тестирования специфического шифрования в ACL.openssl dhparam
ACL, которые запускаются для последующих команд SMTP, могут проверить имя метода шифрования и изменить свои действия соответствующим образом. Имена методов шифрования берутся используемые OpenSSL. Они могут отличаться от имён, используемых в других местах. Например, OpenSSL использует имя DES-CBC3-SHA для шифрования, известного в других контекстах как TLS_RSA_WITH_3DES_EDE_CBC_SHA. Для дополнительных деталей проверьте документацию на OpenSSL.
38.7. Запрос и проверка клиентских сертификатов
Если Вы хотите, чтобы сервер exim запросил сертификат при переговорах о TLS-сессии с клиентом, Вы должны установить tls_verify или tls_try_verify_hosts. Разумеется, Вы можете установить любую из них в * для применения ко всем соединениям TLS. Для любого хоста, который совпадает с этими опциями, exim запрашивет сертификат как часть установки сессии TLS. Содержимое сертификата проверяется путём его сравнения со списком ожидаемых сертификатов. Они должны быть доступны в файле, или в каталоге (только для OpenSSL, не для GnuTLS), идентифицируемом путём tls_verify_certificates.
Файл может содержать много сертфикатов, связанных конец к концу. Если используется каталог (только для OpenSSL), каждый сертификат должен быть в отдельном файле с именем (или символической ссылкой) формы <hash>.0, где <hash> задает значение хэша, созданное из сертификата. Вы можете вычислить релевантный кэш путём запуска команды
где /cert/file содержит один сертификат. Различие между tls_verify_hosts и tls_try_verify_hosts в том, что происходит, если клиент не предоставляет сертификат, или если сертификат не совпадает ни с одним из сертификатов в коллекции из tls_verify_certificates. Если клиент совпадает с tls_verify_hosts, попытка установить TLS-сессию прерывается, а входящее соединение обрыватся. Если клиент совпадает с tls_try_verify_hosts, продолжается (шифрованная) SMTP-сессия. ACL, запускаемые для последующих команд SMTP, могут детектировать факт, что сертификат не был проверен и соотвтественно изменить свои действия. Например, Вы можете настаивать на сертификате до принятия сообщения для релея, но не когда сообщения предназначено для локальной доставки. Когда клиент предоставляет сертификат, (проверенный или нет), значение DN сертификата становится доступным в переменной $tls_peerdn в процессе последующей обработки сообщения.openssl x509 -hash -noout -in /cert/file
Поскольку часто это длинная текстовая строка, по умолчанию она не включается в строку протокола или в заголовок Received:. Вы можете принять меры для её протоколирования, установив ключ DN= в селекторе протоколов tls_peerdn и использовать received_header_text для изменения заголовка Received:. Когда сертификат не предоставлен, переменная $tls_peerdn пуста.
38.8. Отменённые сертификаты
Издатели сертификатов выпускают Списки Аннулированных Сертификатов (Certificate Revocation Lists, CRL), когда сертификаты отменяются. Если у Вас есть такой список, можете передать его серверу exim, используя глобальную опцию tls_crl, и клиенту exim, используя опцию с идентичным названием для транспорта smtp. В каждом случае значение опции раскрывается, и должно быть именем файла, содержащего CRL в формате PEM.
38.9. Конфигурирование клиента exim для использования TLS
Селекторы протоколов tls_ciphe и tls_peerdn применяются к исходящим SMTP-доставкам так же, как и ко входящим, последние вызывают протоколирование серверных DN-сертификатов. Оставшаяся клиентская конфигурация для TLS вся в транспорте smtp. Нет необходимости устанавливать какие-либо опции для работы TLS в транспорте smtp. Если exim собран с поддержкой TLS, а сервер оповестил о поддержке TLS, транспорт smtp всегда пробует запустить TLS-сессию. Однако, это может быть предотвращено установкой hosts_avoid_tls (транспортная опция) в список серверных хостов, с которыми не используется TLS. Если Вы не хотите, чтобы exim пытался отправить сообщения незашифрованными, когда попытка установки шифрованного соединения была неудачной, можете установить опцию hosts_require_tls в список хостов, для которых шифрования является обязательным. Для этих хостов доставка всегда задерживается, если не может быть установлено шифрованное соединение. Если для адреса есть другие хосты, они пробуются обычным способом.
Когда хост сервера не находится в hosts_require_tls, exim может попробовать доставить сообщение незашифрованным. Он всегда так делает, если ответом на STARTTLS будет код 5xx. Для временного кода ошибки или для ошибки переговоров о сессии TLS после успешного кода ответа, происходящее контролируется путём опции tls_tempfail_tryclear транспорта smtp. Если она ложна, доставка к хосту задерживается, и пробуются другие хосты (если они доступны). Если она истинна, exim пытается доставить нешифрованное сообщение после 4xx ответа на STARTTLS, и, если STARTTLS принимается, но последующие переговоры о TLS неудачны, exim закрывает текущее соединение (поскольку оно в неизвестном состоянии), открывает новое к тому же самому хосту, а затем пытается доставить сообщение нешифрованным.
Опции tls_certificate и tls_privatekey транспорта smtp предоставляют клиенту сертификат, который он передаёт на сервер, если тот его запрашивает. Если сервер exim, он будет просить сертификат, лишь если клиент совпадает с опцией tls_verify_hosts или tls_try_verify_hosts.
Отметьте: Эти опции должны быть заданы в транспорте smtp exim для использования TLS, когда он работает как клиент. Exim не предполагает, что серверный сертификат (установленный путём глобальной опции с тем же самым именем) также должен использоваться при работе в роли клиента. Если установлена опция tls_verify_certificates, она должна быть именем файла или (только для OpenSSL, не для GnuTLS) каталогом, который как ожидается содержит коллекцию серверных сертификатов. Клиент проверяет сертификат сервера со своей коллекцией, принимая во внимание любые отозванные сертификаты, которые находятся в списке, заданном опцией tls_crl. Если для транспорта smtp установлена опция tls_require_ciphers, она должна содержать список разрешённых методов шифрования. Если любая из этих проверок неудачна, доставка к текущему хосту прекращается, а транспорт smtp пробует доставить на альтернативный хост, если он есть.
Все опции TLS в транспорте smtp раскрываются до использования, с $host и $host_address, содержащими имя и адрес сервера, на который подконнектился клиент. Принудительная ошибка раскрытия заставляет exim вести себя так, как будто соответствующая опция не задана.
38.10. Несколько сообщений через одно шифрованное TCP/IP-соединение
Exim посылает много сообщений по одному TCP/IP-соединению путём запуска нового процесса для каждого сообщения, передавая сокет от одного процесса следующему. Эта реализация не очень хороша для работы с TLS, поскольку есть много информации о состоянии, ассоциированной с соединением TLS, а не только идентификатор сокета. Передача всей информации о состоянии другому процессу невыполнима.
Следовательно, exim завершает существующую сессию TLS до передачи сокета новому процессу. Новый процесс может попробовать запустить сеанс TLS, и в случае успеха попробовать заново аутентифицироваться, если используется AUTH, до посылки следующего сообщения.
Из RFC не ясно, действительно или нет SMTP-сессия продолжается в чистом виде после закрытия TLS, или же TLS может быть перезапущен позже, как было описано. Однако, если сервер exim, эта остановка и реинициализация работает. Неизвестно, каким (или обоими) образом себя ведут другие серверы, если клиент закрывает сеанс TLS и продолжает с нешифрованным SMTP, но, разумеется, есть те, которые не работают. Для таких серверов exim не должен передавать сокет другому процессу, поскольку неудача последующей попытки его использования заставила бы exim записать в протоколы временную ошибку хоста и задержать иные доставки на этот хост.
Для тестирования этого случая exim посылает команду EHLO на сервер после закрытия TLS-сессии. Если она удачна, соединение закрывается вместо передачи новому процессу доставки, но информация о повторе не записывается. Также есть ручная отмена: Вы можете установить опцию hosts_nopass_tls транспорта smtp в совпадение с тими хостами, для которых exim не должен передавать соединение новому процессу, если используется TLS.
38.11. Сертификаты и всё такое
Для полного понимания работы TLS, необходимо знать о сертификатах, подписании сертификатов и авторизаторах сертификатов. Этот документ не место для обучения, тем более, что я не очень много знаю об этом. Некоторое полезное введение может быть найдено в FAQ дополнения SSL к Apache, в настоящее время: http://www.modssl.org/docs/2.7/ssl_faq.html#ToC24. Другие части документации по modssl также полезны и имеют ссылки на дальнейшие файлы. Книга Eric Rescorla SSL and TLS, опубликованная Addison-Wesley (ISBN 0-201-61598-3), содержит введение и дополнительные всесторонние описания. Некоторые типовые программы, взятые из книги, доступны по адресу: http://www.rtfm.com/openssl-examples/.
38.12. Цепочки сертификатов
Файл, указанный в tls_certificate, может содержать более одного сертификата. Это полезно в случае, когда посылаемый сертификат проверяется промежуточным сертификатом, которого не имеет другая сторона. Несколько сертификатов должны быть в правильном порядке в файле. Вначале хост сертифицирует сам себя, затем следующий сертификат для проверки выданного хостом, затем следующий для проверки предыдущего и так далее до (опционально) корневого сертификата. Корневой сертификат уже должен быть доверенным у получателя для успешной проверки, разумеется, если он заранее не установлен, посылка корневого сертификата вместе с остальными делает его доступным пользователю для установки, если конечный получатель представляет собой пользовательский MUA, который может взаимодействовать с пользователем.
38.13. Самоподписанный сертификат
Вы можете создать самоподписанный сертификат, используя команду req, предоставляемую OpenSSL, например, так:
openssl req -x509 -newkey rsa:1024 -keyout file1 -out file2 \ -days 9999 -nodes
file1 и file2 могут быть одним и тем же файлом, ключ и сертификат разграничены, и могут быть идентифицированы независимо. Опция -days задает период, в течение которого сертификат действителен. Опция -nodes важна: если Вы её не зададите, ключ шифруется с запрашиваемой у Вас парольной фразой, и любое использование ключа вызывает запрос пароля. Это бесполезно, если Вы собираетесь использовать ключ в MTA, где запрос невозможен.
Самоподписанный сертификат, сделанный таким образом, вполне достаточен для тестирования и может быть адекватен для всех Ваших требований, если Вы, главным образом, интересуетесь шифрованием передачи, а не безопасной идентификацией.
Однако, многие клиенты требуют, чтобы предоставленный сервером сертификат был пользовательским (также называемый "leaf or site") сертификатом, а не самоподписанным сертификатом. В этой ситуации самоподписанный сертификат должен быть установлен на клиентском хосте как доверенный корневой авторитативный сертификат (CA), а сертификат, используемый exim, должен быть пользовательским сертификатом, подписанным с этим самоподписанным сертификатом. Для информации о создании самоподписанных сертификатов и использовании их для подписания пользовательских сертификатов, смотрите часть General implementation overview книги Open-source PKI, доступной в онлайне http://ospkibook.sourceforge.net/.