openjdk.ruOpenJDK на русском

JEP 249: OCSP Stapling for TLS

OCSP stapling для TLS

ОтветственныйJamil Nimeh
ТипFeature
ОбластьSE
СтатусClosed / Delivered
Выпуск9
Компонентsecurity-libs / javax.net.ssl
Обсуждениеsecurity dash dev at openjdk dot java dot net
ТрудоёмкостьM
ДлительностьM
РецензентыBrian Goetz, Sean Mullan
ОдобренBrian Goetz
Создан2014/06/09 07:30
Обновлён2026/07/29 18:45
Задача8046321

Аннотация

Реализовать OCSP stapling с помощью расширения TLS Certificate Status Request (раздел 8 RFC 6066) и расширения Multiple Certificate Status Request (RFC 6961).

Критерии успеха

Реализация как в клиентском, так и в серверном режиме должна успешно взаимодействовать как минимум с двумя сторонними реализациями TLS, поддерживающими OCSP stapling.

Мотивация

Проверка статуса отзыва сертификата X.509 — критически важная часть корректной аутентификации на основе сертификатов. Однако проверка статуса сертификата с помощью OCSP обычно требует сетевого запроса для каждого проверяемого сертификата. Из-за дополнительных сетевых запросов включение проверки OCSP для TLS на стороне клиента может существенно сказаться на производительности.

OCSP stapling позволяет, чтобы расходы ресурсов на предоставление OCSP-ответов нёс тот, кто предъявляет сертификат, а не выпустивший его удостоверяющий центр (Certificate Authority, CA). В контексте TLS за запрос OCSP-ответа и его отправку клиентам во время рукопожатия SSL/TLS отвечает TLS-сервер. Кроме того, сервер может кэшировать OCSP-ответы и передавать их всем подключающимся к нему клиентам. Это значительно снижает нагрузку на OCSP-респондер, поскольку ответ может кэшироваться и периодически обновляться сервером, а не каждым клиентом.

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

Производительность

Если клиент получает статус отзыва непосредственно от OCSP-респондера, то для каждого клиента, подключающегося к определённому серверу, OCSP-респондер должен вернуть ответ с конкретным статусом сертификата. Для сайта с высокой посещаемостью OCSP-респондер, скорее всего, станет узким местом по производительности. Кроме того, проверка статуса отзыва включает несколько циклов обмена запросом и ответом. Если проверка OCSP включена на стороне клиента, это существенно сказывается на производительности.

Безопасность

Adam Langley в одной из записей своего блога рассказывает о проблемах безопасности, с которыми сталкиваются клиентские приложения при традиционном OCSP. Он описывает поведение «soft-fail» (мягкий отказ), реализованное в большинстве браузеров: политику, при которой неудачная попытка связаться с OCSP-респондером не приводит к провалу проверки отзыва. Из-за этого злоумышленник может заставить клиента обойти проверку отзыва — перехватив или заблокировав OCSP-запрос клиента либо проведя атаку типа «отказ в обслуживании» на сам респондер.

Сам по себе OCSP stapling не устраняет эту проблему полностью, но избавляет от необходимости проверок OCSP между клиентом и респондером. Сервер по-прежнему должен иметь возможность получить собственный OCSP-ответ и передать его внутри канала (in-band) в рамках рукопожатия TLS.

Сейчас в IETF в виде черновика находится предложение о расширении сертификата «must-staple», которое требовало бы прикладывать OCSP-ответ во время рукопожатия TLS. По сути, это отменяло бы любое поведение soft-fail, которое может применять клиент. Это предлагаемое расширение выходит за рамки данного JEP, но если оно перестанет быть черновиком, то в будущем может стать полезным дополнением.

Наконец, Java-клиентам не обязательно нужны те же значения soft-fail по умолчанию, что и браузерам. В некоторых случаях клиенты могут предпочесть подход hard-fail (жёсткий отказ) или получать отклик пользователя через диалоговое окно, если OCSP-ответ получить не удалось. Например, подход soft-fail по умолчанию и в Java Plugin, и в Java Web Start состоит в показе диалогового окна с предупреждением при загрузке подписанных апплетов.

