Spec-Zone.ru › Ruby 4.0
  1. OpenSSL::
  2. OCSP

module OpenSSL::OCSP

OpenSSL::OCSP реализует запросы и ответы протокола проверки статуса сертификатов в реальном времени.

Для создания и отправки запроса OCSP требуется сертификат субъекта, содержащий URL OCSP в расширении authorityInfoAccess, а также сертификат издателя сертификата субъекта. Сначала загрузим сертификаты издателя и субъекта:

subject = OpenSSL::X509::Certificate.new subject_pem
issuer  = OpenSSL::X509::Certificate.new issuer_pem

Чтобы создать запрос, необходимо создать идентификатор сертификата для сертификата субъекта, чтобы центр сертификации знал, о каком сертификате идёт речь:

digest = OpenSSL::Digest.new('SHA1')
certificate_id =
  OpenSSL::OCSP::CertificateId.new subject, issuer, digest

Затем создадим запрос и добавим в него идентификатор сертификата:

request = OpenSSL::OCSP::Request.new
request.add_certid certificate_id

Добавление одноразового значения в запрос защищает от атак повторного воспроизведения, однако не все центры сертификации обрабатывают одноразовые значения.

request.add_nonce

Чтобы отправить запрос в центр сертификации для проверки, необходимо извлечь OCSP URI из сертификата субъекта:

ocsp_uris = subject.ocsp_uris

require 'uri'

ocsp_uri = URI ocsp_uris[0]

Для отправки запроса мы передадим его методом POST на OCSP URI (согласно RFC 2560). Обратите внимание: в этом примере обрабатываются только HTTP-запросы и не обрабатываются перенаправления, поэтому такой подход не подходит для серьёзного использования.

require 'net/http'

http_response =
  Net::HTTP.start ocsp_uri.hostname, ocsp_uri.port do |http|
    http.post ocsp_uri.path, request.to_der,
              'content-type' => 'application/ocsp-request'
end

response = OpenSSL::OCSP::Response.new http_response.body
response_basic = response.basic

Сначала проверим, имеет ли ответ действительную подпись. Без действительной подписи мы не можем ему доверять. Если проверка не пройдёт, возможно, в системе отсутствует хранилище сертификатов или промежуточные сертификаты.

store = OpenSSL::X509::Store.new
store.set_default_paths

unless response_basic.verify [], store then
  raise 'response is not signed by a trusted certificate'
end

Ответ содержит информацию о статусе (успешно/ошибка). Статус можно вывести в виде строки:

puts response.status_string #=> successful

Далее необходимо узнать подробности ответа, чтобы определить, соответствует ли он нашему запросу. Сначала проверим одноразовое значение. И снова: не все центры сертификации поддерживают одноразовые значения. Значения, возвращаемые методом Request#check_nonce, описаны в документации.

p request.check_nonce basic_response #=> value from -1 to 3

Затем извлечём из базового ответа информацию о статусе сертификата.

single_response = basic_response.find_response(certificate_id)

unless single_response
  raise 'basic_response does not have the status for the certificate'
end

Затем проверим срок действия. Статус, выданный в будущем, необходимо отклонить.

unless single_response.check_validity
  raise 'this_update is in the future or next_update time has passed'
end

case single_response.cert_status
when OpenSSL::OCSP::V_CERTSTATUS_GOOD
  puts 'certificate is still valid'
when OpenSSL::OCSP::V_CERTSTATUS_REVOKED
  puts "certificate has been revoked at #{single_response.revocation_time}"
when OpenSSL::OCSP::V_CERTSTATUS_UNKNOWN
  puts 'responder doesn't know about the certificate'
end

Константы

NOCASIGN

(Этот флаг не используется в OpenSSL 1.0.1g)

NOCERTS

Не включать сертификаты в ответ

NOCHAIN

Не проверять цепочку сертификатов в ответе

NOCHECKS

Не выполнять дополнительные проверки сертификата подписи

NODELEGATED

(Этот флаг не используется в OpenSSL 1.0.1g)

NOEXPLICIT

Не проверять доверие

NOINTERN

Не искать сертификат подписанта среди сертификатов, содержащихся в ответе

NOSIGS

Не проверять подпись ответа

NOTIME

Не включать время producedAt в ответ

NOVERIFY

Не проверять ответ вообще

RESPID_KEY

Идентифицировать ответ по идентификатору ключа сертификата подписи

RESPONSE_STATUS_INTERNALERROR

Внутренняя ошибка издателя

RESPONSE_STATUS_MALFORMEDREQUEST

Некорректный запрос подтверждения

RESPONSE_STATUS_SIGREQUIRED

Необходимо подписать запрос и отправить его повторно

RESPONSE_STATUS_SUCCESSFUL

Response содержит действительные подтверждения

RESPONSE_STATUS_TRYLATER

Повторите попытку позже

RESPONSE_STATUS_UNAUTHORIZED

Ваш запрос не авторизован.

REVOKED_STATUS_AFFILIATIONCHANGED

Имя субъекта сертификата или другая информация о нём изменились

REVOKED_STATUS_CACOMPROMISE

Сертификат этого центра сертификации был отозван из-за компрометации ключа

REVOKED_STATUS_CERTIFICATEHOLD

Действие сертификата приостановлено

REVOKED_STATUS_CESSATIONOFOPERATION

Сертификат больше не требуется

REVOKED_STATUS_KEYCOMPROMISE

Сертификат был отозван из-за компрометации ключа

REVOKED_STATUS_NOSTATUS

Сертификат был отозван по неизвестной причине

REVOKED_STATUS_REMOVEFROMCRL

Действие сертификата ранее было приостановлено, и теперь его следует удалить из списка отозванных сертификатов

REVOKED_STATUS_SUPERSEDED

Сертификат был заменён новым сертификатом

REVOKED_STATUS_UNSPECIFIED

Сертификат был отозван по неуказанной причине

TRUSTOTHER

Не проверять дополнительные сертификаты

V_CERTSTATUS_GOOD

Указывает, что сертификат не отозван, но не обязательно означает, что сертификат был выдан или что этот ответ получен в течение срока действия сертификата

V_CERTSTATUS_REVOKED

Указывает, что сертификат был отозван — окончательно или временно (его действие приостановлено).

V_CERTSTATUS_UNKNOWN

Указывает, что ответчик не знает о запрашиваемом сертификате.

V_RESPID_KEY

Идентификатор ответчика основан на открытом ключе.

V_RESPID_NAME

Идентификатор ответчика основан на имени ключа.

Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API