Sunday, March 13, 2022

[SOLVED] How to check rpm GPG signature using Python3?

Issue

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.


Solution

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


Answered By - Jeff Johnson
Answer Checked By - Cary Denson (WPSolving Admin)