39

I know how to use gpg verify like this:

$ gpg --verify somefile.sig
gpg: Signature made Tue 23 Jul 2013 13:20:02 BST using RSA key ID E1B768A0
gpg: Good signature from "Richard W.M. Jones <rjones@redhat.com>"
gpg:                 aka "Richard W.M. Jones <rich@annexia.org>"
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: F777 4FB1 AD07 4A7E 8C87  67EA 9173 8F73 E1B7 68A0

But what I really want to do is to verify the file against a specific public key file.

The motivation is as part of a program that downloads large files from a website and needs to verify they haven't been tampered with before it uses them. The website will contain the files and the signatures. The program will ship with the GPG public key. When I upload the files to the website I will sign them with the corresponding private key (not distributed obviously). It seems like the program should be able to do something like:

gpg --no-default-keyring --verify file.sig \
    --is-signed-with /usr/share/program/goodkey.asc

But gpg has no option like this. It looks like the only way to do it would be to parse the printed output of the gpg command which seems very unsafe (it contains text controlled by the attacker).

Edit: I don't know what the etiquette is around here for answering ones own questions, but the answer I found was to use the --status-fd flag. This flag generates nicely parsable output which I can check for the desired fingerprint:

gpg --status-fd <N> --verify file.sig

produces on fd N:

[GNUPG:] SIG_ID rpG8ATxU8yZr9SHL+VC/WQbV9ac 2013-07-23 1374582002
[GNUPG:] GOODSIG 91738F73E1B768A0 Richard W.M. Jones <rjones@redhat.com>
[GNUPG:] VALIDSIG F7774FB1AD074A7E8C8767EA91738F73E1B768A0 2013-07-23 1374582002 0 4 0 1 2 00 F7774FB1AD074A7E8C8767EA91738F73E1B768A0
[GNUPG:] TRUST_UNDEFINED

This is how, for example, perl's GnuPG library works.

Jens Erat
  • 37,523
  • 16
  • 80
  • 96
Rich
  • 926
  • 1
  • 9
  • 17
  • If you put the public key that should be used next to the download, what will prevent anybody to tamper the file and put his own public key next to it? – Jens Erat Sep 25 '13 at 18:02
  • 1
    The public key isn't next to the download. The public key is included in the software. The file next to the download is the detached signature. – Rich Sep 25 '13 at 19:30
  • 1
    Now I get it, somewhat misunderstood what you're doing. Answering your own questions is appreciated, best would be to put it into the answer field below. You will be able to select it as "answered your question" within two days or so. – Jens Erat Sep 25 '13 at 19:45
  • Note that the status-fd output you received was only obtained because the public key was in your keyring, it doesn't get around the issue of calling the key file directly instead of importing the key to the default (or any other) keyring. – Ben Sep 25 '13 at 21:59

2 Answers2

33

The only way to use a specific public key file like a keyring is if the file is in the GPG (OpenPGP) file format and not an ASCII armoured version (e.g. pubkey.gpg not pubkey.asc).

So this will verify the file:

gpg --no-default-keyring --keyring /path/to/pubkey.gpg --verify /path/to/file.txt.gpg

And this will not:

gpg --no-default-keyring --keyring /path/to/pubkey.asc --verify /path/to/file.txt.gpg

EDIT: I've gone into a little more detail on this for a similar question on the SuperUser site:

https://superuser.com/questions/639853/gpg-verifying-signatures-without-creating-trust-chain/650359#650359

Community
  • 1
  • 1
Ben
  • 3,981
  • 2
  • 25
  • 34
  • 12
    Quick note, the `--keyring` path must be absolute. If it's **just** a filename it'll look for the keyring file in `~/.gnupg`. To instead look for the keyring in the current directory prepend the filename with `./`. – Jess Jul 28 '16 at 17:33
  • Yep, that's absolutely right. I hoped my generic `/path/to` would be enough, but it is worth stressing in anticipation of confusion, thanks. On a semi-related note, the 2.1 branch recently acquired a new set of commands to do this more effectively even with ASCII armoured files, but it is only available in 2.1.14 or above (the additions were made in early July, 2016; a week before the 2.1.14 release). Some details are in [this post](https://lists.gnupg.org/pipermail/gnupg-devel/2016-July/031308.html) and it looks fairly straight forward, but is unlikely to be backported to 2.0 or 1.4. – Ben Aug 02 '16 at 11:53
  • @Ben, you should rather say the `--keyring` path must *contain a slash,* since `./whatever` is not absolute. – Wildcard Sep 08 '18 at 00:44
  • 1
    @Wildcard You're right, I should have said if the argument for `--keyring` is a only filename (not a relative/absolute path) it'll be looked for in `~/.gnupg` – Jess Sep 11 '18 at 14:27
  • 2
    Can you not just `gpg --dearmor pubkey.asc` and use the output? – ZN13 Apr 13 '19 at 07:30
  • Why is `gpg` _still_ annoyingly difficult to use? A signature verification has 3 input parameters: the signature, the public key, and the file in question. How is it that there does not exist a single command to do a simple verification? When one takes a look at how GPG is supposed to be used, it is no wonder that Git has started supported SSH-signed commits. – wheeler Nov 18 '22 at 08:39
12

I came up with the following script:

#!/bin/bash

set -e

keyfile=$(mktemp --suffix=.gpg)
function cleanup {
    rm "$keyfile"
}
trap cleanup EXIT

gpg2 --yes -o "$keyfile" --dearmor "$1"
gpg2 --status-fd 1 --no-default-keyring --keyring "$keyfile" --trust-model always --verify "$2" 2>/dev/null

use as:

$ check-sig.sh <ascii-armored-keyfile> <signature-document>
zbyszek
  • 5,105
  • 1
  • 27
  • 22
  • What does it mean if the output is: [GNUPG:] NODATA 1 [GNUPG:] NODATA 2 – slashdottir Oct 22 '17 at 03:08
  • 1
    You could modify the last line of that script to read `gpg2 --no-default-keyring --keyring "$keyfile" --trust-model always --verify "$2" 2> /dev/null && echo valid || echo invalid`. That way it will simply return `valid` or `invalid`. – b_laoshi Dec 21 '17 at 07:00