Проверка цифровой подписи с OpenSSL

Как я могу проверить использование сообщений № 7 CMS/PKCS OpenSSL в Ruby?
Сообщение PKCS № 7 используется в качестве цифровой подписи для пользовательских сообщений, таким образом, я должен подписаться, новый пользователь передают и проверяют входящего. Я ничто не нашел полезным в документации и Google. Я нашел немного примеров кода для подписания, но ничто для проверки:

signed = OpenSSL::PKCS7::sign(crt, key, data, [], OpenSSL::PKCS7::DETACHED)

12
задан andrykonchin 4 January 2010 в 11:56
поделиться

1 ответ

Короткий ответ

Если предположить, что все определено так, как было в вашем фрагменте, с отщепленной подписью, без цепочки сертификатов к доверенному корню, сертификатом crt, подписью signed и данными data, то вы должны сделать то, что вам нужно:

store = OpenSSL::X509::Store.new
p7 = OpenSSL::PKCS7.new(signed.to_der)
verified = p7.verify([crt], store, data, 
                     OpenSSL::PKCS7::DETACHED || OpenSSL::PKCS7::NOVERIFY)

(Я не тестировал это, YMMV)

Полная история

Вот полная история того, как я нашел это, со ссылками на все источники, которые я использовал, так что если вам нужна дополнительная информация, вам нужно куда-то пойти и посмотреть.

Взглянув на документацию OpenSSL::PKCS7, мы находим эту мудрость:

PKCS7.new => pkcs7
PKCS7.new(string) => pkcs7
Многие методы в этом классе не документированы.

И быстрый Гугл тоже ничего не обнаруживает. Это говорит о том, что нам придется принять более экстремальные меры. Давайте сделаем Поиск кода Google для каждого, кто использует OpenSSL::PKCS7 для проверки подписи.

Хмм. Найдем некоторые тестовые случаи . Это хорошо, по крайней мере, в нем есть юнит-тесты, которые могут помочь показать, что функциональность действительно работает, и показать, как она работает.

store = OpenSSL::X509::Store.new
store.add_cert(@ca_cert)
ca_certs = [@ca_cert]

data = "aaaaa\r\nbbbbb\r\nccccc\r\n"
tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs)
p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der)
certs = p7.certificates
signers = p7.signers
assert(p7.verify([], store))
assert_equal(data, p7.data)

Это не так уж плохо. Оцените магазин сертификатов. Подпишите данные, затем создайте новый объект OpenSSL::PKCS7 из подписанных данных. Затем вы можете вызвать сертификаты на нем для извлечения цепочки сертификатов, которой он был подписан, подписчики для извлечения подписчиков, и верификация может быть вызвана для проверки того, что подпись действительна. Похоже, что в качестве второго аргумента для проверки вы передаете хранилище сертификатов, содержащее ваши доверенные сертификаты CA. И вы можете извлечь данные, обратившись к данным по этому аргументу.

Но что означает первый аргумент? В наших тестовых случаях никто, кажется, не передаёт ничего, кроме пустого списка для первого аргумента. Хм. Загадка. Вернемся к этому.

Третий, необязательный, аргумент для verify выглядит так, как будто он используется для верификации отделенной сигнатуры:

data = "aaaaa\nbbbbb\nccccc\n"
flag = OpenSSL::PKCS7::BINARY|OpenSSL::PKCS7::DETACHED
tmp = OpenSSL::PKCS7.sign(@ee1_cert, @rsa1024, data, ca_certs, flag)
p7 = OpenSSL::PKCS7::PKCS7.new(tmp.to_der)
a1 = OpenSSL::ASN1.decode(p7)

certs = p7.certificates
signers = p7.signers
assert(!p7.verify([], store))
assert(p7.verify([], store, data))

Вернемся к первому аргументу. Мы нашли больше, чем просто тестовые случаи, когда мы выполняли поиск кода; мы также нашли несколько других применений. На самом деле, второй кажется использует первый аргумент :

# 'true' if signature was created using given cert, 'false' otherwise
def match?(cert)
  @p7.verify([cert.raw_cert], @store, nil, OpenSSL::PKCS7::NOVERIFY)
end

Ah, OK. Это список сертификатов для проверки. И теперь есть четвертый параметр, который, кажется, состоит из флагов. Проверяяя OpenSSL docs, мы видим, что это неинтуитивное имя (проверить с помощью флага NOVERIFY?) означает, что вы должны проверять подпись только на предмет переданных сертификатов и сертификатов, встроенных в подпись, а не пытаться проверить всю цепочку сертификатов на предмет доверенного хранилища CA.

Это вся полезная информация, но есть ли что-нибудь, что мы упускаем? К счастью, Ruby - программное обеспечение с открытым исходным кодом, поэтому мы можем "Использовать исходный код, Люк!". После того, как мы немного подшутили над поиском кода Google, мы находим определение ossl_pkcs7_verify. Как только вы пройдете через несколько загадочные имена, код достаточно прост для чтения; в основном это просто преобразование его аргументов в формат, который OpenSSL может понять, и вызов:

ok = PKCS7_verify(p7, x509s, x509st, in, out, flg);

Так что, похоже, что что'это то, где мы действительно хотим искать документацию.

ОПИСАНИЕ

PKCS7_verify() верифицирует структуру PKCS#7 signedData. p7 является структурой PKCS7 для проверки. certs - это набор сертификатов для поиска сертификата подписанта. store - это доверенное хранилище сертификатов (используется для проверки цепочки). indata - это подписанные данные, если содержание отсутствует в p7 (т.е. оно отделено). Содержимое записывается в из . если это не NULL.

флаги являются дополнительным набором флагов, который может быть использован для модификации верификации операция.

PKCS7_get0_signers() извлекает сертификаты подписчика из p7, он делает следующее , а не , проверяют их действительность или действительность каких-либо подписей. Подписи certs и параметры flags имеют те же значения, что и в PKCS7_verify().

Смотрите страницу full man page для более подробной информации.

О, и в качестве примечания, я нашел это предупреждение во время поиска; оно выглядит как на Ruby 1.9, и, возможно, в некоторых более поздних версиях Ruby 1. 8, класс был перемещен из избыточного OpenSSL::PKCS7::PKCS7 в OpenSSL::PKCS7.

warn("Warning: OpenSSL::PKCS7::PKCS7 is deprecated after Ruby 1.9; use OpenSSL::PKCS7 instead")
40
ответ дан 2 December 2019 в 03:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: