модуль 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
Для создания запроса нам необходимо создать идентификатор сертификата для сертификата субъекта, чтобы CA знал, о каком сертификате мы спрашиваем:
digest = OpenSSL::Digest.new('SHA1')
certificate_id =
OpenSSL::OCSP::CertificateId.new subject, issuer, digest
Затем создайте запрос и добавьте в него идентификатор сертификата:
request = OpenSSL::OCSP::Request.new request.add_certid certificate_id
Добавление nonce в запрос защищает от повторных атак, но не все CA обрабатывают nonce.
request.add_nonce
Для отправки запроса CA для проверки нам необходимо извлечь 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.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
Далее нам нужна информация о деталях ответа, чтобы определить, соответствует ли ответ нашему запросу. Сначала мы проверим nonce. Опять же, не все CA поддерживают nonce. См. 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 certificiate' 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
-
(Этот флаг не используется
OpenSSL1.0.1g) - NOCERTS
-
Не включать сертификаты в ответ
- NOCHAIN
-
Не проверять цепочку сертификатов в ответе
- NOCHECKS
-
Не выполнять дополнительные проверки сертификатов подписи
- NODELEGATED
-
(Этот флаг не используется
OpenSSL1.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
-
Сертификат этой CA был отозван из-за компрометации ключа
- 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–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.