Возможное нарушение конфиденциальности при OCSP-запросах

В обычных сценариях OCSP клиент, отправляя OCSP-запрос, раскрывает OCSP-респондеру и сервер (через запись о сертификате сервера), и себя (как минимум через IP-адрес) и, следовательно, может раскрыть поведение клиента. OCSP stapling решает эту проблему, поскольку клиент больше не отправляет запрос OCSP-респондеру.

Ограничения техники «captive portal»

Техника «captive portal» заставляет HTTP-клиента в сети загрузить специальную веб-страницу, обычно для аутентификации, прежде чем он сможет нормально пользоваться сетью. В таких средах клиенты не могут проверить OCSP-статус сертификата SSL/TLS, поскольку весь сетевой доступ заблокирован до успешной аутентификации.

Итоги

Перечисленные проблемы можно частично смягчить с помощью CRL или лучше решить с помощью OCSP stapling.

Итак, OCSP stapling может помочь повысить производительность TLS, устраняя узкое место в виде OCSP-респондера. Он также может предотвратить возможное нарушение конфиденциальности при OCSP-запросе и обойти ограничение техники «captive portal».

Описание

Эта возможность будет реализована в провайдере SunJSSE. Запланированы небольшие изменения API, и цель — свести эти изменения к минимуму. Реализация выберет разумные значения по умолчанию для параметров, специфичных для OCSP, и позволит настраивать эти значения через следующие системные свойства:

  • jdk.tls.client.enableStatusRequestExtension: по умолчанию это свойство равно true. Оно включает расширения status_request и status_request_v2, а также обработку сообщений CertificateStatus, отправляемых сервером.
  • jdk.tls.server.enableStatusRequestExtension: по умолчанию это свойство равно false. Оно включает поддержку OCSP stapling на стороне сервера.
  • jdk.tls.stapling.responseTimeout: это свойство задаёт максимальное время, которое сервер потратит на получение OCSP-ответов — из кэша или обращаясь к OCSP-респондеру. Полученные ответы будут отправлены в сообщении CertificateStatus, если это применимо с учётом используемого типа stapling. Свойство принимает целое значение в миллисекундах, значение по умолчанию — 5000.
  • jdk.tls.stapling.cacheSize: это свойство задаёт максимальный размер кэша в записях. Значение по умолчанию — 256 объектов. Если кэш заполнен и нужно закэшировать новый ответ, запись кэша, которая дольше всех не использовалась, будет заменена новой. Значение ноль или меньше означает, что количество ответов, которые может содержать кэш, не ограничено сверху.
  • jdk.tls.stapling.cacheLifetime: это свойство задаёт максимальное время жизни закэшированного ответа. Значение указывается в секундах, по умолчанию — 3600 (1 час). Время жизни ответа может оказаться короче значения этого свойства, если в ответе есть поле nextUpdate, срок которого истекает раньше срока жизни в кэше. Значение ноль или меньше отключает ограничение времени жизни в кэше. Если у объекта нет nextUpdate, а время жизни в кэше отключено, ответ не будет кэшироваться.
  • jdk.tls.stapling.responderURI: это свойство позволяет администратору задать URI по умолчанию на случай, если у сертификатов, используемых для TLS, нет расширения Authority Info Access. Оно не переопределяет значение расширения AIA, если не задано свойство jdk.tls.stapling.responderOverride (см. ниже). По умолчанию это свойство не задано.
  • jdk.tls.stapling.responderOverride: это свойство позволяет URI, заданному через свойство jdk.tls.stapling.responderURI, переопределять любое значение расширения AIA. По умолчанию оно равно false.
  • jdk.tls.stapling.ignoreExtensions: это свойство отключает пересылку расширений OCSP, указанных в TLS-расширениях status_request или status_request_v2. По умолчанию оно равно false.

