Digital Signature Verification with Openssl

openssl command line to verify the signature

I found two solutions to your problem.

You can use rsautl that way: (with private key: my.key and public key my-pub.pem)

$ openssl rsautl -sign -inkey my.key -out in.txt.rsa -in in.txt
Enter pass phrase for my.key:
$ openssl rsautl -verify -inkey my-pub.pem -in in.txt.rsa -pubin
Bonjour

With this method, all the document is included within the signature file and is outputted by the final command.

But in my case, my certificate says: Signature Algorithm: sha1WithRSAEncryption.
So I would recommend you to use the standard way of signing document in 4 steps: (This method is used for all asymmetric electronic signatures in order not to overcharge the signature file and/or CPU usage)

  1. Create digest of document to sign (sender)
  2. Sign digest with private key (sender)
  3. Create digest of document to verify (recipient)
  4. Verify signature with public key (recipient)

OpenSSL does this in two steps:

$ openssl dgst -sha256 -sign my.key -out in.txt.sha256 in.txt 
Enter pass phrase for my.key:
$ openssl dgst -sha256 -verify my-pub.pem -signature in.txt.sha256 in.txt
Verified OK

With this method, you sent the recipient two documents: the original file plain text, the signature file signed digest. Attention: the signature file does not include the whole document! Only the digest.

Generating, Signing and Verifying Digital Signature

Don’t use rsautl for this.

According to PKCS1.5, when signing the format of the data that goes into the RSA operation looks something like this:

<padding><metadata><hash of input>

(The metadata specifies which hash function has been used.)

This format is what openssl dgst -verify is looking for when you try to verify the signature. However this is not what you create in your steps.

First of all the default output of openssl dgst is the hex encoding of the resulting hash, not the raw bytes.

Secondly, rsautl is fairly “low level”, and when signing doesn’t add the metadata that openssl dgst -verify is expecting, although it does add the padding.

These two things together mean that the data you are using looks like this:

<padding><hex digits of hash of input>

Obviously this doesn’t match what openssl dgst -verify is expecting, so the verification fails.

It would be possible to create a correctly formatted input for rsautl, but it would be awkward and involve dealing with ASN.1 details. You could also use rsautl -verify instead of dgst -verify, but that would also require a few more details and would mean you are using a non-standard signature format.

The simplest solution is to use openssl dgst for both the creation and verification of the signature. Replace your steps 3 and 4 (except for creating the example.txt file) with the single command:

$ openssl dgst -sha256 -sign private.pem -out example.sha256 example.txt

This hashes the data, correctly formats the hash and performs the RSA operation it. The resulting file should correctly verify with the openssl dgst -verify command.

Digital signature for a file using openssl

Yes, the dgst and rsautl component of OpenSSL can be used to compute a signature given an RSA key pair.

Signing:

openssl dgst -sha256 data.txt > hash
openssl rsautl -sign -inkey privatekey.pem -keyform PEM -in hash >signature

Verifying just the signature:

openssl rsautl -verify -inkey publickey.pem -pubin -keyform PEM -in signature

Update: Capturing Reto's comments from below because this is an important nuance. Presumably if you are going to the trouble to verify, you want to know the signature was produced on the plaintext to which it is attached:

This might sound obvious for some but: Be aware, rsautl verify just decrypts the file signature. The output of this call is guaranteed to be produced by the owner of the private key, but beside that nothing else is being checked. So to actually verify the consistency of data.txt you have to regenerate the digest and then compare it against the output of openssl rsautl -verify.

Verifying that the owner of the private key does vouch for data.txt:

openssl dgst -sha256 -verify publickey.pem -signature signature data.txt

For this operation, openssl requires the public key, the signature, and the message.

verifying a file signature with openssl dgst

openssl dgst -verify foo.pem expects that foo.pem contains the "raw" public key in PEM format. The raw format is an encoding of a SubjectPublicKeyInfo structure, which can be found within a certificate; but openssl dgst cannot process a complete certificate in one go.

You must first extract the public key from the certificate:

openssl x509 -pubkey -noout -in cert.pem > pubkey.pem

then use the key to verify the signature:

openssl dgst -verify pubkey.pem -signature sigfile datafile

Verifying signature created using OpenSSL with BearSSL

The signature file contents shown as

$ hexdump signature
0000000 4530 2002 ac54 51af 8ac0 cee8 dc74 4120
...

is displayed as 16-bit values.

The signature in the C program is defined as an array of 8-bit values

uint8_t signature[] = {
0x45, 0x30, 0x20, 0x02, 0xac, 0x54, 0x51, 0xaf, 0x8a, 0xc0, 0xce, 0xe8, 0xdc, 0x74, 0x41, 0x20,
...
};

Depending on the byte order this may or may not be correct. Does 4530 correspond to 45, 30 or 30, 45?

With little-endian byte-order, the hex dump

4530 2002 ...

would correspond to (*)

uint8_t signature[] = {
0x30, 0x45, 0x02, 0x20, ...
};

I suggest to display the hex dump as 8-bit values, e.g. by using

od -t x1 signature

and, if necessary, fix the array initialization in the C code.

According to dave_thompson_085's comment, the correct byte order is 0x30, 0x45, so the proposed fix (*) is the solution.

And an ECDSA signature on a 256-bit group definitely starts with first tag=SEQUENCE+constructed (always 0x30) then body length usually 68 to 70 (0x44 to 0x46)

Verify Signature ECDSA signature with Openssl

The openssl dgst command "-hex" parameter means that the output is NOT binary but a hex dump of the binary output.

Quote:

-hex

digest is to be output as a hex dump. This is the default case for a
"normal" digest as opposed to a digital signature. See NOTES below for
digital signatures using -hex.

And the note section:

Hex signatures cannot be verified using openssl. Instead, use "xxd -r"
or similar program to transform the hex signature into a binary
signature prior to verification.

So if you use the -hex option for a hex dump, you need to convert it back to binary yourself somehow before passing it into openssl to verify.



Related Topics



Leave a reply



Submit