Gentoo Archives: gentoo-dev

From: "Michał Górny" <mgorny@g.o>
To: gentoo-dev@l.g.o
Cc: "Michał Górny" <mgorny@g.o>
Subject: [gentoo-dev] [PATCH] verify-sig.eclass: Enable EAPI 8 support
Date: Tue, 29 Jun 2021 10:01:00
Message-Id: 20210629100050.6859-1-mgorny@gentoo.org
1 No changes beside EAPI guards, full eclass included for review
2 convenience.
3
4 Signed-off-by: Michał Górny <mgorny@g.o>
5 ---
6 eclass/verify-sig.eclass | 16 +++++-----------
7 1 file changed, 5 insertions(+), 11 deletions(-)
8
9 diff --git a/eclass/verify-sig.eclass b/eclass/verify-sig.eclass
10 index e3ef7f240283..7f89e5388ba3 100644
11 --- a/eclass/verify-sig.eclass
12 +++ b/eclass/verify-sig.eclass
13 @@ -1,271 +1,265 @@
14 -# Copyright 2020 Gentoo Authors
15 +# Copyright 2020-2021 Gentoo Authors
16 # Distributed under the terms of the GNU General Public License v2
17
18 # @ECLASS: verify-sig.eclass
19 # @MAINTAINER:
20 # Michał Górny <mgorny@g.o>
21 -# @SUPPORTED_EAPIS: 7
22 +# @SUPPORTED_EAPIS: 7 8
23 # @BLURB: Eclass to verify upstream signatures on distfiles
24 # @DESCRIPTION:
25 # verify-sig eclass provides a streamlined approach to verifying
26 # upstream signatures on distfiles. Its primary purpose is to permit
27 # developers to easily verify signatures while bumping packages.
28 # The eclass removes the risk of developer forgetting to perform
29 # the verification, or performing it incorrectly, e.g. due to additional
30 # keys in the local keyring. It also permits users to verify
31 # the developer's work.
32 #
33 # To use the eclass, start by packaging the upstream's key
34 # as app-crypt/openpgp-keys-*. Then inherit the eclass, add detached
35 # signatures to SRC_URI and set VERIFY_SIG_OPENPGP_KEY_PATH. The eclass
36 # provides verify-sig USE flag to toggle the verification.
37 #
38 # Example use:
39 # @CODE
40 # inherit verify-sig
41 #
42 # SRC_URI="https://example.org/${P}.tar.gz
43 # verify-sig? ( https://example.org/${P}.tar.gz.sig )"
44 # BDEPEND="
45 # verify-sig? ( app-crypt/openpgp-keys-example )"
46 #
47 # VERIFY_SIG_OPENPGP_KEY_PATH=/usr/share/openpgp-keys/example.asc
48 # @CODE
49
50 -case "${EAPI:-0}" in
51 - 0|1|2|3|4|5|6)
52 - die "Unsupported EAPI=${EAPI} (obsolete) for ${ECLASS}"
53 - ;;
54 - 7)
55 - ;;
56 - *)
57 - die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
58 - ;;
59 +case ${EAPI} in
60 + 7|8) ;;
61 + *) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;;
62 esac
63
64 EXPORT_FUNCTIONS src_unpack
65
66 if [[ ! ${_VERIFY_SIG_ECLASS} ]]; then
67
68 IUSE="verify-sig"
69
70 BDEPEND="
71 verify-sig? (
72 app-crypt/gnupg
73 >=app-portage/gemato-16
74 )"
75
76 # @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEY_PATH
77 # @DEFAULT_UNSET
78 # @DESCRIPTION:
79 # Path to key bundle used to perform the verification. This is required
80 # when using default src_unpack. Alternatively, the key path can be
81 # passed directly to the verification functions.
82
83 # @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEYSERVER
84 # @DEFAULT_UNSET
85 # @DESCRIPTION:
86 # Keyserver used to refresh keys. If not specified, the keyserver
87 # preference from the key will be respected. If no preference
88 # is specified by the key, the GnuPG default will be used.
89
90 # @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEY_REFRESH
91 # @USER_VARIABLE
92 # @DESCRIPTION:
93 # Attempt to refresh keys via WKD/keyserver. Set it to "yes"
94 # in make.conf to enable. Note that this requires working Internet
95 # connection.
96 : ${VERIFY_SIG_OPENPGP_KEY_REFRESH:=no}
97
98 # @FUNCTION: verify-sig_verify_detached
99 # @USAGE: <file> <sig-file> [<key-file>]
100 # @DESCRIPTION:
101 # Read the detached signature from <sig-file> and verify <file> against
102 # it. <key-file> can either be passed directly, or it defaults
103 # to VERIFY_SIG_OPENPGP_KEY_PATH. The function dies if verification
104 # fails.
105 verify-sig_verify_detached() {
106 local file=${1}
107 local sig=${2}
108 local key=${3:-${VERIFY_SIG_OPENPGP_KEY_PATH}}
109
110 [[ -n ${key} ]] ||
111 die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset"
112
113 local extra_args=()
114 [[ ${VERIFY_SIG_OPENPGP_KEY_REFRESH} == yes ]] || extra_args+=( -R )
115 [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]] && extra_args+=(
116 --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}"
117 )
118
119 # GPG upstream knows better than to follow the spec, so we can't
120 # override this directory. However, there is a clean fallback
121 # to GNUPGHOME.
122 addpredict /run/user
123
124 local filename=${file##*/}
125 [[ ${file} == - ]] && filename='(stdin)'
126 einfo "Verifying ${filename} ..."
127 gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \
128 gpg --verify "${sig}" "${file}" ||
129 die "PGP signature verification failed"
130 }
131
132 # @FUNCTION: verify-sig_verify_message
133 # @USAGE: <file> <output-file> [<key-file>]
134 # @DESCRIPTION:
135 # Verify that the file ('-' for stdin) contains a valid, signed PGP
136 # message and write the message into <output-file> ('-' for stdout).
137 # <key-file> can either be passed directly, or it defaults
138 # to VERIFY_SIG_OPENPGP_KEY_PATH. The function dies if verification
139 # fails. Note that using output from <output-file> is important as it
140 # prevents the injection of unsigned data.
141 verify-sig_verify_message() {
142 local file=${1}
143 local output_file=${2}
144 local key=${3:-${VERIFY_SIG_OPENPGP_KEY_PATH}}
145
146 [[ -n ${key} ]] ||
147 die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset"
148
149 local extra_args=()
150 [[ ${VERIFY_SIG_OPENPGP_KEY_REFRESH} == yes ]] || extra_args+=( -R )
151 [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]] && extra_args+=(
152 --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}"
153 )
154
155 # GPG upstream knows better than to follow the spec, so we can't
156 # override this directory. However, there is a clean fallback
157 # to GNUPGHOME.
158 addpredict /run/user
159
160 local filename=${file##*/}
161 [[ ${file} == - ]] && filename='(stdin)'
162 einfo "Verifying ${filename} ..."
163 gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \
164 gpg --verify --output="${output_file}" "${file}" ||
165 die "PGP signature verification failed"
166 }
167
168 # @FUNCTION: verify-sig_verify_signed_checksums
169 # @USAGE: <checksum-file> <algo> <files> [<key-file>]
170 # @DESCRIPTION:
171 # Verify the checksums for all files listed in the space-separated list
172 # <files> (akin to ${A}) using a PGP-signed <checksum-file>. <algo>
173 # specified the checksum algorithm (e.g. sha256). <key-file> can either
174 # be passed directly, or it defaults to VERIFY_SIG_OPENPGP_KEY_PATH.
175 #
176 # The function dies if PGP verification fails, the checksum file
177 # contains unsigned data, one of the files do not match checksums
178 # or are missing from the checksum file.
179 verify-sig_verify_signed_checksums() {
180 local checksum_file=${1}
181 local algo=${2}
182 local files=()
183 read -r -d '' -a files <<<"${3}"
184 local key=${4:-${VERIFY_SIG_OPENPGP_KEY_PATH}}
185
186 local chksum_prog chksum_len
187 case ${algo} in
188 sha256)
189 chksum_prog=sha256sum
190 chksum_len=64
191 ;;
192 *)
193 die "${FUNCNAME}: unknown checksum algo ${algo}"
194 ;;
195 esac
196
197 [[ -n ${key} ]] ||
198 die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset"
199
200 local checksum filename junk ret=0 count=0
201 while read -r checksum filename junk; do
202 [[ ${#checksum} -eq ${chksum_len} ]] || continue
203 [[ -z ${checksum//[0-9a-f]} ]] || continue
204 has "${filename}" "${files[@]}" || continue
205 [[ -z ${junk} ]] || continue
206
207 "${chksum_prog}" -c --strict - <<<"${checksum} ${filename}"
208 if [[ ${?} -eq 0 ]]; then
209 (( count++ ))
210 else
211 ret=1
212 fi
213 done < <(verify-sig_verify_message "${checksum_file}" - "${key}")
214
215 [[ ${ret} -eq 0 ]] ||
216 die "${FUNCNAME}: at least one file did not verify successfully"
217 [[ ${count} -eq ${#files[@]} ]] ||
218 die "${FUNCNAME}: checksums for some of the specified files were missing"
219 }
220
221 # @FUNCTION: verify-sig_src_unpack
222 # @DESCRIPTION:
223 # Default src_unpack override that verifies signatures for all
224 # distfiles if 'verify-sig' flag is enabled. The function dies if any
225 # of the signatures fails to verify or if any distfiles are not signed.
226 # Please write src_unpack() yourself if you need to perform partial
227 # verification.
228 verify-sig_src_unpack() {
229 if use verify-sig; then
230 local f suffix found
231 local distfiles=() signatures=() nosigfound=() straysigs=()
232
233 # find all distfiles and signatures, and combine them
234 for f in ${A}; do
235 found=
236 for suffix in .asc .sig; do
237 if [[ ${f} == *${suffix} ]]; then
238 signatures+=( "${f}" )
239 found=sig
240 break
241 else
242 if has "${f}${suffix}" ${A}; then
243 distfiles+=( "${f}" )
244 found=dist+sig
245 break
246 fi
247 fi
248 done
249 if [[ ! ${found} ]]; then
250 nosigfound+=( "${f}" )
251 fi
252 done
253
254 # check if all distfiles are signed
255 if [[ ${#nosigfound[@]} -gt 0 ]]; then
256 eerror "The following distfiles lack detached signatures:"
257 for f in "${nosigfound[@]}"; do
258 eerror " ${f}"
259 done
260 die "Unsigned distfiles found"
261 fi
262
263 # check if there are no stray signatures
264 for f in "${signatures[@]}"; do
265 if ! has "${f%.*}" "${distfiles[@]}"; then
266 straysigs+=( "${f}" )
267 fi
268 done
269 if [[ ${#straysigs[@]} -gt 0 ]]; then
270 eerror "The following signatures do not match any distfiles:"
271 for f in "${straysigs[@]}"; do
272 eerror " ${f}"
273 done
274 die "Unused signatures found"
275 fi
276
277 # now perform the verification
278 for f in "${signatures[@]}"; do
279 verify-sig_verify_detached \
280 "${DISTDIR}/${f%.*}" "${DISTDIR}/${f}"
281 done
282 fi
283
284 # finally, unpack the distfiles
285 default_src_unpack
286 }
287
288 _VERIFY_SIG_ECLASS=1
289 fi
290 --
291 2.32.0