Реализации Java на стороне клиента и сервера смогут поддерживать hello-расширения TLS status_request и status_request_v2. Расширение status_request описано в RFC 6066. Поддерживающие его серверы будут включать один OCSP-ответ для сертификата, идентифицирующего сервер, в новое сообщение рукопожатия TLS (CertificateStatus). Расширение status_request_v2 описано в RFC 6961. Оно позволяет клиенту запросить у сервера один OCSP-ответ в сообщении CertificateStatus (аналогично status_request) или попросить сервер получить OCSP-ответ для каждого сертификата из списка сертификатов в сообщении Certificate (далее — тип ocsp_multi).

Клиентская сторона

  • OCSP stapling будет включён по умолчанию, и его можно отключить с помощью системного свойства. Это делается через свойство jdk.tls.client.enableStatusRequestExtension.

  • По умолчанию клиенты будут указывать в сообщении рукопожатия ClientHello оба расширения — status_request и status_request_v2. Для расширения status_request_v2 будут указываться оба типа — ocsp и ocsp_multi.

  • Для создания hello-расширений потребуется создать новые классы в sun.security.ssl — по аналогии с тем, как были реализованы ServerNameIndicator, RenegotiationInfoExtension и другие расширения.

  • Чтобы использовать новые расширения, в классе ClientHello будут определены дополнительные методы, добавляющие эти расширения. Эти методы будут вызываться из ClientHandshaker.clientHello().

  • Потребуется создать новый класс сообщения рукопожатия в классе HandshakeMessage для кодирования и разбора сообщения CertificateStatus.

  • Необходимо изменение публичного API в ExtendedSSLSession, позволяющее вызывающему коду получать OCSP-ответы, полученные в процессе рукопожатия. Новый метод:

    public List<byte[]> getStatusResponses();

Серверная сторона

  • В реализации на стороне сервера OCSP stapling по умолчанию будет отключён, но его можно включить с помощью системного свойства jdk.tls.server.enableStatusRequestExtension. Серверы с отключённой поддержкой OCSP stapling будут игнорировать расширения status_request и status_request_v2.

  • Заполнение сервером информации status_request или status_request_v2 в сообщении ServerHello будет зависеть от того, как клиент указал эти расширения. Как правило, то же расширение запроса, что было в ClientHello, будет возвращено в ServerHello, за следующими исключениями:

    • Серверы, получившие в ClientHello оба расширения — status_request и status_request_v2, — будут указывать status_request_v2 в ServerHello.

    • Серверы, получившие в ClientHello расширения status_request_v2 с обоими типами ocsp и ocsp_multi, будут указывать status_request_v2 в сообщении ServerHello и ocsp_multi в сообщении CertificateStatus.

    • Если выбран status_request_v2/ocsp_multi, для получения каждого ответа будут использоваться разные потоки. Этим будет управлять StatusResponseManager, который отвечает и за получение, и за кэширование OCSP-ответов.

  • OCSP-ответы следует кэшировать везде, где это возможно. Клиенты, не указывающие nonce в своём расширении status_request[_v2], могут получить закэшированный ответ.

    • Закэшированные ответы не следует использовать, если текущее время позже значения поля nextUpdate.

    • Закэшированные ответы без поля nextUpdate могут храниться в кэше в течение заранее заданного времени жизни (см. «Настраиваемые параметры» ниже).

    • Серверы, получившие status_requests с расширением nonce, не должны возвращать закэшированные ответы в сообщении CertificateStatus.

  • Поддержку stapling на стороне сервера можно будет настраивать через описанные выше системные свойства.

  • StatusResponseManager создаётся при создании экземпляра SSLContext. Значения свойств считываются при конструировании SSLContext. Эти значения можно изменить, и когда будет создан новый объект SSLContext, StatusResponseManager получит новые значения.

Stapling и X509ExtendedTrustManagers

