22

Is it possible to ask gpg (or gpg4win) to just verify whether a file was signed by a particular public key file, without having to import and sign and trust that key?

i.e. something like

gpg --using-key pubkey.txt --verify message.txt

as opposed to having to create your own private key and then do

gpg --import pubkey.txt 
gpg --lsign-key [name within pubkey.txt]
# ... something to do with choosing trust levels
gpg --verify message.txt
3
  • 1
    Try to see if the command gpg --status-fd 1 --verify (thefile) gives in its output as first string the fingerprint of the key that made the signature.
    – harrymc
    Sep 25, 2013 at 18:59
  • Some context here: we have a system which signs things. We give its public key to people who might receive messages from this system, so that they may check that messages were not tampered with. However we don't want to tell recipients to "trust anything signed by this key" because then it could be used to authenticate messages from other systems (e.g. emails from their friends).
    – OJW
    Sep 27, 2013 at 22:18
  • So we want to give someone a command/batch file that checks "does gpg say this message was sent by this key?" without interfering with their day-to-day use of gpg for communicating with other people. The key should only be trusted because the command-line requests it, not because GPG has been told to always trust it.
    – OJW
    Sep 27, 2013 at 22:23

4 Answers 4

16
+100

You must have the public key to verify a signature made with the corresponding private key, but you don't have to sign or even locally sign the key. In this case you will receive a warning from GPG that the key is untrusted.

Here's a test I made with a file signed by my own key, but on a system where the key had not been imported:

[ben@seditious tmp]$ gpg -v --verify thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
gpg: Can't check signature: public key not found
[ben@seditious tmp]$ gpg -v --status-fd 1 --verify thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
[GNUPG:] ERRSIG 7FF2D37135C7553C 1 10 00 1380142299 9
[GNUPG:] NO_PUBKEY 7FF2D37135C7553C
gpg: Can't check signature: public key not found
[ben@seditious tmp]$ 

Unfortunately Harry's suggestion doesn't work, it does extract a little more information, but not enough to be of use.

As you can see, the most information obtained is the key ID of the subkey used to make the signature and the time the signature was made. This matches the data available to pgpdump (or --list-packets):

bash-3.2$ pgpdump thing.txt.gpg 
Old: Compressed Data Packet(tag 8)
    Comp alg - ZLIB <RFC1950>(comp 2)
Old: One-Pass Signature Packet(tag 4)(13 bytes)
    New version(3)
    Sig type - Signature of a binary document(0x00).
    Hash alg - SHA512(hash 10)
    Pub alg - RSA Encrypt or Sign(pub 1)
    Key ID - 0x7FF2D37135C7553C
    Next packet - other than one pass signature
Old: Literal Data Packet(tag 11)(24 bytes)
    Format - binary
    Filename - thing.txt
    File modified time - Thu Sep 26 06:51:39 EST 2013
    Literal - ...
Old: Signature Packet(tag 2)(412 bytes)
    Ver 4 - new
    Sig type - Signature of a binary document(0x00).
    Pub alg - RSA Encrypt or Sign(pub 1)
    Hash alg - SHA512(hash 10)
    Hashed Sub: signature creation time(sub 2)(4 bytes)
        Time - Thu Sep 26 06:51:39 EST 2013
    Sub: issuer key ID(sub 16)(8 bytes)
        Key ID - 0x7FF2D37135C7553C
    Hash left 2 bytes - f0 97 
    RSA m^d mod n(3066 bits) - ...
        -> PKCS-1
bash-3.2$ 

