Error message
Verification failure
openssl pkeyutl -verify prints the sibling "Signature Verification Failure". On OpenSSL 3.x both are accompanied by an error-stack line such as "error:030000EA:digital envelope routines:EVP_DigestVerifyFinal:provider signature failure" (reproduced on 3.6).
What it means
openssl dgst -verify computed the digest of your data, checked the signature against the public key, and the mathematics said no. Key, data and signature were all readable — one of the three does not belong with the others. The success output, for contrast, is "Verified OK".
Why it happens
Signature in raw r‖s instead of DER
commonOpenSSL only accepts ECDSA signatures as ASN.1 DER. A 64-byte signature from WebCrypto, JWS or most Go/Python raw-mode APIs must be converted first; passed as-is it can also produce "Error verifying data" on parse.
The data differs from what was signed
commonA trailing newline added by an editor, CRLF vs LF conversion by git, or hashing an already-hashed digest again (dgst hashes its input — feeding it a SHA-256 digest signs the hash of the hash).
Digest mismatch
commonSigned with -sha256 but verified with -sha384 (or the signer's library defaulted to another hash). The digest is part of the signed statement; both sides must use the same one.
Wrong public key
occasionalA rotated key, the key of a different service, or a public key derived from a different private key than the one that signed.
How to fix it
- 1.
Convert raw signatures to DER first
If the signature is exactly 64 bytes (P-256) or 96 bytes (P-384), it is raw r‖s. Convert it with the DER ⇄ raw tool below — it also flags non-canonical high-S values that strict verifiers reject — then re-run dgst -verify.
- 2.
Verify a pre-hashed digest with pkeyutl
When you hold the digest rather than the message, dgst is the wrong tool (it would hash again). pkeyutl verifies against the raw digest.
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.
Eliminate data drift
Compare digests of the exact bytes on both sides; any difference means the message changed, not the crypto.
bash openssl dgst -sha256 message.bin # run on signer and verifier sides xxd message.bin | tail -2 # check for a sneaky trailing 0a