Why OpenSSL tools can successfully verify a not signed file? - ssl

I have two files with the same content: msg.txt and msg2.txt. The msg.txt was signed, msg2.txt - was not signed. But I see both files passes the signature validation.
Why is it so? I thought if I sign a file, the signature should be attached somewhere to the file. But hexdump shows there is no difference between the files.
msg.txt
$ hexdump -C msg.txt
00000000 48 69 0a |Hi.|
00000003
msg2.txt
$ hexdump -C msg2.txt
00000000 48 69 0a |Hi.|
00000003
Now every new file which contains "Hi" word only can be successfully verified. What if another user creates a file with a "Hi" word?!
Steps to reproduce:
Create a self-signed PEM certificate-key pair
openssl req -x509 -sha512 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Create files
$ echo "Hi" > msg.txt
$ echo "Hi" > msg2.txt
Sign msg.txt
$ openssl dgst -sha512 -sign key.pem -out /tmp/signature msg.txt
$ openssl base64 -in /tmp/signature -out signature
Verify msg.txt signature
$ openssl base64 -d -in signature -out /tmp/signature
$ openssl x509 -pubkey -noout -in cert.pem > pubkey.pem
$ openssl dgst -sha512 -verify pubkey.pem -signature /tmp/signature msg.txt
Verified OK
Verify msg2.txt signature
$ openssl dgst -sha512 -verify pubkey.pem -signature /tmp/signature msg2.txt
Verified OK

I thought if I sign a file, the signature should be attached somewhere to the file.
You explicitly put the signature into the separate file /tmp/signature which you later used when validating the signature - which explains why the signature was not part of the file.
And you did not sign a file but you signed the contents of a file - which explains why the signature can be applied to two separate files which have exactly the same contents.

Related

Open SSL digital signature unable to load key file

I'm looking to create an example of creating a document, digitally signing it, and verifying it. All works fine until I try and verify the signature, all I get is unable to load key file
Create a document, which needs an agreement (signature):
echo I, Bob, promise to pay Mark £1000 by 1/1/2020 > contract.txt
Generate a private key:
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
Generate the public key from the private key:
openssl rsa -in private_key.pem -RSAPublicKey_out -out public_key.pem
Digitally sign the document:
openssl dgst -sha256 -hex -sign private_key.pem -out signature.sign contract.txt
Then if we view the contents of signature.sign:
RSA-SHA256(contract.txt)= 2f5dc8216766562a9fb67a7b09b43b599889e7adea3d4d508194018961a82a9076051ee3c3952af9dbd607cbfe1095976ec5e877e22c0e4a884003ebef672f9a3e598128f819435a178c92ad10e4a409dc28db6e6500dfcee6a58e352446c354dec0852d6d826ee443fe158e6c30a231d30eb00e03c21a3e98855445bcc43a000f205b44ea8fc2f4ed85cd7c03c5708d649ef9a7d737b0948b9bdba322868e18492446eac054e2d4a31f0fa9bfccc627b621da0a9a261fb6169c1f107ec0311844151e77e50aeedb1be860c2b0b58f077c2886f9a7f05e727c0f9d4cc24d668f96bf7d6a2fff40a4b14951e745847c13812b35df95f91d202df0ef6ea5a05078
To verify the signature:
openssl dgst -sha256 -hex -verify public_key.pem -signature signature.sign contract.txt
Full script:
echo I, Bob, promise to pay Mark £1000 by 1/1/2020 > contract.txt
openssl genpkey -algorithm RSA -out private_key.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -in private_key.pem -RSAPublicKey_out -out public_key.pem
openssl dgst -sha256 -sign private_key.pem -out signature contract.txt
openssl dgst -sha256 -verify public_key.pem -signature signature contract.txt
Thank you!

How to convert the .der file to .pub?

Late I convert the .pub file to .der file through
ssh-keygen -f ran.pub -e -m PKCS8 | openssl pkey -pubin -outform DER -out pub.der
and current I want to convert .pub file to .der
But here when I try .der file to .pem or other .pub it can't convert
I tried this
openssl x509 -inform der -in pub.der -out certificate.pem
But it will getting error
unable to load certificate
4601439852:error:09FFF06C:PEM routines:CRYPTO_internal:no start line:/BuildRoot/Library/Caches/com.apple.xbs/Sources/libressl/libressl-22.200.4/libressl-2.6/crypto/pem/pem_lib.c:683:Expecting: TRUSTED CERTIFICATE
Here the solution
openssl rsa -in pub.der -pubout -out pub.pem

Decrypt openssl certificate

