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
-
(Этот флаг не используется в
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
-
Сертификат этого центра сертификации был отозван из-за компрометации ключа
- 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.