dnf icon indicating copy to clipboard operation
dnf copied to clipboard

GPG key gets broken while importing

Open marmarek opened this issue 1 year ago • 0 comments

When DNF is importing a key, it first mangles it via GnuPG, and only then import to rpmdb (which nowadays uses Sequoia). Those two PGP implementations are not 100% compatible which leads to issues - specifically, some keys that GnuPG is happy about (or even produced by GnuPG) are not accepted by Sequoia. In this particular case, I hit https://gitlab.com/sequoia-pgp/sequoia/-/issues/1023 (similar to https://gitlab.com/sequoia-pgp/sequoia/-/issues/1024).

When using DNF, the package verification fails:

# /usr/bin/dnf -y --releasever=37 --installroot=/builder/dnfroot --config=/builder/dnfroot/etc/dnf/dnf.conf --downloaddir=/builder/plugins/installer/work/202307282149/x86_64/os/Packages --downloadonly install qubes-template-whonix-workstation-17
...
Importing GPG key 0x6D5C71B3:
 Userid     : "Qubes OS Release 4.2 Community Templates Signing Key"
 Fingerprint: 8F24 D388 C9DA 21A5 5D7D BC8F 08D0 8ABE 6D5C 71B3
 From       : /tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.2-templates-community
error: Certificate 08D08ABE6D5C71B3:
  Policy rejects 08D08ABE6D5C71B3: No binding signature at time 2023-07-28T22:19:01Z
Key import failed (code 2). Failing package is: qubes-template-whonix-gateway-17-4.2.0-202307131323.noarch
 GPG Keys are configured as: file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.2-templates-community
Public key for qubes-template-whonix-workstation-17-4.2.0-202307131323.noarch.rpm is not installed. Failing package is: qubes-template-whonix-workstation-17-4.2.0-202307131323.noarch
 GPG Keys are configured as: file:///tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.2-templates-community

But, when I import the key using rpmkeys directly, it works:

$ rpmkeys --import --root $PWD/rpmdb --verbose --define='_pkgverify_level signature' --define='_pkgverify_flags 0x0' /tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.2-templates-community 
$ rpmkeys --checksig --root $PWD/rpmdb --verbose --define='_pkgverify_level signature' --define='_pkgverify_flags 0x0' /builder/plugins/installer/work/202307282149/x86_64/os/Packages/qubes-template-whonix-gateway-17-4.2.0-202307131323.noarch.rpm 
/builder/plugins/installer/work/202307282149/x86_64/os/Packages/qubes-template-whonix-gateway-17-4.2.0-202307131323.noarch.rpm:
    Header V4 EdDSA/SHA256 Signature, key ID 6d5c71b3: OK
    Header SHA256 digest: OK
    Header SHA1 digest: OK
    Payload SHA256 digest: OK
    V4 EdDSA/SHA256 Signature, key ID 6d5c71b3: OK
    MD5 digest: OK

Similarly, if I import the key into rpmdb in /builder/dnfroot (as used in the dnf call earlier here), it works fine then.

This seems to be related to this part of crypto.py (called from Base._get_key_for_package()):

def rawkey2infos(key_fo):
    pb_dir = tempfile.mkdtemp()
    keyinfos = []
    with pubring_dir(pb_dir), Context() as ctx:
        ctx.op_import(key_fo)
        for key in ctx.keylist():
            subkey = _extract_signing_subkey(key)
            if subkey is None:
                continue
            keyinfos.append(Key(key, subkey))
        ctx.armor = True
        for info in keyinfos:
            with Data() as sink:
                ctx.op_export(info.id_, 0, sink)
                sink.seek(0, os.SEEK_SET)
                info.raw_key = sink.read()
    dnf.util.rm_rf(pb_dir) 
    return keyinfos

def retrieve(keyurl, repo=None):
    if keyurl.startswith('http:'):
        logger.warning(_("retrieving repo key for %s unencrypted from %s"), repo.id, keyurl)
    with dnf.util._urlopen(keyurl, repo=repo) as handle:
        keyinfos = rawkey2infos(handle)
    for keyinfo in keyinfos:
        keyinfo.url = keyurl
    return keyinfos

I have confirmed the above is breaking the key. It can be also reproduced outside of dnf:

$ sq inspect /tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.2-templates-community
/tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.2-templates-community: OpenPGP Certificate.

    Fingerprint: 8F24D388C9DA21A55D7DBC8F08D08ABE6D5C71B3
Public-key algo: EdDSA
Public-key size: 256 bits
  Creation time: 2023-03-14 14:35:36 UTC
      Key flags: certification, signing

         UserID: Qubes OS Release 4.2 Community Templates Signing Key
$ mkdir test
$ gpg --homedir $PWD/test --import /tmp/qubes-installer/qubes-release/RPM-GPG-KEY-qubes-4.2-templates-community
gpg: WARNING: unsafe permissions on homedir '/home/user/test'
gpg: key 08D08ABE6D5C71B3: public key "Qubes OS Release 4.2 Community Templates Signing Key" imported
gpg: Total number processed: 1
gpg:               imported: 1
$ gpg --homedir $PWD/test -a --export | sq inspect
gpg: WARNING: unsafe permissions on homedir '/home/user/test'
-: OpenPGP Certificate.

    Fingerprint: 8F24D388C9DA21A55D7DBC8F08D08ABE6D5C71B3
                 Invalid: No binding signature at time 2023-07-28T22:29:23Z
Public-key algo: EdDSA
Public-key size: 256 bits
  Creation time: 2023-03-14 14:35:36 UTC

         UserID: Qubes OS Release 4.2 Community Templates Signing Key
                 Invalid: No binding signature at time 2023-07-28T22:29:23Z

While technically it can be qualified as a GnuPG bug, I don't think it's smart to mix two parsers, especially this way (transform using loose one then pass the output to a stricter one). It will lead to issues like this, especially given the GnuPG code shape.

The key in question can be found at https://github.com/QubesOS/qubes-qubes-release/blob/main/RPM-GPG-KEY-qubes-4.2-templates-community (if you look at its commit history, you'll see I needed to fix it there). Example package signed with it is at https://yum.qubes-os.org/r4.2/templates-community/rpm/qubes-template-whonix-gateway-17-4.2.0-202307131323.noarch.rpm (it's a big one, sorry).

$ dnf --version
4.15.0
  Installed: dnf-0:4.15.0-1.fc38.noarch at Sat May 20 01:44:10 2023
  Built    : Fedora Project at Thu Apr  6 08:24:21 2023

  Installed: rpm-0:4.18.1-3.fc38.x86_64 at Sat May 20 01:44:11 2023
  Built    : Fedora Project at Wed Apr 26 05:35:27 2023

marmarek avatar Jul 28 '23 23:07 marmarek