As you can see it provides the hash algorithm, the details of the type of key (my signing key is a 3072-bit RSA subkey and the key ID of the subkey, but there is nothing to identify the master key. That information is only revealed when you have the public key and verify the signature.

Then I imported my public key on that system and tried again:

[ben@seditious tmp]$ gpg -v --verify thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
gpg: using subkey 35C7553C instead of primary key 73590E5D
gpg: using PGP trust model
gpg: Good signature from "Ben M <ben@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M (backup email address) <benm@REDACTED>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: DB47 24E6 FA42 86C9 2B4E  55C4 321E 4E23 7359 0E5D
     Subkey fingerprint: B7F0 FE75 9387 430D D0C5  8BDB 7FF2 D371 35C7 553C
gpg: binary signature, digest algorithm SHA512
[ben@seditious tmp]$ 

Now it is able to identify the key and match it to the primary key. It is, however, possible to reduce the nature of those warnings like this:

[ben@seditious tmp]$ gpg -v --verify --trust-model always thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
gpg: using subkey 35C7553C instead of primary key 73590E5D
gpg: Good signature from "Ben M <ben@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M (backup email address) <benm@REDACTED>"
gpg: WARNING: Using untrusted key!
gpg: binary signature, digest algorithm SHA512
[ben@seditious tmp]$ 

There's still a warning that it is an untrusted key, but not massively so and removing verbosity only reduces it to this:

[ben@seditious tmp]$ gpg --verify --trust-model always thing.txt.gpg 
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
gpg: Good signature from "Ben M <ben@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M (backup email address) <benm@REDACTED>"
gpg: WARNING: Using untrusted key!
[ben@seditious tmp]$ 

The public key is required for the verification stage because it is used to match data generated by the signer with their private key. It can be thought of, in simple terms, as the complement of encryption where the private key is needed to decypt data encrypted to the public key.

Note: I've tweaked the UIDs in this example a little bit, but everyone who gets that key will see what they really are. Otherwise the output is a straight copy and paste.

EDIT: You can call the public key file directly like a keyring if you have it in the non-ASCII armoured format (i.e. a .gpg file instead of a .asc file). Even so, you still need the public key. To do this the command is like this:

[ben@seditious ~]$ gpg -v --no-default-keyring --keyring /tmp/mykey.gpg --verify /tmp/thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
gpg: using subkey 35C7553C instead of primary key 73590E5D
gpg: using PGP trust model
gpg: Good signature from "Ben M <ben@REDACTED>"
gpg:                 aka "Ben M (backup email address) <benm@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: DB47 24E6 FA42 86C9 2B4E  55C4 321E 4E23 7359 0E5D
     Subkey fingerprint: B7F0 FE75 9387 430D D0C5  8BDB 7FF2 D371 35C7 553C
gpg: binary signature, digest algorithm SHA512
[ben@seditious ~]$ 
9
  • Looking at your output, I have reached the exactly opposite conclusion. I have used your output in my answer, but have given you credit for it.
    – harrymc
    Sep 26, 2013 at 6:10
  • The part you refer to which is the long form of the subkey's key ID (technically the full key ID is the fingerprint) is the only identifiable part. Without possession of the public key, though, you cannot identify the master key or verify the signature. The details of this are in section 5.2 of RFC 4880 (with a little bit in section 2.2, but 5.2 is where the useful stuff is). If I'm wrong prove verification without a copy of the key (hint: you can't do it with my examples).
    – Ben
    Sep 26, 2013 at 6:36
  • Also, on your conclusion regarding --verify, it only works when the key is available, otherwise go back to the first example in my answer where the key ID and time of the signature is verified, but the key is not found.
    – Ben
    Sep 26, 2013 at 6:43
  • Yes, full identification is of course not possible from only the key ID. I have modified my answer to clearly state that this is only a heuristic. Your conclusion is that what the poster is asking is impossible, but that is probably because the poster used the word "verify" which is too strong.
    – harrymc
    Sep 27, 2013 at 5:43
  • 1
    That's true, the OP is probably not using the terms properly and I may have fudged them in a couple of places too (I was sneezing a lot last night). If his question was just about validating a sig without importing a key, then the example in my edit shows how it can be done, but only if that key is in OpenPGP (pubkey.gpg) format. It doesn't work if the exported key is in ASCII armoured (pubkey.asc) format.
    – Ben
    Sep 27, 2013 at 6:15
2

If you're OK with shipping a keyring, rather than a public key file, you probably want to use gpgv rather than gpg:

gpgv --keyring key.ring somefile.txt
0

If your word "verify" in the question means "absolutely verify", then of course a public key must be imported to completely verify a signed document. However, if this means "identify", then I describe below a heuristic that can tell whether a group of documents were all signed by the same signature.

According to the tests carried out by @Ben to verify my comment, there is the possibility that the following command could be used to heuristically indicate the signing key :

gpg --status-fd 1 --verify thefile.gpg

The test of Ben gave the result below. Of note are the values of ERRSIG and NO_PUBKEY, and also the value of "RSA key ID" which is partially contained in them both, as follows :

[ben@seditious tmp]$ gpg -v --status-fd 1 --verify thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
[GNUPG:] ERRSIG 7FF2D37135C7553C 1 10 00 1380142299 9
[GNUPG:] NO_PUBKEY 7FF2D37135C7553C
gpg: Can't check signature: public key not found

Note above the string 7FF2D37135C7553C. This same string is found inside the the key fingerprint that is reported once the key is imported :

[ben@seditious ~]$ gpg -v --no-default-keyring --keyring /tmp/mykey.gpg --verify /tmp/thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
gpg: using subkey 35C7553C instead of primary key 73590E5D
gpg: using PGP trust model
gpg: Good signature from "Ben M <ben@REDACTED>"
gpg:                 aka "Ben M (backup email address) <benm@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg:                 aka "Ben M <ben.m@REDACTED>"
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: DB47 24E6 FA42 86C9 2B4E  55C4 321E 4E23 7359 0E5D
     Subkey fingerprint: B7F0 FE75 9387 430D D0C5  8BDB 7FF2 D371 35C7 553C
gpg: binary signature, digest algorithm SHA512

This string is found as the lower part of the fingerprint (Subkey above), so might possibly be used to identify the key. The "Primary key fingerprint" should probably be verified as well, in addition to the Subkey.

The "RSA key ID" string is identical in both outputs and is also found as the last part of the fingerprint, so it might be possible that it is sufficient by itself to identify the signature. If that's the case, using only the output of gpg --verify might be enough to identify the signature in a simpler way.

[ben@seditious tmp]$ gpg -v --verify thing.txt.gpg 
gpg: original file name='thing.txt'
gpg: Signature made Thu 26 Sep 2013 06:51:39 AM EST using RSA key ID 35C7553C
gpg: Can't check signature: public key not found

My knowledge of GPG is not sufficient to fully validate this method, so you should try it on more example files. If it works, you could then sort the files according to their signatures, but will need to import the key to find the identity of the signee.

To clearly state again: This method cannot fully identify a signature. It is only a way to heuristically sort signed documents.

4
  • A signature contains enough data to identify the key used to create it and in conjunction with the key servers it can be used to locate the master key (assuming a signing subkey was used as in my examples). Without a copy of the public key in OpenPGP format (either in a keyring or as in my final example), validation of the signature is not possible because the fingerprint/key ID is not enough data to calculate that.
    – Ben
    Sep 26, 2013 at 20:57
  • @Ben: I repeat that this is only a heuristic, which is the best that can be done in answer the poster's question of "verify whether a file was signed by a particular public key file, without having to import and sign and trust that key".
    – harrymc
    Sep 27, 2013 at 5:33
  • would it make the question any clearer if I said that we trust any keys in the .pub file (for the purposes of checking this specific data file), and that the reasons why we choose to trust this .pub file are outside the scope of any GPG activity?
    – OJW
    Sep 27, 2013 at 22:02
  • Will the heuristic of listing the keys in the .pub file and comparing their RSA key ID be useful? I don't have gpg here to try, but maybe something like "gpg --no-default-keyring --keyring <pub-file> --list-keys".
    – harrymc
    Sep 28, 2013 at 18:32
0

I ended up here looking for a way to validate InRelease files outside of apt

This is what I now have:

for i in /etc/apt/trusted.gpg.d/*.gpg; do
  [[ $trusted -eq 0 ]] && gpg --status-fd 1 --no-random-seed-file --homedir . --no-default-keyring --trust-model always --keyring $i --verify InRelease 2>/dev/null | grep -q GOODSIG && trusted=1
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .