Search code examples
pythonpython-3.xrpmartifactorymirroring

How to check rpm GPG signature using Python3?


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