У разработчиков есть определённая свобода в том, как обрабатывать ответы, полученные через OCSP stapling. Этот JEP не меняет существующие методики проверки пути сертификации и проверки отзыва. Это значит, что и клиент, и сервер могут указывать расширения status_request, получать OCSP-ответы через сообщение CertificateStatus и оставлять пользователю свободу в том, как реагировать на информацию об отзыве или на её отсутствие.

Как и в предыдущих выпусках JDK, если вызывающий код не передаёт PKIXBuilderParameters, проверка отзыва отключена. Если вызывающий код создаёт PKIXBuilderParameters и включает проверку отзыва методом setRevocationEnabled, то OCSP-ответы, полученные через stapling, будут проверяться. То же самое происходит, если свойство com.sun.net.ssl.checkRevocation имеет значение true. В таблице ниже приведены примеры нескольких подходов (предполагается, что OCSP stapling включён и на клиенте, и на сервере):

PKIXBuilderParameters Свойство checkRevocation PKIXRevocationChecker Результат
по умолчанию по умолчанию по умолчанию Проверка отзыва отключена
по умолчанию true по умолчанию Проверка отзыва включена*, установлен SOFT_FAIL
создан экземпляр по умолчанию по умолчанию Проверка отзыва включена*, установлен SOFT_FAIL
создан экземпляр по умолчанию создан экземпляр, добавлен в PKIXBuilderParameters Проверка отзыва включена*, режим hard fail (жёсткий отказ).

* Клиент выполнит собственный OCSP-запрос в качестве запасного варианта, только если свойство безопасности ocsp.enable установлено в true

Подробнее о настройке объектов PKIXBuilderParameters и PKIXRevocationChecker и об их связи с JSSE можно узнать в Java PKI API Programmer's Guide и в JSSE Reference Guide.

Тестирование

  1. Реализация OCSP Stapling не должна нарушать обратную совместимость.

  2. Клиентская реализация должна уметь отправлять серверам, которые их поддерживают, расширения status_request ClientHello в стиле RFC 6066. Она должна правильно разбирать то же hello-расширение в сообщении рукопожатия ServerHello и правильно разбирать содержимое последующего сообщения рукопожатия CertificateStatus.

  3. Клиентская реализация должна уметь отправлять серверам, которые их поддерживают, расширения status_request_v2 ClientHello в стиле RFC 6961. Она должна уметь указывать в hello-расширении типы ocsp или ocsp_multi (или оба). Она должна правильно разбирать те же hello-расширения в сообщении рукопожатия ServerHello и правильно разбирать содержимое последующего сообщения рукопожатия CertificateStatus.

  4. Серверная реализация должна уметь принимать расширения status_request и status_request_v2 в сообщении рукопожатия ClientHello и запрашивать соответствующий OCSP-респондер. Она должна уметь помещать OCSP-ответы в сообщение рукопожатия TLS CertificateStatus, которое возвращается клиенту.

  5. Серверная реализация должна уметь кэшировать действительные OCSP-ответы для повторного использования с клиентами, которые не передают расширения nonce в своих hello-расширениях status_request[_v2].

  6. Клиент должен взаимодействовать как минимум с двумя разными веб-серверами, поддерживающими OCSP stapling (например, Apache 2.4+).

  7. Сервер должен взаимодействовать как минимум с двумя разными клиентскими реализациями, способными указывать status_request или status_request_v2. В настоящее время большинство основных браузеров (Firefox, Chrome и др.) умеют формировать hello-расширение status_request, как и другие инструменты, например s_client из OpenSSL. Для автоматического тестирования можно создать небольшие приложения, которые компонуются с библиотеками NSS и OpenSSL и устанавливают TLS-соединения с OCSP stapling.

Риски и допущения

В этой реализации OCSP stapling будет по умолчанию включён для клиентов Java в JDK. Однако возможны проблемы совместимости с TLS-серверами, которые не принимают расширения TLS status_request или status_request_v2. Чтобы при необходимости отключить OCSP stapling, определено системное свойство или свойство безопасности.