I generated 3 keys / certificates using this script:
#!/bin/sh
AUTH='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android#android.com'
if [ "$1" == "" ]; then
echo "Create a test certificate key."
echo "Usage: $0 NAME"
echo "Will generate NAME.pk8 and NAME.x509.pem"
echo " $AUTH"
exit
fi
openssl genrsa -3 -out $1.pem 2048
openssl req -new -x509 -key $1.pem -out $1.x509.pem -days 10000 \
-subj "$AUTH"
echo "Please enter the password for this key:"
openssl pkcs8 -in $1.pem -topk8 -outform DER -out $1.pk8 -passout stdin
The output is:
releasekey.pem
releasekey.pk8
releasekey.x509.pem
Then I'm trying to decrypt it using this command:
openssl pkcs8 -in ~/.android-certs/releasekey.pk8 -inform DER
So, the output is
alex-garmas-osx:android alex-garmash$ openssl pkcs8 -in ~/.android-
certs/releasekey.pk8 -inform DER
Enter Password:
-----BEGIN PRIVATE KEY-----
CONTENT OF PRIVATE KEY HERE
-----END PRIVATE KEY-----
And it works OK. releasekey.pk8 doesn't have a passphrase
When I do the same with the command:
openssl pkcs8 -in ~/.android-certs/releasekey.pk8 -inform DER -nocrypt
I have an error:
140735885419528:error:0D0680A8:asn1 encoding routines:ASN1_CHECK_TLEN:wrong tag:tasn_dec.c:1200:
140735885419528:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:tasn_dec.c:768:
140735885419528:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:tasn_dec.c:700:Field=version, Type=PKCS8_PRIV_KEY_INFO
In the documentation I see that I can use option -nocrypt, but why is it failing?
UPDATE
Many thanks to #bartonjs for the explanation. To solve this problem you need to add -nocrypt flag to the last command of the script, then you can use the command above to decrypt generated key
#!/bin/sh
AUTH='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android#android.com'
if [ "$1" == "" ]; then
echo "Create a test certificate key."
echo "Usage: $0 NAME"
echo "Will generate NAME.pk8 and NAME.x509.pem"
echo " $AUTH"
exit
fi
openssl genrsa -3 -out $1.pem 2048
openssl req -new -x509 -key $1.pem -out $1.x509.pem -days 10000 \
-subj "$AUTH"
echo "Please enter the password for this key:"
openssl pkcs8 -in $1.pem -topk8 -outform DER -out $1.pk8 -passout stdin -nocrypt
You are getting prompted for the empty password, and it succeeds, and with -nocrypt it is failing.
There's a difference between "encrypted with the empty password" and "not encrypted" (though to a brute forcer, not much of one).
An unencrypted PKCS#8 blob looks like (ASN.1):
PrivateKeyInfo ::= SEQUENCE {
version Version,
privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
privateKey PrivateKey,
attributes [0] IMPLICIT Attributes OPTIONAL }
If it has been encrypted, then it's
EncryptedPrivateKeyInfo ::= SEQUENCE {
encryptionAlgorithm EncryptionAlgorithmIdentifier,
encryptedData EncryptedData }
EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
EncryptedData ::= OCTET STRING
So -nocrypt tells OpenSSL that it should expect the first structure directly, whereas yours looks like the second (notably, the first child of the SEQUENCE wasn't an INTEGER, but was another SEQUENCE).
And saying that your data was encrypted with the empty password doesn't mean it was encrypted with some sort of empty key. The creator of the PKCS#8 file almost certainly went through the trouble of picking a random salt to the PBKDF2 algorithm, which then gets combined with the empty password to produce an output. That data is still noise, just... easier to brute force noise than normal.

Data verification with openssl smime fails

I am using openssl smime to sign and verify data.
To sign text file using openssl I sue the following command:
openssl smime -sign -in sample.txt -out mail.msg -signer cert.pem -inkey key.pem
Then I proceed to verification:
openssl smime -verify -in mail.msg -CAfile allCA.pem
The verification succeed.
My problem is that I have an external tool that performs the verification using the following command:
openssl smime -verify -in mail.msg -inform DER -CAfile allCA.pem
How to sign my txt file so it can be verified with the previous command ?
What I've tried so far:
openssl smime -sign -in sample.txt -out mail.msg -outform DER -signer cert.pem -inkey key.pem
But I get an error when trying to verify my mail:
Verification failure
140204331579208:error:2107507A:PKCS7 routines:PKCS7_verify:no content:pk7_smime.c:291:
The way you call sign operation creates detached signature so you would need to pass -content sample.txt to verify command. However, it is possible to create structure that encapsulates message together with signature (-nodetach parameter).
This is the sign command you are looking for:
openssl smime -sign -in data.dat -out mail.msg -signer cert.pem -inkey key.pem -outform DER -nodetach

Digital signature for a file using openssl

Is there a way to digitally sign a x509 certificate or any document using openssl?
To Generate Private Key
openssl genrsa -out privatekey.pem 2048
To Sign
openssl dgst -sha256 -sign privatekey.pem -out data.txt.signature data.txt
To Generate The Public Key
dgst -verify requires the public key
openssl rsa -in privatekey.pem -outform PEM -pubout -out publickey.pem
To Verify
openssl dgst -sha256 -verify publickey.pem -signature data.txt.signature data.txt
In case of success: prints "Verified OK", return code 0
In case of failure: prints "Verification Failure", return code 1
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.
To digitally sign document in openssl it will work
For this first your certificate should be trusted
it would be look like this
-----BEGIN TRUSTED CERTIFICATE-----
MIIDbjCCAlYCCQCOyunl25ProDANBgkqhkiG9w0BAQUFADB5MQswCQYDVQQGEwJJ
...
-----END TRUSTED CERTIFICATE-----
Then use following command
smime -sign -signer certificate.pem -inkey private.key -in test.txt \
-out test1.txt -from ashish -to singhal