Spec-Zone.ru › Ruby 2.2

модуль OpenSSL::OCSP

OpenSSL::OCSP реализует запросы и ответы протокола Online Certificate Status Protocol.

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

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

Для создания запроса нам нужно создать идентификатор сертификата субъекта, чтобы ЦС знал, о каком сертификате мы спрашиваем:

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

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

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

Добавление nonce в запрос защищает от атак повторного воспроизведения, но не все ЦС обрабатывают nonce.

request.add_nonce

Для отправки запроса ЦС на проверку нам нужно извлечь OCSP URI из сертификата субъекта:

authority_info_access = subject.extensions.find do |extension|
  extension.oid == 'authorityInfoAccess'
end

descriptions = authority_info_access.value.split "\n"
ocsp = descriptions.find do |description|
  description.start_with? 'OCSP'
end

require 'uri'

ocsp_uri = URI ocsp[/URI:(.*)/, 1]

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

require 'net/http'

http_response =
  Net::HTTP.start ocsp_uri.hostname, ocsp.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.verify [], store then
  raise 'response is not signed by a trusted certificate'
end

Ответ содержит информацию о статусе (успех/неудача). Мы можем отобразить статус как строку:

puts response.status_string #=> successful

Далее нам нужна информация о деталях ответа, чтобы определить, соответствует ли ответ нашему запросу. Сначала проверим nonce. Опять же, не все ЦС поддерживают nonce. См. OpenSSL::OCSP::Request#check_nonce для значений возвращаемых значений.

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

Затем извлеките информацию о статусе из основного ответа. (В запросе можно проверить несколько сертификатов, но в этом примере был представлен только один.)

response_certificate_id, status, reason, revocation_time,
  this_update, next_update, extensions = basic_response.status

Затем проверим различные поля.

unless response_certificate_id == certificate_id then
  raise 'certificate id mismatch'
end

now = Time.now

if this_update > now then
  raise 'update date is in the future'
end

if now > next_update then
  raise 'next update time has passed'
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

Сертификат ранее был приостановлен и теперь должен быть удален из CRL

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–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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