33
votes

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 <[email protected]>"
gpg:                 aka "Richard W.M. Jones <[email protected]>"
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 <[email protected]>
[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.

2
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
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
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
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

2 Answers

25
votes

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

11
votes

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>