1 |
It is useful for verifying distfiles that come from OpenBSD folks, since |
2 |
signify produces signatures incompatible with GnuPG. |
3 |
|
4 |
Signed-off-by: Anna Vyalkova <cyber+gentoo@×××××.in> |
5 |
--- |
6 |
Changed "ed25519" back to "signify" |
7 |
eclass/verify-sig.eclass | 141 ++++++++++++++++++++++++++++++--------- |
8 |
1 file changed, 108 insertions(+), 33 deletions(-) |
9 |
|
10 |
diff --git a/eclass/verify-sig.eclass b/eclass/verify-sig.eclass |
11 |
index 2bc5bd5ddba..7d5f89fbc44 100644 |
12 |
--- a/eclass/verify-sig.eclass |
13 |
+++ b/eclass/verify-sig.eclass |
14 |
@@ -1,265 +1,340 @@ |
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 8 |
22 |
# @BLURB: Eclass to verify upstream signatures on distfiles |
23 |
# @DESCRIPTION: |
24 |
# verify-sig eclass provides a streamlined approach to verifying |
25 |
# upstream signatures on distfiles. Its primary purpose is to permit |
26 |
# developers to easily verify signatures while bumping packages. |
27 |
# The eclass removes the risk of developer forgetting to perform |
28 |
# the verification, or performing it incorrectly, e.g. due to additional |
29 |
# keys in the local keyring. It also permits users to verify |
30 |
# the developer's work. |
31 |
# |
32 |
# To use the eclass, start by packaging the upstream's key |
33 |
# as app-crypt/openpgp-keys-*. Then inherit the eclass, add detached |
34 |
# signatures to SRC_URI and set VERIFY_SIG_OPENPGP_KEY_PATH. The eclass |
35 |
# provides verify-sig USE flag to toggle the verification. |
36 |
# |
37 |
+# If you need to use signify, you may want to copy distfiles into WORKDIR to |
38 |
+# work around "Too many levels of symbolic links" error. |
39 |
+# @EXAMPLE: |
40 |
# Example use: |
41 |
+# |
42 |
# @CODE |
43 |
# inherit verify-sig |
44 |
# |
45 |
# SRC_URI="https://example.org/${P}.tar.gz |
46 |
# verify-sig? ( https://example.org/${P}.tar.gz.sig )" |
47 |
# BDEPEND=" |
48 |
# verify-sig? ( app-crypt/openpgp-keys-example )" |
49 |
# |
50 |
# VERIFY_SIG_OPENPGP_KEY_PATH=${BROOT}/usr/share/openpgp-keys/example.asc |
51 |
# @CODE |
52 |
|
53 |
case ${EAPI} in |
54 |
7|8) ;; |
55 |
*) die "${ECLASS}: EAPI ${EAPI:-0} not supported" ;; |
56 |
esac |
57 |
|
58 |
EXPORT_FUNCTIONS src_unpack |
59 |
|
60 |
if [[ ! ${_VERIFY_SIG_ECLASS} ]]; then |
61 |
|
62 |
IUSE="verify-sig" |
63 |
|
64 |
-BDEPEND=" |
65 |
- verify-sig? ( |
66 |
- app-crypt/gnupg |
67 |
- >=app-portage/gemato-16 |
68 |
- )" |
69 |
+# @ECLASS-VARIABLE: VERIFY_SIG_METHOD |
70 |
+# @PRE_INHERIT |
71 |
+# @DESCRIPTION: |
72 |
+# Signature verification method to use. The allowed value are: |
73 |
+# |
74 |
+# - openpgp -- verify PGP signatures using app-crypt/gnupg (the default) |
75 |
+# - signify -- verify signatures with Ed25519 public key using app-crypt/signify |
76 |
+: ${VERIFY_SIG_METHOD:=openpgp} |
77 |
+ |
78 |
+case ${VERIFY_SIG_METHOD} in |
79 |
+ openpgp) |
80 |
+ BDEPEND=" |
81 |
+ verify-sig? ( |
82 |
+ app-crypt/gnupg |
83 |
+ >=app-portage/gemato-16 |
84 |
+ )" |
85 |
+ ;; |
86 |
+ signify) |
87 |
+ BDEPEND="verify-sig? ( app-crypt/signify )" |
88 |
+ ;; |
89 |
+ *) |
90 |
+ die "${ECLASS}: unknown method '${VERIFY_SIG_METHOD}'" |
91 |
+ ;; |
92 |
+esac |
93 |
|
94 |
# @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEY_PATH |
95 |
# @DEFAULT_UNSET |
96 |
# @DESCRIPTION: |
97 |
# Path to key bundle used to perform the verification. This is required |
98 |
# when using default src_unpack. Alternatively, the key path can be |
99 |
# passed directly to the verification functions. |
100 |
|
101 |
# @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEYSERVER |
102 |
# @DEFAULT_UNSET |
103 |
# @DESCRIPTION: |
104 |
# Keyserver used to refresh keys. If not specified, the keyserver |
105 |
# preference from the key will be respected. If no preference |
106 |
-# is specified by the key, the GnuPG default will be used. |
107 |
+# is specified by the key, the GnuPG default will be used. Supported for |
108 |
+# OpenPGP only. |
109 |
|
110 |
# @ECLASS-VARIABLE: VERIFY_SIG_OPENPGP_KEY_REFRESH |
111 |
# @USER_VARIABLE |
112 |
# @DESCRIPTION: |
113 |
# Attempt to refresh keys via WKD/keyserver. Set it to "yes" |
114 |
# in make.conf to enable. Note that this requires working Internet |
115 |
-# connection. |
116 |
+# connection. Supported for OpenPGP only. |
117 |
: ${VERIFY_SIG_OPENPGP_KEY_REFRESH:=no} |
118 |
|
119 |
# @FUNCTION: verify-sig_verify_detached |
120 |
# @USAGE: <file> <sig-file> [<key-file>] |
121 |
# @DESCRIPTION: |
122 |
# Read the detached signature from <sig-file> and verify <file> against |
123 |
# it. <key-file> can either be passed directly, or it defaults |
124 |
# to VERIFY_SIG_OPENPGP_KEY_PATH. The function dies if verification |
125 |
# fails. |
126 |
verify-sig_verify_detached() { |
127 |
local file=${1} |
128 |
local sig=${2} |
129 |
local key=${3:-${VERIFY_SIG_OPENPGP_KEY_PATH}} |
130 |
|
131 |
[[ -n ${key} ]] || |
132 |
die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset" |
133 |
|
134 |
local extra_args=() |
135 |
[[ ${VERIFY_SIG_OPENPGP_KEY_REFRESH} == yes ]] || extra_args+=( -R ) |
136 |
- [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]] && extra_args+=( |
137 |
- --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}" |
138 |
- ) |
139 |
+ if [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]]; then |
140 |
+ [[ ${VERIFY_SIG_METHOD} == openpgp ]] || |
141 |
+ die "${FUNCNAME}: VERIFY_SIG_OPENPGP_KEYSERVER is not supported" |
142 |
+ |
143 |
+ extra_args+=( |
144 |
+ --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}" |
145 |
+ ) |
146 |
+ fi |
147 |
|
148 |
# GPG upstream knows better than to follow the spec, so we can't |
149 |
# override this directory. However, there is a clean fallback |
150 |
# to GNUPGHOME. |
151 |
addpredict /run/user |
152 |
|
153 |
local filename=${file##*/} |
154 |
[[ ${file} == - ]] && filename='(stdin)' |
155 |
einfo "Verifying ${filename} ..." |
156 |
- gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \ |
157 |
- gpg --verify "${sig}" "${file}" || |
158 |
- die "PGP signature verification failed" |
159 |
+ case ${VERIFY_SIG_METHOD} in |
160 |
+ openpgp) |
161 |
+ gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \ |
162 |
+ gpg --verify "${sig}" "${file}" || |
163 |
+ die "PGP signature verification failed" |
164 |
+ ;; |
165 |
+ signify) |
166 |
+ signify -V -p "${key}" -m "${file}" -x "${sig}" || |
167 |
+ die "Signify signature verification failed" |
168 |
+ ;; |
169 |
+ esac |
170 |
} |
171 |
|
172 |
# @FUNCTION: verify-sig_verify_message |
173 |
# @USAGE: <file> <output-file> [<key-file>] |
174 |
# @DESCRIPTION: |
175 |
# Verify that the file ('-' for stdin) contains a valid, signed PGP |
176 |
# message and write the message into <output-file> ('-' for stdout). |
177 |
# <key-file> can either be passed directly, or it defaults |
178 |
# to VERIFY_SIG_OPENPGP_KEY_PATH. The function dies if verification |
179 |
# fails. Note that using output from <output-file> is important as it |
180 |
# prevents the injection of unsigned data. |
181 |
verify-sig_verify_message() { |
182 |
local file=${1} |
183 |
local output_file=${2} |
184 |
local key=${3:-${VERIFY_SIG_OPENPGP_KEY_PATH}} |
185 |
|
186 |
[[ -n ${key} ]] || |
187 |
die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset" |
188 |
|
189 |
local extra_args=() |
190 |
[[ ${VERIFY_SIG_OPENPGP_KEY_REFRESH} == yes ]] || extra_args+=( -R ) |
191 |
- [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]] && extra_args+=( |
192 |
- --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}" |
193 |
- ) |
194 |
+ if [[ -n ${VERIFY_SIG_OPENPGP_KEYSERVER+1} ]]; then |
195 |
+ [[ ${VERIFY_SIG_METHOD} == openpgp ]] || |
196 |
+ die "${FUNCNAME}: VERIFY_SIG_OPENPGP_KEYSERVER is not supported" |
197 |
+ |
198 |
+ extra_args+=( |
199 |
+ --keyserver "${VERIFY_SIG_OPENPGP_KEYSERVER}" |
200 |
+ ) |
201 |
+ fi |
202 |
|
203 |
# GPG upstream knows better than to follow the spec, so we can't |
204 |
# override this directory. However, there is a clean fallback |
205 |
# to GNUPGHOME. |
206 |
addpredict /run/user |
207 |
|
208 |
local filename=${file##*/} |
209 |
[[ ${file} == - ]] && filename='(stdin)' |
210 |
einfo "Verifying ${filename} ..." |
211 |
- gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \ |
212 |
- gpg --verify --output="${output_file}" "${file}" || |
213 |
- die "PGP signature verification failed" |
214 |
+ case ${VERIFY_SIG_METHOD} in |
215 |
+ openpgp) |
216 |
+ gemato gpg-wrap -K "${key}" "${extra_args[@]}" -- \ |
217 |
+ gpg --verify --output="${output_file}" "${file}" || |
218 |
+ die "PGP signature verification failed" |
219 |
+ ;; |
220 |
+ signify) |
221 |
+ signify -V -e -p "${key}" -m "${output_file}" -x "${file}" || |
222 |
+ die "Signify signature verification failed" |
223 |
+ ;; |
224 |
+ esac |
225 |
} |
226 |
|
227 |
-# @FUNCTION: verify-sig_verify_signed_checksums |
228 |
+# @FUNCTION: _gpg_verify_signed_checksums |
229 |
+# @INTERNAL |
230 |
# @USAGE: <checksum-file> <algo> <files> [<key-file>] |
231 |
# @DESCRIPTION: |
232 |
-# Verify the checksums for all files listed in the space-separated list |
233 |
-# <files> (akin to ${A}) using a PGP-signed <checksum-file>. <algo> |
234 |
-# specified the checksum algorithm (e.g. sha256). <key-file> can either |
235 |
-# be passed directly, or it defaults to VERIFY_SIG_OPENPGP_KEY_PATH. |
236 |
-# |
237 |
-# The function dies if PGP verification fails, the checksum file |
238 |
-# contains unsigned data, one of the files do not match checksums |
239 |
-# or are missing from the checksum file. |
240 |
-verify-sig_verify_signed_checksums() { |
241 |
+# GnuPG-specific function to verify a signed checksums list. |
242 |
+_gpg_verify_signed_checksums() { |
243 |
local checksum_file=${1} |
244 |
local algo=${2} |
245 |
local files=() |
246 |
read -r -d '' -a files <<<"${3}" |
247 |
local key=${4:-${VERIFY_SIG_OPENPGP_KEY_PATH}} |
248 |
- |
249 |
local chksum_prog chksum_len |
250 |
+ |
251 |
case ${algo} in |
252 |
sha256) |
253 |
chksum_prog=sha256sum |
254 |
chksum_len=64 |
255 |
;; |
256 |
*) |
257 |
die "${FUNCNAME}: unknown checksum algo ${algo}" |
258 |
;; |
259 |
esac |
260 |
|
261 |
- [[ -n ${key} ]] || |
262 |
- die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset" |
263 |
- |
264 |
local checksum filename junk ret=0 count=0 |
265 |
while read -r checksum filename junk; do |
266 |
[[ ${#checksum} -eq ${chksum_len} ]] || continue |
267 |
[[ -z ${checksum//[0-9a-f]} ]] || continue |
268 |
has "${filename}" "${files[@]}" || continue |
269 |
[[ -z ${junk} ]] || continue |
270 |
|
271 |
"${chksum_prog}" -c --strict - <<<"${checksum} ${filename}" |
272 |
if [[ ${?} -eq 0 ]]; then |
273 |
(( count++ )) |
274 |
else |
275 |
ret=1 |
276 |
fi |
277 |
done < <(verify-sig_verify_message "${checksum_file}" - "${key}") |
278 |
|
279 |
[[ ${ret} -eq 0 ]] || |
280 |
die "${FUNCNAME}: at least one file did not verify successfully" |
281 |
[[ ${count} -eq ${#files[@]} ]] || |
282 |
die "${FUNCNAME}: checksums for some of the specified files were missing" |
283 |
} |
284 |
|
285 |
+# @FUNCTION: verify-sig_verify_signed_checksums |
286 |
+# @USAGE: <checksum-file> <algo> <files> [<key-file>] |
287 |
+# @DESCRIPTION: |
288 |
+# Verify the checksums for all files listed in the space-separated list |
289 |
+# <files> (akin to ${A}) using a signed <checksum-file>. <algo> specifies |
290 |
+# the checksum algorithm (e.g. sha256). <key-file> can either be passed |
291 |
+# directly, or it defaults to VERIFY_SIG_OPENPGP_KEY_PATH. |
292 |
+# |
293 |
+# The function dies if signature verification fails, the checksum file |
294 |
+# contains unsigned data, one of the files do not match checksums or |
295 |
+# are missing from the checksum file. |
296 |
+verify-sig_verify_signed_checksums() { |
297 |
+ local checksum_file=${1} |
298 |
+ local algo=${2} |
299 |
+ local files=() |
300 |
+ read -r -d '' -a files <<<"${3}" |
301 |
+ local key=${4:-${VERIFY_SIG_OPENPGP_KEY_PATH}} |
302 |
+ |
303 |
+ [[ -n ${key} ]] || |
304 |
+ die "${FUNCNAME}: no key passed and VERIFY_SIG_OPENPGP_KEY_PATH unset" |
305 |
+ |
306 |
+ case ${VERIFY_SIG_METHOD} in |
307 |
+ openpgp) |
308 |
+ _gpg_verify_signed_checksums \ |
309 |
+ "${checksum_file}" "${algo}" "${files[@]}" "${key}" |
310 |
+ ;; |
311 |
+ signify) |
312 |
+ signify -C -p "${key}" \ |
313 |
+ -x "${checksum_file}" "${files[@]}" || |
314 |
+ die "Signify signature verification failed" |
315 |
+ ;; |
316 |
+ esac |
317 |
+} |
318 |
+ |
319 |
# @FUNCTION: verify-sig_src_unpack |
320 |
# @DESCRIPTION: |
321 |
# Default src_unpack override that verifies signatures for all |
322 |
# distfiles if 'verify-sig' flag is enabled. The function dies if any |
323 |
# of the signatures fails to verify or if any distfiles are not signed. |
324 |
# Please write src_unpack() yourself if you need to perform partial |
325 |
# verification. |
326 |
verify-sig_src_unpack() { |
327 |
if use verify-sig; then |
328 |
local f suffix found |
329 |
local distfiles=() signatures=() nosigfound=() straysigs=() |
330 |
|
331 |
# find all distfiles and signatures, and combine them |
332 |
for f in ${A}; do |
333 |
found= |
334 |
for suffix in .asc .sig; do |
335 |
if [[ ${f} == *${suffix} ]]; then |
336 |
signatures+=( "${f}" ) |
337 |
found=sig |
338 |
break |
339 |
else |
340 |
if has "${f}${suffix}" ${A}; then |
341 |
distfiles+=( "${f}" ) |
342 |
found=dist+sig |
343 |
break |
344 |
fi |
345 |
fi |
346 |
done |
347 |
if [[ ! ${found} ]]; then |
348 |
nosigfound+=( "${f}" ) |
349 |
fi |
350 |
done |
351 |
|
352 |
# check if all distfiles are signed |
353 |
if [[ ${#nosigfound[@]} -gt 0 ]]; then |
354 |
eerror "The following distfiles lack detached signatures:" |
355 |
for f in "${nosigfound[@]}"; do |
356 |
eerror " ${f}" |
357 |
done |
358 |
die "Unsigned distfiles found" |
359 |
fi |
360 |
|
361 |
# check if there are no stray signatures |
362 |
for f in "${signatures[@]}"; do |
363 |
if ! has "${f%.*}" "${distfiles[@]}"; then |
364 |
straysigs+=( "${f}" ) |
365 |
fi |
366 |
done |
367 |
if [[ ${#straysigs[@]} -gt 0 ]]; then |
368 |
eerror "The following signatures do not match any distfiles:" |
369 |
for f in "${straysigs[@]}"; do |
370 |
eerror " ${f}" |
371 |
done |
372 |
die "Unused signatures found" |
373 |
fi |
374 |
|
375 |
# now perform the verification |
376 |
for f in "${signatures[@]}"; do |
377 |
verify-sig_verify_detached \ |
378 |
"${DISTDIR}/${f%.*}" "${DISTDIR}/${f}" |
379 |
done |
380 |
fi |
381 |
|
382 |
# finally, unpack the distfiles |
383 |
default_src_unpack |
384 |
} |
385 |
|
386 |
_VERIFY_SIG_ECLASS=1 |
387 |
fi |
388 |
-- |
389 |
2.34.1 |