diff --git a/sdk_container/src/third_party/portage-stable/eclass/verify-sig.eclass b/sdk_container/src/third_party/portage-stable/eclass/verify-sig.eclass new file mode 100644 index 0000000000..e3ef7f2402 --- /dev/null +++ b/sdk_container/src/third_party/portage-stable/eclass/verify-sig.eclass @@ -0,0 +1,271 @@ +# Copyright 2020 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: verify-sig.eclass +# @MAINTAINER: +# Michał Górny +# @SUPPORTED_EAPIS: 7 +# @BLURB: Eclass to verify upstream signatures on distfiles +# @DESCRIPTION: +# verify-sig eclass provides a streamlined approach to verifying +# upstream signatures on distfiles. Its primary purpose is to permit +# developers to easily verify signatures while bumping packages. +# The eclass removes the risk of developer forgetting to perform +# the verification, or performing it incorrectly, e.g. due to additional +# keys in the local keyring. It also permits users to verify +# the developer's work. +# +# To use the eclass, start by packaging the upstream's key +# as app-crypt/openpgp-keys-*. Then inherit the eclass, add detached +# signatures to SRC_URI and set VERIFY_SIG_OPENPGP_KEY_PATH. The eclass +# provides verify-sig USE flag to toggle the verification. +# +# Example use: +# @CODE +# inherit verify-sig +# +# SRC_URI="https://example.org/${P}.tar.gz +# verify-sig? ( https://example.org/${P}.tar.gz.sig )" +# BDEPEND=" +# verify-sig? ( app-crypt/openpgp-keys-example )" +# +# VERIFY_SIG_OPENPGP_KEY_PATH=/usr/share/openpgp-keys/example.asc +# @CODE + +case "${EAPI:-0}" in + 0|1|2|3|4|5|6) + die "Unsupported EAPI=${EAPI} (obsolete) for ${ECLASS}" + ;; + 7) + ;; + *) + die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}" + ;; +esac + +EXPORT_FUNCTIONS src_unpack + +if [[ ! ${_VERIFY_SIG_ECLASS} ]]; then + +IUSE="verify-sig" + +BDEPEND=" + verify-sig? ( + app-crypt/gnupg + >=app-portage/gemato-16 + )" + +# @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEY_PATH +# @DEFAULT_UNSET +# @DESCRIPTION: +# Path to key bundle used to perform the verification. This is required +# when using default src_unpack. Alternatively, the key path can be +# passed directly to the verification functions. + +# @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEYSERVER +# @DEFAULT_UNSET +# @DESCRIPTION: +# Keyserver used to refresh keys. If not specified, the keyserver +# preference from the key will be respected. If no preference +# is specified by the key, the GnuPG default will be used. + +# @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEY_REFRESH +# @USER_VARIABLE +# @DESCRIPTION: +# Attempt to refresh keys via WKD/keyserver. Set it to "yes" +# in make.conf to enable. Note that this requires working Internet +# connection. +: ${VERIFY_SIG_OPENPGP_KEY_REFRESH:=no} + +# @FUNCTION: verify-sig_verify_detached +# @USAGE: [] +# @DESCRIPTION: +# Read the detached signature from and verify against +# it. can either be passed directly, or it defaults +# to VERIFY_SIG_OPENPGP_KEY_PATH. The function dies if verification +# fails. +verify-sig_verify_detached() { + local file=${1} + local sig=${2} + local key=${3:-${VERIFY_SIG_OPENPGP_KEY_PATH}} + + [[ -n ${key} ]] || + die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset" + + local extra_args=() + [[ ${VERIFY_SIG_OPENPGP_KEY_REFRESH} == yes ]] || extra_args+=( -R ) + [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]] && extra_args+=( + --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}" + ) + + # GPG upstream knows better than to follow the spec, so we can't + # override this directory. However, there is a clean fallback + # to GNUPGHOME. + addpredict /run/user + + local filename=${file##*/} + [[ ${file} == - ]] && filename='(stdin)' + einfo "Verifying ${filename} ..." + gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \ + gpg --verify "${sig}" "${file}" || + die "PGP signature verification failed" +} + +# @FUNCTION: verify-sig_verify_message +# @USAGE: [] +# @DESCRIPTION: +# Verify that the file ('-' for stdin) contains a valid, signed PGP +# message and write the message into ('-' for stdout). +# can either be passed directly, or it defaults +# to VERIFY_SIG_OPENPGP_KEY_PATH. The function dies if verification +# fails. Note that using output from is important as it +# prevents the injection of unsigned data. +verify-sig_verify_message() { + local file=${1} + local output_file=${2} + local key=${3:-${VERIFY_SIG_OPENPGP_KEY_PATH}} + + [[ -n ${key} ]] || + die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset" + + local extra_args=() + [[ ${VERIFY_SIG_OPENPGP_KEY_REFRESH} == yes ]] || extra_args+=( -R ) + [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]] && extra_args+=( + --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}" + ) + + # GPG upstream knows better than to follow the spec, so we can't + # override this directory. However, there is a clean fallback + # to GNUPGHOME. + addpredict /run/user + + local filename=${file##*/} + [[ ${file} == - ]] && filename='(stdin)' + einfo "Verifying ${filename} ..." + gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \ + gpg --verify --output="${output_file}" "${file}" || + die "PGP signature verification failed" +} + +# @FUNCTION: verify-sig_verify_signed_checksums +# @USAGE: [] +# @DESCRIPTION: +# Verify the checksums for all files listed in the space-separated list +# (akin to ${A}) using a PGP-signed . +# specified the checksum algorithm (e.g. sha256). can either +# be passed directly, or it defaults to VERIFY_SIG_OPENPGP_KEY_PATH. +# +# The function dies if PGP verification fails, the checksum file +# contains unsigned data, one of the files do not match checksums +# or are missing from the checksum file. +verify-sig_verify_signed_checksums() { + local checksum_file=${1} + local algo=${2} + local files=() + read -r -d '' -a files <<<"${3}" + local key=${4:-${VERIFY_SIG_OPENPGP_KEY_PATH}} + + local chksum_prog chksum_len + case ${algo} in + sha256) + chksum_prog=sha256sum + chksum_len=64 + ;; + *) + die "${FUNCNAME}: unknown checksum algo ${algo}" + ;; + esac + + [[ -n ${key} ]] || + die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset" + + local checksum filename junk ret=0 count=0 + while read -r checksum filename junk; do + [[ ${#checksum} -eq ${chksum_len} ]] || continue + [[ -z ${checksum//[0-9a-f]} ]] || continue + has "${filename}" "${files[@]}" || continue + [[ -z ${junk} ]] || continue + + "${chksum_prog}" -c --strict - <<<"${checksum} ${filename}" + if [[ ${?} -eq 0 ]]; then + (( count++ )) + else + ret=1 + fi + done < <(verify-sig_verify_message "${checksum_file}" - "${key}") + + [[ ${ret} -eq 0 ]] || + die "${FUNCNAME}: at least one file did not verify successfully" + [[ ${count} -eq ${#files[@]} ]] || + die "${FUNCNAME}: checksums for some of the specified files were missing" +} + +# @FUNCTION: verify-sig_src_unpack +# @DESCRIPTION: +# Default src_unpack override that verifies signatures for all +# distfiles if 'verify-sig' flag is enabled. The function dies if any +# of the signatures fails to verify or if any distfiles are not signed. +# Please write src_unpack() yourself if you need to perform partial +# verification. +verify-sig_src_unpack() { + if use verify-sig; then + local f suffix found + local distfiles=() signatures=() nosigfound=() straysigs=() + + # find all distfiles and signatures, and combine them + for f in ${A}; do + found= + for suffix in .asc .sig; do + if [[ ${f} == *${suffix} ]]; then + signatures+=( "${f}" ) + found=sig + break + else + if has "${f}${suffix}" ${A}; then + distfiles+=( "${f}" ) + found=dist+sig + break + fi + fi + done + if [[ ! ${found} ]]; then + nosigfound+=( "${f}" ) + fi + done + + # check if all distfiles are signed + if [[ ${#nosigfound[@]} -gt 0 ]]; then + eerror "The following distfiles lack detached signatures:" + for f in "${nosigfound[@]}"; do + eerror " ${f}" + done + die "Unsigned distfiles found" + fi + + # check if there are no stray signatures + for f in "${signatures[@]}"; do + if ! has "${f%.*}" "${distfiles[@]}"; then + straysigs+=( "${f}" ) + fi + done + if [[ ${#straysigs[@]} -gt 0 ]]; then + eerror "The following signatures do not match any distfiles:" + for f in "${straysigs[@]}"; do + eerror " ${f}" + done + die "Unused signatures found" + fi + + # now perform the verification + for f in "${signatures[@]}"; do + verify-sig_verify_detached \ + "${DISTDIR}/${f%.*}" "${DISTDIR}/${f}" + done + fi + + # finally, unpack the distfiles + default_src_unpack +} + +_VERIFY_SIG_ECLASS=1 +fi