From Fedora Project Wiki

Revision as of 06:34, 22 August 2022 by Atim (talk | contribs) (Typo)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Rationale

Many upstream source releases are accompanied by a PGP signature. It is possible for source tarballs to be compromised at any point in time, from the download site or within the Fedora lookaside cache.

Fedora packages should, as a matter of course, validate any available signature on the source files used for building.

Proposal

I propose to add a new section to the guidelines, perhaps between the existing Use of pregenerated code and Spec File Naming sections. It should read as follows:

Source file verification

Where PGP or equivalent signatures are published by the upstream project, Fedora packages MUST validate that signature as part of the RPM build process as first command in the in the %prep section of the spec file. Any detached signature file (e.g. foo.tar.gz.asc or foo.tar.gz.sig) must be uploaded to the package lookaside cache alongside the source code, while the GPG key itself must be committed directly to package SCM.

The following format must be used:

Source0: ftp://ftp.example.com/pub/foo/%{name}-%{version}.tar.gz
Source1: ftp://ftp.example.com/pub/foo/%{name}-%{version}.tar.gz.asc
Source2: gpgkey-0123456789ABCDEF0123456789ABCDEF.gpg
…
BuildRequires: gnupg2
…
%prep
gpgv2 --keyring %{SOURCE2} %{SOURCE1} %{SOURCE0}

The first source is the actual tarball and the second one the GPG signature from upstream. The third source contains the upstream GPG key that is used to generate the signature. Ideally the maintainer should download if from a trusted location and verify it. However, even if it is not verified at the first addition, it still enhances security in a trust-on-first-use way. It will ensure that future attacks will be detected if the key is the right one or that a current attack will be detected later, if future releases are signed by the correct key. A minimal keyring with the key with the ID

7D33D762FD6C35130481347FDB4B54CBA4826A18

can be created with the following command:

gpg2 --export --export-options export-minimal 7D33D762FD6C35130481347FDB4B54CBA4826A18 > gpgkey-7D33D762FD6C35130481347FDB4B54CBA4826A18.gpg

Eventually gpgv2 will support ascii-armored keyrings, then it will not be necessary to store a binary blob in the packaging SCM: https://bugs.gnupg.org/gnupg/issue2290

Exceptions

If the upstream tarball of a package needs to be modified, for example because it contains forbidden items, then the tarball cannot be verified as part of the build process. In this case the upstream GPG keyring must still be included in the package SCM and the instructions/script used to build the stripped down tarball needs to verify the upstream source.

If upstream signed a tarball differently, for example by signing only the uncompressed tarball but distributes a compressed version, the %setup step must the adjusted accordingly, for example:

Source0:        http://downloads.sourceforge.net/libhx/libHX-%{version}.tar.xz
Source1:        http://downloads.sourceforge.net/libhx/libHX-%{version}.tar.asc
Source2:        gpgkey-B56B8B9D9915AA8796EDC013DFFF2CDB19FC338D.gpg

# For source verification with gpgv2
BuildRequires:  gnupg2 xz

%prep
xzcat %{SOURCE0} | gpgv2 --quiet --keyring %{SOURCE2} %{SOURCE1} -
%setup -q

Design Decisions

The GPG signature is checked at the beginning of the %prep step to make sure that no compromised code runs as part of the build process. Otherwise if packages run for example ./autogen.sh the script might already be modified to do bad things.

The upstream keyring should be part of the package SCM to make sure that the trust invested in it is shared between all (co)maintainers. This way, if maintainer A added the keyring, maintainer B can trust it as well without extra effort. Also it ensures that the keyring is not accidently downloaded from a potentially compromised location.

The signature should be checked as part of the build process to make sure that all test builds in preparation of a new update are also checked and maintainers will not accidently build packages from unverified sources.

The strict format about how to do the verification ensures that it can be easily verified for correctness to make sure that there are no accidental mistakes. Also no valid reason for not checking the signature is known.

Help

If a package maintainer needs help getting their package compliant to this guideline or if they do not know what to do if a build fails because of a signature verification, they should seek help on the fedora devel mailing list before circumventing the check to make sure that they do not build compromised software.

Alternatives

Instead of storing the binary keyring in the package SCM, the armored keyring could be stored. But then it needs to be de-armored before being used by gpgv2, adding one extra line to the %setup step.

An example of how to do it would be:

Source0: https://upstream-url/%{name}-%{version}.tar.gz
Source1: https://upstream-url/%{name}-%{version}.tar.gz.asc
Source2: https://upstream-url/gpg-pub-key.asc
…
BuildRequires: gnupg2
…
%prep
gpg2 --import --import-options import-export,import-minimal %{SOURCE2} > ./gpg-keyring.gpg
gpgv2 --keyring ./gpg-keyring.gpg %{SOURCE1} %{SOURCE0}

Note, that the exact path of the keyring file must match in both commands. Without the dotslash in the second command, a keyring file in the directory ~/.gnupg will be used instead of the one generated from SOURCE2.

The above works on Fedora only. If you want something that works on EPEL7 as well, use the following gpg2 command:

gpg2 --import --import-options import-minimal --no-default-keyring --keyring ./gpg-keyring.gpg %{SOURCE2}