How can I import a key via gpg --recv-key
and check it's fingerprint automatically? Ideally, I would use gpg --recv-key $fingerprint
directly, but gpg only recently added a check, that the received key(s) actually had the correct fingerprint instead of trusting the key-server blindly and the fix has not landed in all distributions I care about (e.g. the Docker Ubuntu Image still has an old gpg version).
I want to use it in combination with apt-key
to add a PPA to a docker container.
#!/bin/bash
set -e
tempName=$(mktemp)
gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys $fingerprint 1> $tempName 2>/dev/null
grep "^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$" $tempName
grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName
This script will return with a non-zero exit code if the key can't be downloaded or if the keyserver returns a malicious key. Beware: The malicious key still ends up in the gpg keyring, so you if you use it outside of a Dockerfile you will probably want to restore the original key ring afterwards. The commands for use in a Dockerfile (adding a rust PPA as an example):
RUN echo "deb http://ppa.launchpad.net/hansjorg/rust/ubuntu trusty main" >> /etc/apt/sources.list
RUN echo "deb-src http://ppa.launchpad.net/hansjorg/rust/ubuntu trusty main" >> /etc/apt/sources.list
RUN bash -c 'set -e;tempName=$(mktemp);apt-key adv --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys C03264CD6CADC10BFD6E708B37FD5E80BD6B6386 1> $tempName 2>/dev/null;grep "^\[GNUPG\:\] IMPORT_OK [[:digit:]]* C03264CD6CADC10BFD6E708B37FD5E80BD6B6386$" $tempName;grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName'
The first building block to consider is GnuPGs --status-fd
option. It tells gpg to write machine readable output to the given file descriptor. The file descriptor 1
always references stdout, so we will use that. Then we will have to find out what the output of --status-fd
looks like. The documentation for that is not in the manpage, but in doc/DETAILS
. An example output looks like this:
# gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys BD6B6386 2>/dev/null
[GNUPG:] IMPORTED 37FD5E80BD6B6386 Launchpad PPA for Hans Jørgen Hoel
[GNUPG:] IMPORT_OK 1 C03264CD6CADC10BFD6E708B37FD5E80BD6B6386
[GNUPG:] IMPORT_RES 1 0 1 1 0 0 0 0 0 0 0 0 0 0
So we are looking for IMPORT_OK
and IMPORT_RES
lines. The second parameter after IMPORT_OK
is the actual fingerprint of the imported key. The first parameter after IMPORT_RES
is the number of keys imported.
In the output, gpg escapes newlines, so it is ok to match for lines beginning with [GNUPG:]
to assert we not matching in strings that are controlled by an attacker (for example the name field in the key could otherwise contain \n[GNUPG:] IMPORT_OK 1 C03264CD6CADC10BFD6E708B37FD5E80BD6B6386]
and fool us by creating a match).
With grep we can match for a line beginning with [GNUPG] sometext
via grep "^\[GNUPG\:\]"
and for a whole line with grep "^\[GNUPG\:\] sometext$"
(^
and $
represent the start and end of a line). According to the documentation, any number following IMPORT_OK
is ok for us, so we match against "[[:digit:]]*"
. Thus, as regular expressions we get "^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$"
and "^\[GNUPG\:\] IMPORT_RES 1"
As we want to match the output twice, we safe it into a temporary file (by creating an empty temporary file with mktemp
and rerouting the output in that file). If grep
does not match any lines it returns with a non-zero error code. We can use that by instructing bash
to abort on any error via set -e
. Overall we end up with:
set -e
tempName=$(mktemp)
gpg --status-fd 1 --keyserver keyserver.ubuntu.com --recv-keys $fingerprint 1> $tempName 2>/dev/null
grep "^\[GNUPG\:\] IMPORT_OK "[[:digit:]]*" "$fingerprint"$" $tempName
grep "^\[GNUPG\:\] IMPORT_RES 1" $tempName
How to use with apt
to add a repository key:
apt-key
features the adv
command to hand over command line parameters directly to gpg (run the above command without output rerouting to see the actual gpg command generated by apt-key
). So we can simply exchange gpg
with apt-key adv
to operate on the repository key ring.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With