#ruby #openssl
#ruby #openssl
Вопрос:
Из-за неправильного решения со стороны OpenSSL, которое повлияло на привязки Ruby, единственный способ проверить, подписан ли запрос OCSP, — это проанализировать предупреждение из OpenSSL::OCSP::Request#verify
. Я перехватываю $stderr
и читаю предупреждение, но если я повторяю этот процесс в нескольких модульных тестах, первое сообщение об ошибке фиксируется каждый раз, даже если при каждом перехвате используется новый буфер.
В качестве примера я создал этот скрипт: test.rb
#!/usr/bin/env ruby
require 'openssl'
require 'stringio'
def main
if ARGV[0]
puts "signed: n#{signed}"
puts "unsigned: n#{unsigned}"
else
puts "unsigned: n#{unsigned}"
puts "signed: n#{signed}"
end
end
def unsigned
cert = OpenSSL::X509::Certificate.new
certid = OpenSSL::OCSP::CertificateId.new cert, cert
request = OpenSSL::OCSP::Request.new.add_certid certid
store = OpenSSL::X509::Store.new
capture_stderr { request.verify([], store) }
end
def signed
key = OpenSSL::PKey::RSA.generate(2048)
cert = OpenSSL::X509::Certificate.new
cert.public_key = key.public_key
cert.sign(key, OpenSSL::Digest::SHA1.new)
certid = OpenSSL::OCSP::CertificateId.new OpenSSL::X509::Certificate.new, cert
store = OpenSSL::X509::Store.new
store.add_cert cert
request = OpenSSL::OCSP::Request.new.add_certid certid
request.sign(cert, key)
capture_stderr { request.verify([], store) }
end
def capture_stderr
$stderr = StringIO.new
result = yield
[result, $stderr.string]
ensure
$stderr = STDERR
end
# try `./test.rb` and `./test.rb 1`
main
Изменяя порядок вызовов функций, я получаю разные результаты.
$ ./test.rb
unsigned:
[false, "./test.rb:22: warning: error:27074080:OCSP routines:OCSP_request_verify:request not signedn"]
signed:
[false, "./test.rb:38: warning: error:27074080:OCSP routines:OCSP_request_verify:request not signedn"]
и
$ ./test.rb 1
signed:
[false, "./test.rb:38: warning: error:27074065:OCSP routines:OCSP_request_verify:certificate verify errorn"]
unsigned:
[false, "./test.rb:22: warning: error:27074065:OCSP routines:OCSP_request_verify:certificate verify errorn"]
Я полагаю, что объяснение этого странного поведения, вероятно, относится к языковой части C кодовой базы Ruby stdlib.
Комментарии:
1. «… единственный способ проверить, подписан ли запрос OCSP, — это проанализировать предупреждение из OpenSSL ::OCSP::Request#verify» — Простите мое невежество… Вы можете найти источник для механизма OCSP в
<openssl src>/apps/ocsp.c
. Вы можете извлекать / повторно использовать любой код, который хотите, из библиотеки. Проблема, похоже, в Ruby и его неспособности предоставить то, что вам нужно. OpenSSL не предоставляет привязок; они предоставляются Python, Ruby, PHP и т. Д. Возможно, вам следует отправить отчет об ошибке в Ruby, чтобы получить то, что вам нужно.2. Хм … раньше туда не заглядывал. Но там нет использования
OCSP_request_verify
. Проверяется только ответ. Так что, если это даже недоступно в части приложения, я думаю, это довольно сильное сообщение о том, что авторы OpenSSL не считают целесообразным проверять, откуда поступают запросы. Возможно, мне нужно переосмыслить, почему я это делаю (и почему OCSP RFC даже определяет статус SigRequired).3. Если предупреждение или сообщение об ошибке поступает из OpenSSL, код может быть удален. OpenSSL предоставляет такие функции, как
OCSP_verify
,OCSP_BASICRESP_verify
иOCSP_REQUEST_verify
. Возможно, Ruby нужно его раскрыть. Не верьте мне на слово…cd <openssl src>
а затем выполнитьgrep -IR 'OCSP_*.*verify' *
.
Ответ №1:
Оказалось, что это ошибка в библиотеке OpenSSL Ruby. Это было исправлено в версии Gem 2.0.0-beta2: https://github.com/ruby/openssl/commit/9af69abcec15b114d9a0ec3811983fc1d7b5a1dc
Теперь сообщения OpenSSL не передаются повторно в stderr. Однако теперь невозможно отличить ненадежные подписи от отсутствующих подписей. К счастью, я ошибался раньше, и проверка действительно завершается ошибкой из-за отсутствия подписей.