diff --git a/scripts/libmakepkg/integrity/verify_signature.sh.in b/scripts/libmakepkg/integrity/verify_signature.sh.in index ad5bb66d..f77d1189 100644 --- a/scripts/libmakepkg/integrity/verify_signature.sh.in +++ b/scripts/libmakepkg/integrity/verify_signature.sh.in @@ -32,7 +32,7 @@ check_pgpsigs() { msg "$(gettext "Verifying source file signatures with %s...")" "gpg" - local netfile proto pubkey success status fingerprint trusted + local netfile proto pubkey success status fingerprints trusted local warnings=0 local errors=0 local statusfile=$(mktemp) @@ -57,49 +57,59 @@ check_pgpsigs() { # these variables are assigned values in parse_gpg_statusfile success=0 - status= - pubkey= - fingerprint= - trusted= + declare -A status + fingerprints=() + trusted=0 parse_gpg_statusfile "$statusfile" if (( ! $success )); then printf '%s' "$(gettext "FAILED")" >&2 - case "$status" in - "missingkey") - printf ' (%s)' "$(gettext "unknown public key") $pubkey" >&2 - ;; - "revokedkey") - printf " ($(gettext "public key %s has been revoked"))" "$pubkey" >&2 - ;; - "bad") - printf ' (%s)' "$(gettext "bad signature from public key") $pubkey" >&2 - ;; - "error") - printf ' (%s)' "$(gettext "error during signature verification")" >&2 - ;; - esac errors=1 else if (( ${#validpgpkeys[@]} == 0 && !trusted )); then - printf "%s ($(gettext "the public key %s is not trusted"))" $(gettext "FAILED") "$fingerprint" >&2 + printf '%s' "$(gettext "FAILED")" >&2 + for pubkey in "${fingerprints[@]}"; do + printf " ($(gettext "the public key %s is not trusted"))" "$pubkey" >&2 + done errors=1 - elif (( ${#validpgpkeys[@]} > 0 )) && ! in_array "$fingerprint" "${validpgpkeys[@]}"; then - printf "%s (%s %s)" "$(gettext "FAILED")" "$(gettext "invalid public key")" "$fingerprint" >&2 + elif (( ${#validpgpkeys[@]} > 0 )) && ! arrays_intersect fingerprints validpgpkeys; then + printf '%s' "$(gettext "FAILED")" >&2 + for pubkey in "${fingerprints[@]}"; do + printf " (%s %s)" "$(gettext "invalid public key")" "$pubkey" >&2 + done errors=1 else printf '%s' "$(gettext "Passed")" >&2 - case "$status" in + fi + fi + + if (( warnings )); then + for pubkey in "${!status[@]}"; do + case "${status["$pubkey"]}" in + "good") + printf ' (%s)' "$(gettext "good signature from public key") $pubkey" >&2 + ;; + "missingkey") + printf ' (%s)' "$(gettext "unknown public key") $pubkey" >&2 + ;; + "revokedkey") + printf " ($(gettext "public key %s has been revoked"))" "$pubkey" >&2 + ;; + "bad") + printf ' (%s)' "$(gettext "bad signature from public key") $pubkey" >&2 + ;; + "error") + printf ' (%s)' "$(gettext "error during signature verification")" >&2 + ;; "expired") - printf ' (%s)' "$(gettext "WARNING:") $(gettext "the signature has expired.")" >&2 - warnings=1 + printf " (%s $(gettext "the signature by key %s has expired."))" "$(gettext "WARNING:")" "$pubkey" >&2 ;; "expiredkey") - printf ' (%s)' "$(gettext "WARNING:") $(gettext "the key has expired.")" >&2 - warnings=1 + printf " (%s $(gettext "the key %s has expired."))" "$(gettext "WARNING:")" "$pubkey" >&2 ;; esac - fi + done fi + printf '\n' >&2 done @@ -204,50 +214,49 @@ parse_gpg_statusfile() { while read -r _ type arg1 _ _ _ _ arg6 _ _ _ arg10 _; do case "$type" in GOODSIG) - pubkey=$arg1 success=1 - status="good" + status["$arg1"]="good" ;; EXPSIG) - pubkey=$arg1 success=1 - status="expired" + warnings=1 + status["$arg1"]="expired" ;; EXPKEYSIG) - pubkey=$arg1 success=1 - status="expiredkey" + warnings=1 + status["$arg1"]="expiredkey" ;; REVKEYSIG) - pubkey=$arg1 - success=0 - status="revokedkey" + warnings=1 + status["$arg1"]="revokedkey" ;; BADSIG) - pubkey=$arg1 - success=0 - status="bad" + warnings=1 + status["$arg1"]="bad" ;; ERRSIG) - pubkey=$arg1 - success=0 + warnings=1 if [[ $arg6 == 9 ]]; then - status="missingkey" + status["$arg1"]="missingkey" else - status="error" + status["$arg1"]="error" fi ;; VALIDSIG) if [[ $arg10 ]]; then # If the file was signed with a subkey, arg10 contains # the fingerprint of the primary key - fingerprint=$arg10 + fingerprints+=("$arg10") else - fingerprint=$arg1 + fingerprints+=("$arg1") fi ;; TRUST_UNDEFINED|TRUST_NEVER) - trusted=0 + # If the signature file contains multiple signatures, we + # consider the file to be valid if any of the signatures is + # made by a trusted key, so having other untrusted signatures + # is not a fatal error ;; TRUST_MARGINAL|TRUST_FULLY|TRUST_ULTIMATE) trusted=1 diff --git a/scripts/libmakepkg/util/util.sh.in b/scripts/libmakepkg/util/util.sh.in index 6c0e589a..15499227 100644 --- a/scripts/libmakepkg/util/util.sh.in +++ b/scripts/libmakepkg/util/util.sh.in @@ -53,6 +53,18 @@ is_array() { return $ret } +# Returns 0 if the two arrays passed by name have intersecting elements, +# 1 otherwise +arrays_intersect() { + local -n _arrays_intersect_first=$1 + local -n _arrays_intersect_second=$2 + local element + for element in "${_arrays_intersect_first[@]}"; do + in_array "$element" "${_arrays_intersect_second[@]}" && return 0 + done + return 1 +} + # Canonicalize a directory path if it exists canonicalize_path() { local path="$1"