Сообщение об ошибке
Verification failure
Формулировка OpenSSL 3.x. OpenSSL 1.1.x пишет её с заглавных букв: «Verification Failure». openssl pkeyutl -verify выводит родственное сообщение «Signature Verification Failure». В OpenSSL 3.x оба сопровождаются строкой стека ошибок вроде «error:030000EA:digital envelope routines:EVP_DigestVerifyFinal:provider signature failure» (воспроизведено на 3.6). Подпись, которая вообще не в DER, до этого этапа не доходит: её проверка завершается сообщением «Error verifying data».
Что это означает
Команда openssl dgst -verify вычислила дайджест ваших данных, проверила подпись по открытому ключу, и математика ответила «нет». Ключ, данные и подпись прочитались без ошибок — просто одно из трёх не подходит к двум другим. Для сравнения: при успешной проверке выводится «Verified OK».
Почему это происходит
Данные отличаются от тех, что были подписаны
частоПеревод строки в конце, добавленный редактором, преобразование между CRLF и LF в git или повторное хеширование уже готового дайджеста (dgst хеширует входные данные: если передать ему дайджест SHA-256, подписан будет хеш от хеша).
Не совпадает алгоритм дайджеста
частоПодпись создана с -sha256, а проверяется с -sha384 (или библиотека подписанта по умолчанию взяла другую хеш-функцию). Дайджест входит в подписанные данные: обе стороны должны использовать одну и ту же хеш-функцию.
Не тот открытый ключ
иногдаКлюч, заменённый при ротации, ключ другого сервиса или открытый ключ, полученный не из того закрытого ключа, которым создана подпись.
Как исправить
- 1.
Сначала исключите проблему с кодировкой подписи
dgst -verify читает подписи ECDSA только в формате ASN.1 DER. Подпись raw r‖s из WebCrypto, JWS или API Go и Python в режиме raw (ровно 64 байта для P-256 и 96 — для P-384) отсеивается раньше, с сообщением «Error verifying data». Если ваша подпись в DER и всё равно не проходит на этом шаге, неверны данные, дайджест или ключ. Инструмент DER ⇄ raw ниже преобразует подпись из одной формы в другую и отмечает неканонические значения high-S, которые строгая проверка отвергает.
- 2.
Проверьте заранее вычисленный дайджест с помощью pkeyutl
Если у вас есть дайджест, а не само сообщение, dgst — неподходящий инструмент (он захеширует данные ещё раз). pkeyutl проверяет подпись по дайджесту как есть.
bash openssl dgst -sha256 -binary message.bin > msg.hash openssl pkeyutl -verify -pubin -inkey pub.pem \ -sigfile sig.der -in msg.hash -pkeyopt digest:sha256 - 3.
Исключите расхождение данных
Посчитайте дайджест именно тех байтов, которые есть на каждой стороне, и сравните: любое расхождение означает, что изменилось сообщение, а не криптография.
bash openssl dgst -sha256 message.bin # run on signer and verifier sides xxd message.bin | tail -2 # check for a sneaky trailing 0a