Не могу подписать с DSA
Ключ DSA создается с помощью:
openssl genpkey -genparam -algorithm DSA -out dsaparams.pem -pkeyopt dsa_paramgen_bits:1024
openssl genpkey -paramfile dsaparams.pem -out dsakey.pem
Когда я пытаюсь подписать, эта ошибка отображается:
echo 'bacon' > text
openssl pkeyutl -sign -in text -inkey dsakey.pem -out sig
Public Key operation error
Можно подписать с openssl dgst -sign
но не с командами выше.
Почему это происходит? man openssl-pkeyutl
говорит, что DSA позволяет подпись и проверку. Я использую OpenSSL 1.1.0g
1 ответ
TLDR: кажется openssl pkeyutl
предназначен для подписи хеша, но передается меньший файл, где ожидается хеш; и некоторая проверка, присутствующая в OpenSSL 1.1.0g (но не OpenSSL 1.0.2g), улавливает эту ошибку.
FWIW, не было никакой ошибки, когда я попробовал команды вопроса с OpenSSL 1.0.2g. Но я вижу 3 причины, по которым он может потерпеть неудачу (и, во-первых, должен):
openssl pkeyutl
задокументировано, что не выполняет хеш, который, как ожидается, будет выполнен внешне. Так что я думаю, что более новые версииopenssl pkeyutl
Корахорошо проваливается, когда входной файл короче, чем параметр q закрытого ключа, потому что это единственное, что нужно сделать. Это по крайней мере согласуется с man-страницей:В случае подписей RSA, ECDSA и DSA эта утилита не будет выполнять хеширование входных данных, а будет использовать данные непосредственно в качестве ввода алгоритма подписи. В зависимости от типа ключа, типа подписи и режима заполнения максимальные допустимые длины входных данных различаются. В общем случае с RSA подписанные данные не могут быть длиннее ключевого модуля, в случае ECDSA и DSA данные не должны быть длиннее размера поля, в противном случае они будут незаметно усечены до размера поля.
Другими словами, если значение дайджеста равно sha1, входное значение должно быть длиной 20 байтов для двоичного кодирования вывода хеш-функции SHA-1.
В наши дни 1024-битный DSA по праву считается устаревшим, а в некоторых местах (включая некоторые реализации SSH) его поддержка была удалена.
- В наши дни SHA-1 по праву считается устаревшей.
Я бы предложил по крайней мере 2048-битный DSA, SHA-256 и хэширование файла перед вычислением подписи, что лучше всего сделать с openssl dgst
который может хэш-то-подписать, когда openssl pkeyutl
не могу. Я не гуру openssl, но я бы попробовал исследовать следующее:
# generate a private key and extract the public key
openssl genpkey -paramfile dsaparams.pem -out dsaprivkey.pem
openssl dsa -in dsaprivkey.pem -pubout > dsapubkey.pem
# create a file "myfile" to be signed
echo 'The Magic Words are Squeamish Ossifrage' > myfile
# create signature "myfile.sig"
openssl dgst -sha256 -sign dsaprivkey.pem myfile > myfile.sig
# verify "myfile" against signature "myfile.sig" and public key
openssl dgst -sha256 -verify dsapubkey.pem -signature myfile.sig myfile
Примечание. В предыдущей попытке openssl 1.0.2g генерировал подписи с 160-битным q (возможно, с использованием SHA-1). За комментарий я добавил -sha256
в openssl dgst
, но это не имело значения. Эксперименты показывают, что необходимо использовать -pkeyopt dsa_paramgen_q_bits:256
хотя man-страница явно заявляет -pkeyopt dsa_paramgen_md:sha256
заботится об этом:
dsa_paramgen_md:digest
Дайджест для использования при генерации параметров. Должен быть одним изsha1
,sha224
или жеsha256
, Если установлено, то число битов в q будет соответствовать выходному размеру указанного дайджеста иdsa_paramgen_q_bits
параметр будет игнорироваться (..)