I am working on creating a local CentOS mirror on a local Artifactory instance, and I built a Python3 script to check for differences between the remote and local repos and update the local ones accordingly.
As a requirement, I need to add a step that checks the validity of the downloaded rpm packages before adding them to the local mirror.
While I could do that by calling "rpm -K" (after importing the CentOS GPG keys), I was wondering if there would be a better way in which I can implement this, perhaps without relying on external packages.
Here is a short shell script that extracts the "plaintext" (i.e. the region that is signed) from a *.rpm file. This is for the header+payload signature, the header-only signature plaintext is similar, just only the header blob).
You will need the signature (you can use rpm-python bindings, see note below) and you will need python bindings to gpg in order to verify a package signature.
Note that verification of a downloaded and possibly tampered package that requires parsing to find the plaintext and retrieve the signature is already a tricky business: you can be exploited before you can verify the signature.
============================== /usr/lib/rpm/tgpg
#!/bin/sh
for pkg in $*
do
if [ "$pkg" = "" -o ! -e "$pkg" ]; then
echo "no package supplied" 1>&2
exit 1
fi
plaintext=$(mktemp /tmp/tgpg-$$.XXXXXX)
detached=$(mktemp /tmp/tgpg-$$.XXXXXX)
# --- Extract detached signature
rpm -qp -vv --qf '%{siggpg:armor}' $pkg > $detached
# --- Figger the offset of header+payload in the package
leadsize=96
o=$(expr $leadsize + 8)
set $(od -j $o -N 8 -t u1 $pkg)
il=$(expr 256 \* \( 256 \* \( 256 \* $2 + $3 \) + $4 \) + $5)
dl=$(expr 256 \* \( 256 \* \( 256 \* $6 + $7 \) + $8 \) + $9)
sigsize=$(expr 8 + 16 \* $il + $dl)
o=$(expr $o + $sigsize + \( 8 - \( $sigsize \% 8 \) \) \% 8)
# --- Extract header+payload
dd if=$pkg ibs=$o skip=1 2>/dev/null > $plaintext
# --- Verify DSA signature using gpg
gpg --batch -vv --debug 0xfc02 --verify $detached $plaintext
# --- Clean up
rm -f $detached $plaintext
done