• [gentoo-dev] [PATCH 1/2] sec-keys.eclass: new eclass

    From Eli Schwartz@21:1/5 to All on Wed Nov 27 21:40:01 2024
    The current state of verify-sig support is a bit awkward. We rely on
    validating distfiles against a known trusted keyring, but creating the
    known trusted keyring is basically all manual verification. We somehow
    decide an ascii armored key is good enough without any portage
    assistance, then arrange to download it and trust it by Manifest hash.
    How do we know when updating a key is actually safe?

    This eclass handles the problem in a manner inspired in part by pacman.
    We require an eclass variable that lists all permitted PGP fingerprints,
    and the eclass is responsible checking that list against the keys we
    will install. It comes with a mechanism for computing SRC_URI for a
    couple of well known locations, or you can append your own in the
    ebuild.

    Key rotations, both expected and malicious, are easily detected by
    checking the git log for changes to declared finterprints in a bump. The
    former can be rationalized in the commit message. So can the latter, but
    in most cases those will be rejected during peer review.

    Signed-off-by: Eli Schwartz <eschwartz@gentoo.org>
    ---
    eclass/sec-keys.eclass | 150 +++++++++++++++++++++++++++++++++++++++++
    1 file changed, 150 insertions(+)
    create mode 100644 eclass/sec-keys.eclass

    diff --git a/eclass/sec-keys.eclass b/eclass/sec-keys.eclass
    new file mode 100644
    index 000000000000..95e1b4a92c0e
    --- /dev/null
    +++ b/eclass/sec-keys.eclass
    @@ -0,0 +1,150 @@
    +# Copyright 2024 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: sec-keys.eclass
    +# @MAINTAINER:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @AUTHOR:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Provides a uniform way of handling ebuilds which package PGP key material
    +# @DESCRIPTION:
    +# This eclass provides a streamlined approach to finding suitable source material
    +# for OpenPGP keys used by the verify-sig eclass. Its primary purpose is to permit
    +# developers to easily and securely package new sec-keys/* packages. The eclass
    +# removes the risk of developers accidentally packaging m
  • From Sam James@21:1/5 to mgorny@gentoo.org on Wed Nov 27 23:00:01 2024
    Michał Górny <mgorny@gentoo.org> writes:

    On Wed, 2024-11-27 at 15:30 -0500, Eli Schwartz wrote:
    The current state of verify-sig support is a bit awkward. We rely on
    validating distfiles against a known trusted keyring, but creating the
    known trusted keyring is basically all manual verification. We somehow
    decide an ascii armored key is good enough without any portage
    assistance, then arrange to download it and trust it by Manifest hash.
    How do we know when updating a key is actually safe?

    This eclass handles the problem in a manner inspired in part by pacman.
    We require an eclass variable that lists all permitted PGP fingerprints,
    and the eclass is responsible checking that list against the keys we
    will install. It comes with a mechanism for computing SRC_URI for a
    couple of well known locations, or you can append your own in the
    ebuild.

    How about adding a src_test() that would check if the key needs bumping,
    i.e. if an online update triggers any meaningful changes?

    Ooh, I like this idea. We could print a pgpdump diff.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?UTF-8?Q?Micha=C5=82_G=C3=B3rny?=@21:1/5 to Eli Schwartz on Wed Nov 27 22:20:02 2024
    On Wed, 2024-11-27 at 15:30 -0500, Eli Schwartz wrote:
    The current state of verify-sig support is a bit awkward. We rely on validating distfiles against a known trusted keyring, but creating the
    known trusted keyring is basically all manual verification. We somehow
    decide an ascii armored key is good enough without any portage
    assistance, then arrange to download it and trust it by Manifest hash.
    How do we know when updating a key is actually safe?

    This eclass handles the problem in a manner inspired in part by pacman.
    We require an eclass variable that lists all permitted PGP fingerprints,
    and the eclass is responsible checking that list against the keys we
    will install. It comes with a mechanism for computing SRC_URI for a
    couple of well known locations, or you can append your own in the
    ebuild.

    How about adding a src_test() that would check if the key needs bumping,
    i.e. if an online update triggers any meaningful changes?

    --
    Best regards,
    Michał Górny


    -----BEGIN PGP SIGNATURE-----

    iQFGBAABCgAwFiEEx2qEUJQJjSjMiybFY5ra4jKeJA4FAmdHi08SHG1nb3JueUBn ZW50b28ub3JnAAoJEGOa2uIyniQOxEMH/jxzRwUcVWVUGa61wIdSgb+sZRzEVnHv kUknR+yl0RfjnZ331U4gfRJPdEcrvWeviNel66Edh1R99637R0R07S4xqZNV+RUd Yjoj8opwMO0cVAKtHUkjcKF8TMsSy3nR40mmkuGSaUqQK1/fCFT5wsfkp6DfAECt PvoB9QcU+NDkVcWm+iPOS5MX4Xvx4oQ6yMMUJDHk455RtXSvR98yWN0iOwQjkA1R y7cCe8ZCAYijCg0pG3m6socerrc94Iq3G8YpQvbsdv+q6kUL/WnV5V0GTj8XNM66 qwY47M3Nclr1ml94PhvKed37p+nFuH9VCSR4YcPNinblaCSo6stK+Zo=
    =3IYH
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Sam James@21:1/5 to Eli Schwartz on Wed Nov 27 23:00:01 2024
    Eli Schwartz <eschwartz@gentoo.org> writes:

    The current state of verify-sig support is a bit awkward. We rely on validating distfiles against a known trusted keyring, but creating the
    known trusted keyring is basically all manual verification. We somehow
    decide an ascii armored key is good enough without any portage
    assistance, then arrange to download it and trust it by Manifest hash.
    How do we know when updating a key is actually safe?

    This eclass handles the problem in a manner inspired in part by pacman.
    We require an eclass variable that lists all permitted PGP fingerprints,
    and the eclass is responsible checking that list against the keys we
    will install. It comes with a mechanism for computing SRC_URI for a
    couple of well known locations, or you can append your own in the
    ebuild.

    Key rotations, both expected and malicious, are easily detected by
    checking the git log for changes to declared finterprints in a bump. The

    s/finterprints/fingerprints/

    former can be rationalized in the commit message. So can the latter, but
    in most cases those will be rejected during peer review.

    Signed-off-by: Eli Schwartz <eschwartz@gentoo.org>
    ---
    eclass/sec-keys.eclass | 150 +++++++++++++++++++++++++++++++++++++++++
    1 file changed, 150 insertions(+)
    create mode 100644 eclass/sec-keys.eclass


    I'm actually pleasantly surprised by how elegant this is -- which is no reflection on you, just I sort of assumed the implementation would have
    to be a bit gnarlier (not sure why).

    One thing I really want to solve in general is key refreshes, given we
    have no "src_fetch", users can't opt in to key refreshes even with verify-sig.eclass unless network-sandbox is off, but that's a separate
    problem. mgorny's suggestion wrt src_test would allow us to even
    tinderbox needed refreshes which somewhat solves that problem too.

    I like it.

    diff --git a/eclass/sec-keys.eclass b/eclass/sec-keys.eclass
    new file mode 100644
    index 000000000000..95e1b4a92c0e
    --- /dev/null
    +++ b/eclass/sec-keys.eclass
    @@ -0,0 +1,150 @@
    +# Copyright 2024 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: sec-keys.eclass
    +# @MAINTAINER:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @AUTHOR:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Provides a uniform way of handling ebuilds which package PGP key material
    +# @DESCRIPTION:
    +# This eclass provides a streamlined approach to finding suitable source material
    +# for OpenPGP keys used by the verify-sig eclass. Its primary purpose is to permit
    +# developers to easily and securely package new sec-keys/* packages. The eclass
    +# removes the risk of developers accidentally packaging malformed key material, or
    +# neglecting to notice when PGP identities have changed.
    +#
    +# To use the eclass, define SEC_KEYS_VALIDPGPKEYS to contain the fingerprint of
    +# the key and the short name of the key's owner.
    +#
    +# @EXAMPLE:
    +# Example use:
    +#
    +# @CODE
    +# SEC_KEYS_VALIDPGPKEYS=(
    +# '4EC8A4DB7D2E01C00AF36C49E5C587B5E286C65A:jsmith:github'
    +# )

    Can you expand the example(s) here maybe with some comments in the array
    to help people see when it might be suitable to use e.g. none with a mix
    of github?

    +#
    +# inherit sec-keys
    +# @CODE
    +
    +case ${EAPI} in
    + 8) ;;
    + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
    +esac
    +
    +if [[ ! ${_SEC_KEYS_ECLASS} ]]; then
    +_SEC_KEYS_ECLASS=1
    +
    +inherit edo
    +
    +# @ECLASS_VARIABLE: SEC_KEYS_VALIDPGPKEYS
    +# @PRE_INHERIT
    +# @DEFAULT_UNSET
    +# @DESCRIPTION:
    +# Mapping of fingerprints, name, and optional location of PGP keys to include,
    +# separated by colons. The allowed values for a location are:
    +#
    +# - github -- fetch key from github.com/${name}.pgp
    +#
    +# - openpgp -- fetch key by fingerprint from https://keys.openpgp.org
    +#
    +# - ubuntu -- fetch key by fingerprint from http://keyserver.ubuntu.com (the default)
    +#
    +# - none -- do not add to SRC_URI, the ebuild will provide a custom download location
    +_sec_keys_set_globals() {
    + if [[ ${SEC_KEYS_VALIDPGPKEYS[*]} ]]; then
    + local key fingerprint name loc locations=() remote
    + for key in "${SEC_KEYS_VALIDPGPKEYS[@]}"; do
    + fingerprint=${key%%:*}
    + name=${key#${fingerprint}:}; name=${name%%:*}
    + IFS=: read -r -a locations <<<"${key##*:}"
    + [[ ${locations[@]} ]] || locations=(ubuntu)
    + for loc in "${locations[@]}"; do
    + case ${loc} in
    + github) remote="https://github.com/${name}.gpg";;
    + openpgp) remote="https://keys.openpgp.org/vks/v1/by-fingerprint/${fingerprint}";;
    + ubuntu) remote="https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${fingerprint}";;
    + # provided via manual SRC_URI
    + none) continue;;
    + *) die "${ECLASS}: unknown PGP key remote: ${loc}";;
    +
    + esac
    + SRC_URI+="
    + ${remote} -> openpgp-keys-${name}-${loc}-${PV}.asc
    + "
    + done
    + done
    + fi
    +}
    +_sec_keys_set_globals
    +unset -f _sec_keys_set_globals
    +
    +BDEPEND="app-crypt/gnupg"
    +S=${WORKDIR}
    +
    +LICENSE="public-domain"
    +SLOT="0"
    +
    +
    +# @FUNCTION: sec-keys_src_compile
    +# @DESCRIPTION:
    +# Default src_compile override that imports all public keys into a keyring, +# and validates that they are listed in SEC_KEYS_VALIDPGPKEYS. +sec-keys_src_compile() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + mkdir -m700 -p "${GNUPGHOME}" || die

    Is there any value in using gemato's gpg-wrap for this function?

    +
    + pushd "${DISTDIR}" >/dev/null || die
    + gpg --import ${A} || die
    + popd >/dev/null || die
    +
    + local line imported_keys=() found=0
    + while IFS=: read -r -a line; do
    + if [[ ${line[0]} = pub ]]; then
    + # new key
    + found=0
    + elif [[ ${found} = 0 && ${line[0]} = fpr ]]; then
    + # primary fingerprint
    + imported_keys+=("${line[9]}")
    + found=1
    + fi
    + done < <(gpg --batch --list-keys --keyid-format=long --with-colons || die)
    +
    + printf '%s\n' "${imported_keys[@]}" | sort > imported_keys.list || die + printf '%s\n' "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}" | sort > allowed_keys.list || die
    +
    + local extra_keys=($(comm -23 imported_keys.list allowed_keys.list || die))
    + local missing_keys=($(comm -13 imported_keys.list allowed_keys.list || die))

    Any reason to not readarray this instead?

    +
    + if [[ ${#extra_keys[@]} != 0 ]]; then
    + die "too many keys found. Suspicious keys: ${extra_keys[@]}"
    + fi
    + if [[ ${#missing_keys[@]} != 0 ]]; then
    + die "too few keys found. Unavailable keys: ${missing_keys[@]}" + fi
    +}
    +
    +# @FUNCTION: sec-keys_src_install
    +# @DESCRIPTION:
    +# Default src_install override that minifies and exports all PGP public keys +# into an ascii-armored keyfile installed to the standard /usr/share/openpgp-keys.
    +sec-keys_src_install() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local fingerprint
    + local gpg_command=(gpg --no-permission-warning --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + local uids=()
    + mapfile -t uids < <("${gpg_command[@]}" --list-key --with-colons ${fingerprint} | awk -F: '/^uid/{print $10}' || die)
    + edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc || die

    No need for the die here.

    + done
    +
    + insinto /usr/share/openpgp-keys
    + doins ${PN#openpgp-keys-}.asc
    +}
    +
    +fi
    +
    +EXPORT_FUNCTIONS src_compile src_install

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eli Schwartz@21:1/5 to All on Thu Nov 28 05:30:01 2024
    This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --------------LzA3rrxrTzGhBznGr7OE0MVd
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: quoted-printable

    On 11/27/24 4:12 PM, Michał Górny wrote:
    On Wed, 2024-11-27 at 15:30 -0500, Eli Schwartz wrote:
    The current state of verify-sig support is a bit awkward. We rely on
    validating distfiles against a known trusted keyring, but creating the
    known trusted keyring is basically all manual verification. We somehow
    decide an ascii armored key is good enough without any portage
    assistance, then arrange to download it and trust it by Manifest hash.
    How do we know when updating a key is actually safe?

    This eclass handles the problem in a manner inspired in part by pacman.
    We require an eclass variable that lists all permitted PGP fingerprints,
    and the eclass is responsible checking that list against the keys we
    will install. It comes with a mechanism for computing SRC_URI for a
    couple of well known locations, or you can append your own in the
    ebuild.

    How about adding a src_test() that would check if the key needs bumping,
    i.e. if an online update triggers any meaningful changes?


    This is a really nice suggestion. I used Sam's tip about pgpdump, so
    that we print a diff after the online update, and fail if diff produces
    a diff.

    We use a cleaned and minimized version of the key, so it will only
    show/trigger on changes to the uid or self-sig packets, which isn't
    exactly the same as "meaningful changes". For example, running the tests
    on the gnutls keyring in the second patch, Daiki's key has been updated
    on Ubuntu with an additional expiry date change for a secondary uid,
    which may be meaningful in certain senses but we can validate it just
    fine using the primary uid.


    --
    Eli Schwartz

    --------------LzA3rrxrTzGhBznGr7OE0MVd--

    -----BEGIN PGP SIGNATURE-----

    wnsEABYIACMWIQTnFNnmK0TPZHnXm3qEp9ErcA0vVwUCZ0fwlQUDAAAAAAAKCRCEp9ErcA0vVxUQ AQCoYJs9aWG0zy1Bi3X7M+vOcEYS5udJMaegqFPJKCutggD/ZkvXqbCZRrokfd8qDYR+OAalZed2 z0A7jfZAD9ZtUgQ=
    =CPfj
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eli Schwartz@21:1/5 to Sam James on Thu Nov 28 05:20:01 2024
    Copy: gentoo-dev@lists.gentoo.org

    This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --------------LLYwgcOUprV5g0x91Fk8Spa0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: quoted-printable

    On 11/27/24 4:57 PM, Sam James wrote:
    Eli Schwartz <eschwartz@gentoo.org> writes:
    +# @EXAMPLE:
    +# Example use:
    +#
    +# @CODE
    +# SEC_KEYS_VALIDPGPKEYS=(
    +# '4EC8A4DB7D2E01C00AF36C49E5C587B5E286C65A:jsmith:github'
    +# )

    Can you expand the example(s) here maybe with some comments in the array
    to help people see when it might be suitable to use e.g. none with a mix
    of github?


    Sure, good idea.


    +# @FUNCTION: sec-keys_src_compile
    +# @DESCRIPTION:
    +# Default src_compile override that imports all public keys into a keyring, >> +# and validates that they are listed in SEC_KEYS_VALIDPGPKEYS.
    +sec-keys_src_compile() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + mkdir -m700 -p "${GNUPGHOME}" || die

    Is there any value in using gemato's gpg-wrap for this function?


    I don't think so. The main use case for gemato that I see is it
    automatically entering a tempdir context based on a keyfile. We need to
    support multiple keyfiles, including ebuild-specified SRC_URI that may
    not be ascii-armored and cannot be concatenated together, which means in
    order to get to a point where gpg-wrap can be used to run one-off
    commands using a keyfile in which gemato wraps the creation of a
    keyring... we've basically done all the work we actually wanted to do.


    + local extra_keys=($(comm -23 imported_keys.list allowed_keys.list || die))
    + local missing_keys=($(comm -13 imported_keys.list allowed_keys.list || die))

    Any reason to not readarray this instead?


    The files each contain a list of words (PGP fingerprint, consisting of characters matching [0-9A-F] and nothing else), with the only whitspace
    in the file being newline characters.

    Both readarray and command substitution tokenize this the same. I'm not
    sure it particularly matters which one to use, but command substitution
    can be done on one line (local variable=($(command || die)) ) whereas
    readarray requires two lines (local -a variable; readarray -t varlist < <(command || die) ) and you have to remember to use -t and -a.

    I don't think readarray provides any functionality we need here.


    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + local uids=()
    + mapfile -t uids < <("${gpg_command[@]}" --list-key --with-colons ${fingerprint} | awk -F: '/^uid/{print $10}' || die)
    + edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc || die

    No need for the die here.


    Right, I probably forgot to remove this when I switched to edo.



    --
    Eli Schwartz

    --------------LLYwgcOUprV5g0x91Fk8Spa0--

    -----BEGIN PGP SIGNATURE-----

    wnsEABYIACMWIQTnFNnmK0TPZHnXm3qEp9ErcA0vVwUCZ0fu3AUDAAAAAAAKCRCEp9ErcA0vV2Zs AP9MTo2j8q9MwUcC5vOeDZVjXzw10mHNApcnQZfRWnPPgQD/QNImdJC4ID06oTSmSeDFn62Y2/I9 YJ9AiKOTqHiBtwY=
    =J42X
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eli Schwartz@21:1/5 to All on Thu Nov 28 05:40:02 2024
    v2 changes:

    - add src_test
    - add support for gentoo keyserver
    - fix small typo in handling multiple sources
    - remove outdated die based on review

    Eli Schwartz (2):
    sec-keys.eclass: new eclass
    sec-keys/openpgp-keys-gnutls: update to use sec-keys.eclass

    eclass/sec-keys.eclass | 197 ++++++++++++++++++
    sec-keys/openpgp-keys-gnutls/Manifest | 1 +
    .../openpgp-keys-gnutls-20240415-r1.ebuild | 22 ++
    3 files changed, 220 insertions(+)
    create mode 100644 eclass/sec-keys.eclass
    create mode 100644 sec-keys/openpgp-keys-gnutls/openpgp-keys-gnutls-20240415-r1.ebuild

    Range-diff against v1:
    1: 02c47372ec21 ! 1: 6777dbb541bf sec-keys.eclass: new eclass
    @@ Commit message
    ebuild.

    Key rotations, both expected and malicious, are easily detected by
    - checking the git log for changes to declared finterprints in a bump. The
    + checking the git log for changes to declared fingerprints in a bump. The
    former can be rationalized in the commit message. So can the latter, but
    in most cases those will be rejected during peer review.

    @@ eclass/sec-keys.eclass (new)
    +#
    +# @CODE
    +# SEC_KEYS_VALIDPGPKEYS=(
    -+# '4EC8A4DB7D2E01C00AF36C49E5C587B5E286C65A:jsmith:github'
    ++# # implicit Ubuntu
    ++# '3DB7F3CA6C1D90B99FE25B38D4B476A4D175C54F:bjones:'
    ++# '4EC8A4DB7D2E01C00AF36C49E5C587B5E286C65A:jsmith:github,openpgp'
    ++# # key only available on personal website, use manual SRC_URI
    ++# '5FD9B5EC8E3F12D11BA47D50F6D698C6F397D76B:awhite:none'
    +# )
    +#
    +# inherit sec-keys
    ++#
    ++# SRC_URI+="https://awhite.com/awhite.gpg -> awhite-${PV}.gpg"
    +# @CODE
    +
    +case ${EAPI} in
    @@ eclass/sec-keys.eclass (new)
    +# Mapping of fingerprints, name, and optional location of PGP keys to include,
    +# separated by colons. The allowed values for a location are:
    +#
    ++# - gentoo -- fetch key by fingerprint from https://keys.gentoo.org
    ++#
    +# - github -- fetch key from github.com/${name}.pgp
    +#
    +# - openpgp -- fetch key by fingerprint from https://keys.openpgp.org
    @@ eclass/sec-keys.eclass (new)
    + for key in "${SEC_KEYS_VALIDPGPKEYS[@]}"; do
    + fingerprint=${key%%:*}
    + name=${key#${fingerprint}:}; name=${name%%:*}
    -+ IFS=: read -r -a locations <<<"${key##*:}"
    ++ IFS=, read -r -a locations <<<"${key##*:}"
    + [[ ${locations[@]} ]] || locations=(ubuntu)
    + for loc in "${locations[@]}"; do
    + case ${loc} in
    ++ gentoo) remote="https://keys.gentoo.org/pks/lookup?op=get&search=0x${fingerprint}";;
    + github) remote="https://github.com/${name}.gpg";;
    + openpgp) remote="https://keys.openpgp.org/vks/v1/by-fingerprint/${fingerprint}";;
    + ubuntu) remote="https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${fingerprint}";;
    @@ eclass/sec-keys.eclass (new)
    +_sec_keys_set_globals
    +unset -f _sec_keys_set_globals
    +
    -+BDEPEND="app-crypt/gnupg"
    ++IUSE="test"
    ++PROPERTIES="test_network"
    ++RESTRICT="test"
    ++
    ++BDEPEND="
    ++ app-crypt/gnupg
    ++ test? ( app-crypt/pgpdump )
    ++"
    +S=${WORKDIR}
    +
    +LICENSE="public-domain"
    @@ eclass/sec-keys.eclass (new)
    + fi
    +}
    +
    ++
    ++sec-keys_src_test() {
    ++ local -x GNUPGHOME=${WORKDIR}/gnupg
    ++ local key fingerprint name server
    ++ local gpg_command=(gpg --export-options export-minimal)
    ++
    ++ for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    ++ "${gpg_command[@]}" --export "${fingerprint}" | pgpdump > "${fingerprint}.pgpdump" || die
    ++ done
    ++
    ++ # Best-effort attempt to check for updates. keyservers can and usually do
    ++ # fail for weird reasons, (such as being unable to import a key without a
    ++ # uid) as well as normal reasons, like the key being exclusive to a
    ++ # different keyserver. this isn't a reason to fail src_test.
    ++ for server in keys.gentoo.org keys.openpgp.org keyserver.ubuntu.com; do
    ++ gpg --refresh-keys --keyserver "hkps://${server}"
    ++ done
    ++ for key in "${SEC_KEYS_VALIDPGPKEYS[@]}"; do
    ++ if [[ ${key##*:} = *github* ]]; then
    ++ name=${key#*:}; name=${name%%:*}
    ++ wget -qO- https://github.com/${name}.gpg | gpg --import || die
    ++ fi
    ++ done
    ++
    ++ for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    ++ "${gpg_command[@]}" --export "${fingerprint}" | pgpdump > "${fingerprint}.pgpdump.new" || die
    ++ diff -u "${fingerprint}.pgpdump" "${fingerprint}.pgpdump.new" || die "updates available for PGP key: ${fingerprint}"
    ++ done
    ++
    ++}
    ++
    +# @FUNCTION: sec-keys_src_install
    +# @DESCRIPTION:
    +# Default src_install override that minifies and exports all PGP public keys
    @@ eclass/sec-keys.eclass (new)
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + local uids=()
    + mapfile -t uids < <("${gpg_command[@]}" --list-key --with-colons ${fingerprint} | awk -F: '/^uid/{print $10}' || die)
    -+ edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc || die
    ++ edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc
    + done
    +
    + insinto /usr/share/openpgp-keys
    @@ eclass/sec-keys.eclass (new)
    +
    +fi
    +
    -+EXPORT_FUNCTIONS src_compile src_install
    ++EXPORT_FUNCTIONS src_compile src_test src_install
    2: 0060997db9cb = 2: 2f78bceaed3b sec-keys/openpgp-keys-gnutls: update to use sec-keys.eclass
    --
    2.45.2

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From =?utf-8?Q?Ulrich_M=C3=BCller?=@21:1/5 to All on Thu Nov 28 11:40:01 2024
    On Wed, 27 Nov 2024, Eli Schwartz wrote:

    --- /dev/null
    +++ b/eclass/sec-keys.eclass
    @@ -0,0 +1,150 @@
    +# Copyright 2024 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: sec-keys.eclass
    +# @MAINTAINER:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @AUTHOR:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Provides a uniform way of handling ebuilds which package PGP key material
    +# @DESCRIPTION:
    +# This eclass provides a streamlined approach to finding suitable source material
    +# for OpenPGP keys used by the verify-sig eclass. Its primary purpose is to permit
    +# developers to easily and securely package new sec-keys/* packages. The eclass
    +# removes the risk of developers accidentally packaging malformed key material, or
    +# neglecting to notice when PGP identities have changed.
    +#
    +# To use the eclass, define SEC_KEYS_VALIDPGPKEYS to contain the fingerprint of
    +# the key and the short name of the key's owner.

    Please wrap these comment lines to a line length of 70-ish characters
    for readability.

    Also, there should be two spaces after every full stop (except when it's followed by a newline), so groff can recognise the sentence end in the generated man page.

    +#
    +# @EXAMPLE:
    +# Example use:
    +#
    +# @CODE
    +# SEC_KEYS_VALIDPGPKEYS=(
    +# '4EC8A4DB7D2E01C00AF36C49E5C587B5E286C65A:jsmith:github'
    +# )
    +#
    +# inherit sec-keys
    +# @CODE
    +
    +case ${EAPI} in
    + 8) ;;
    + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
    +esac
    +
    +if [[ ! ${_SEC_KEYS_ECLASS} ]]; then
    +_SEC_KEYS_ECLASS=1
    +
    +inherit edo
    +
    +# @ECLASS_VARIABLE: SEC_KEYS_VALIDPGPKEYS
    +# @PRE_INHERIT
    +# @DEFAULT_UNSET
    +# @DESCRIPTION:
    +# Mapping of fingerprints, name, and optional location of PGP keys to include,
    +# separated by colons. The allowed values for a location are:
    +#
    +# - github -- fetch key from github.com/${name}.pgp
    +#
    +# - openpgp -- fetch key by fingerprint from https://keys.openpgp.org
    +#
    +# - ubuntu -- fetch key by fingerprint from http://keyserver.ubuntu.com (the default)
    +#
    +# - none -- do not add to SRC_URI, the ebuild will provide a custom download location
    +_sec_keys_set_globals() {
    + if [[ ${SEC_KEYS_VALIDPGPKEYS[*]} ]]; then

    Why is the if needed? If the array is empty, the following for loop
    won't execute.

    + local key fingerprint name loc locations=() remote
    + for key in "${SEC_KEYS_VALIDPGPKEYS[@]}"; do
    + fingerprint=${key%%:*}
    + name=${key#${fingerprint}:}; name=${name%%:*}
    + IFS=: read -r -a locations <<<"${key##*:}"
    + [[ ${locations[@]} ]] || locations=(ubuntu)
    + for loc in "${locations[@]}"; do
    + case ${loc} in
    + github) remote="https://github.com/${name}.gpg";;
    + openpgp) remote="https://keys.openpgp.org/vks/v1/by-fingerprint/${fingerprint}";;
    + ubuntu) remote="https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x${fingerprint}";;
    + # provided via manual SRC_URI
    + none) continue;;
    + *) die "${ECLASS}: unknown PGP key remote: ${loc}";;
    +
    + esac
    + SRC_URI+="
    + ${remote} -> openpgp-keys-${name}-${loc}-${PV}.asc
    + "
    + done
    + done
    + fi
    +}
    +_sec_keys_set_globals
    +unset -f _sec_keys_set_globals
    +
    +BDEPEND="app-crypt/gnupg"
    +S=${WORKDIR}
    +
    +LICENSE="public-domain"
    +SLOT="0"
    +
    +
    +# @FUNCTION: sec-keys_src_compile
    +# @DESCRIPTION:
    +# Default src_compile override that imports all public keys into a keyring, +# and validates that they are listed in SEC_KEYS_VALIDPGPKEYS. +sec-keys_src_compile() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + mkdir -m700 -p "${GNUPGHOME}" || die
    +
    + pushd "${DISTDIR}" >/dev/null || die
    + gpg --import ${A} || die
    + popd >/dev/null || die
    +
    + local line imported_keys=() found=0
    + while IFS=: read -r -a line; do
    + if [[ ${line[0]} = pub ]]; then
    + # new key
    + found=0
    + elif [[ ${found} = 0 && ${line[0]} = fpr ]]; then
    + # primary fingerprint
    + imported_keys+=("${line[9]}")
    + found=1
    + fi
    + done < <(gpg --batch --list-keys --keyid-format=long --with-colons || die)
    +
    + printf '%s\n' "${imported_keys[@]}" | sort > imported_keys.list || die + printf '%s\n' "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}" | sort > allowed_keys.list || die

    Maybe create these files in ${T} instead?

    +
    + local extra_keys=($(comm -23 imported_keys.list allowed_keys.list || die))
    + local missing_keys=($(comm -13 imported_keys.list allowed_keys.list || die))
    +
    + if [[ ${#extra_keys[@]} != 0 ]]; then
    + die "too many keys found. Suspicious keys: ${extra_keys[@]}"
    + fi
    + if [[ ${#missing_keys[@]} != 0 ]]; then
    + die "too few keys found. Unavailable keys: ${missing_keys[@]}" + fi
    +}
    +
    +# @FUNCTION: sec-keys_src_install
    +# @DESCRIPTION:
    +# Default src_install override that minifies and exports all PGP public keys +# into an ascii-armored keyfile installed to the standard /usr/share/openpgp-keys.
    +sec-keys_src_install() {
    + local -x GNUPGHOME=${WORKDIR}/gnupg
    + local fingerprint
    + local gpg_command=(gpg --no-permission-warning --export-options export-minimal)
    +
    + for fingerprint in "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}"; do
    + local uids=()
    + mapfile -t uids < <("${gpg_command[@]}" --list-key --with-colons ${fingerprint} | awk -F: '/^uid/{print $10}' || die)
    + edo "${gpg_command[@]}" "${uids[@]/#/--comment=}" --export --armor "${fingerprint}" >> ${PN#openpgp-keys-}.asc || die

    edo dies by itself, so "|| die" is not needed.

    + done
    +
    + insinto /usr/share/openpgp-keys
    + doins ${PN#openpgp-keys-}.asc
    +}
    +
    +fi
    +
    +EXPORT_FUNCTIONS src_compile src_install

    -----BEGIN PGP SIGNATURE-----

    iQFDBAEBCAAtFiEEtDnZ1O9xIP68rzDbUYgzUIhBXi4FAmdIR3UPHHVsbUBnZW50 b28ub3JnAAoJEFGIM1CIQV4usqYH/28Pnycn6Uk3HlW/CQNR1DZ7Iqg2KvHDrC9l RhfNu5Hs1SvF8KvUgOSgEZqlDHCO8DyqkiIt3JOBRJyO5HDwgHvof+OLI1nvifcE XVgLo358M+yL9I5l672tYeyRiM6THNIUdjZ1R/veY1wJ0WxXjaIJGa0Twuf1QzTa C8tPZ2m1981E07f2hfmdu+UjKt3xKFAl6abeRlhT/7v3fRcrPbmh4PeP2MDqpcNm dvmscE0iwN/5B7uhwUcjQJWXTzOJoy09WtcAH7ixZLUi9mxHGfbbeuVy2AZT4gRV ZyDaWLx0vBr8LObMbLK+pj9LVP747rrBuSDwZ/AsvkxZlYlB9qw=
    =2XSq
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Eli Schwartz@21:1/5 to All on Thu Nov 28 16:40:02 2024
    This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --------------lLAdaQRCsdKwYxnNNU9Lgn0W
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: quoted-printable

    On 11/28/24 5:35 AM, Ulrich Müller wrote:
    On Wed, 27 Nov 2024, Eli Schwartz wrote:

    --- /dev/null
    +++ b/eclass/sec-keys.eclass
    @@ -0,0 +1,150 @@
    +# Copyright 2024 Gentoo Authors
    +# Distributed under the terms of the GNU General Public License v2
    +
    +# @ECLASS: sec-keys.eclass
    +# @MAINTAINER:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @AUTHOR:
    +# Eli Schwartz <eschwartz@gentoo.org>
    +# @SUPPORTED_EAPIS: 8
    +# @BLURB: Provides a uniform way of handling ebuilds which package PGP key material
    +# @DESCRIPTION:
    +# This eclass provides a streamlined approach to finding suitable source material
    +# for OpenPGP keys used by the verify-sig eclass. Its primary purpose is to permit
    +# developers to easily and securely package new sec-keys/* packages. The eclass
    +# removes the risk of developers accidentally packaging malformed key material, or
    +# neglecting to notice when PGP identities have changed.
    +#
    +# To use the eclass, define SEC_KEYS_VALIDPGPKEYS to contain the fingerprint of
    +# the key and the short name of the key's owner.

    Please wrap these comment lines to a line length of 70-ish characters
    for readability.

    Also, there should be two spaces after every full stop (except when it's followed by a newline), so groff can recognise the sentence end in the generated man page.


    I usually do 80-ish for readability! Okay, I can do 70 too. :) Thanks
    for the tip about the spaces, I don't usually write groff by hand.
    Surprising that groff cannot handle this automatically, though.


    +_sec_keys_set_globals() {
    + if [[ ${SEC_KEYS_VALIDPGPKEYS[*]} ]]; then

    Why is the if needed? If the array is empty, the following for loop
    won't execute.


    Not sure, perhaps an artifact of a previous revision that had different handling. Let's remove it.


    + printf '%s\n' "${imported_keys[@]}" | sort > imported_keys.list || die >> + printf '%s\n' "${SEC_KEYS_VALIDPGPKEYS[@]%%:*}" | sort > allowed_keys.list || die

    Maybe create these files in ${T} instead?


    I'm not sure this is an important distinction. It's the main thing the
    package works on. I could put GNUPGHOME in ${T} as well, if you like? :)

    But keeping it in ${WORKDIR} makes it more straightforward for people to
    look at manually when a failed build happens. And that's important when
    dealing with the primary logic of a package (there's no source code to
    compile here).



    --
    Eli Schwartz

    --------------lLAdaQRCsdKwYxnNNU9Lgn0W--

    -----BEGIN PGP SIGNATURE-----

    wnsEABYIACMWIQTnFNnmK0TPZHnXm3qEp9ErcA0vVwUCZ0iODQUDAAAAAAAKCRCEp9ErcA0vVyLp AP41euZbZXGdM8rZ227eSxpp2VCGpl3NkNWo5YBRMbg88gEA+SdUDaXSPANwomDwNYPPHo/+CTtp EAsv+W7MqnNu1gE=
    =dfLS
    -----END PGP SIGNATURE-----

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)