From 4f114f38178aeaffcc571aa42e2f930ca916f79d Mon Sep 17 00:00:00 2001 From: Ashley Whetter Date: Sun, 8 May 2016 17:28:28 +0100 Subject: libmakepkg: extract functions for integrity checking Signed-off-by: Ashley Whetter Signed-off-by: Allan McRae --- scripts/Makefile.am | 6 + scripts/libmakepkg/.gitignore | 2 + scripts/libmakepkg/integrity.sh.in | 45 +++ .../libmakepkg/integrity/generate_checksum.sh.in | 107 ++++++ .../libmakepkg/integrity/generate_signature.sh.in | 49 +++ scripts/libmakepkg/integrity/verify_checksum.sh.in | 130 +++++++ .../libmakepkg/integrity/verify_signature.sh.in | 216 +++++++++++ scripts/libmakepkg/util/pkgbuild.sh.in | 20 +- scripts/makepkg.sh.in | 428 --------------------- scripts/po/POTFILES.in | 5 + 10 files changed, 579 insertions(+), 429 deletions(-) create mode 100644 scripts/libmakepkg/integrity.sh.in create mode 100644 scripts/libmakepkg/integrity/generate_checksum.sh.in create mode 100644 scripts/libmakepkg/integrity/generate_signature.sh.in create mode 100644 scripts/libmakepkg/integrity/verify_checksum.sh.in create mode 100644 scripts/libmakepkg/integrity/verify_signature.sh.in diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 1e6a40bb..e4f9fb1b 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -41,6 +41,7 @@ LIBRARY = \ libmakepkgdir = $(datarootdir)/makepkg LIBMAKEPKGDIRS = \ + integrity \ lint_package \ lint_pkgbuild \ source \ @@ -53,6 +54,11 @@ LIBMAKEPKG = \ libmakepkg/util/util.sh LIBMAKEPKG_IN = \ + libmakepkg/integrity.sh \ + libmakepkg/integrity/generate_checksum.sh \ + libmakepkg/integrity/generate_signature.sh \ + libmakepkg/integrity/verify_checksum.sh \ + libmakepkg/integrity/verify_signature.sh \ libmakepkg/lint_package.sh \ libmakepkg/lint_package/build_references.sh \ libmakepkg/lint_package/missing_backup.sh \ diff --git a/scripts/libmakepkg/.gitignore b/scripts/libmakepkg/.gitignore index 211a0882..941d39a5 100644 --- a/scripts/libmakepkg/.gitignore +++ b/scripts/libmakepkg/.gitignore @@ -1,3 +1,5 @@ +integrity.sh +integrity/*.sh lint_package.sh lint_package/*.sh lint_pkgbuild.sh diff --git a/scripts/libmakepkg/integrity.sh.in b/scripts/libmakepkg/integrity.sh.in new file mode 100644 index 00000000..cb8159d3 --- /dev/null +++ b/scripts/libmakepkg/integrity.sh.in @@ -0,0 +1,45 @@ +#!/bin/bash +# +# integrity.sh - functions relating to source integrity checking +# +# Copyright (c) 2011-2016 Pacman Development Team +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_SH" ]] && return +LIBMAKEPKG_INTEGRITY_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + +for lib in "$LIBRARY/integrity/"*.sh; do + source "$lib" +done + +check_source_integrity() { + if (( SKIPCHECKSUMS && SKIPPGPCHECK )); then + warning "$(gettext "Skipping all source file integrity checks.")" + elif (( SKIPCHECKSUMS )); then + warning "$(gettext "Skipping verification of source file checksums.")" + check_pgpsigs "$@" + elif (( SKIPPGPCHECK )); then + warning "$(gettext "Skipping verification of source file PGP signatures.")" + check_checksums "$@" + else + check_checksums "$@" + check_pgpsigs "$@" + fi +} diff --git a/scripts/libmakepkg/integrity/generate_checksum.sh.in b/scripts/libmakepkg/integrity/generate_checksum.sh.in new file mode 100644 index 00000000..7a567100 --- /dev/null +++ b/scripts/libmakepkg/integrity/generate_checksum.sh.in @@ -0,0 +1,107 @@ +#!/bin/bash +# +# generate_checksum.sh - functions for generating source checksums +# +# Copyright (c) 2014-2016 Pacman Development Team +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_GENERATE_CHECKSUM_SH" ]] && return +LIBMAKEPKG_INTEGRITY_GENERATE_CHECKSUM_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + +generate_one_checksum() { + local integ=$1 arch=$2 sources numsrc indentsz idx + + if [[ $arch ]]; then + array_build sources "source_$arch" + else + array_build sources 'source' + fi + + numsrc=${#sources[*]} + if (( numsrc == 0 )); then + return + fi + + if [[ $arch ]]; then + printf "%ssums_%s=(%n" "$integ" "$arch" indentsz + else + printf "%ssums=(%n" "$integ" indentsz + fi + + for (( idx = 0; idx < numsrc; ++idx )); do + local netfile=${sources[idx]} + local proto sum + proto="$(get_protocol "$netfile")" + + case $proto in + bzr*|git*|hg*|svn*) + sum="SKIP" + ;; + *) + if [[ $netfile != *.@(sig?(n)|asc) ]]; then + local file + file="$(get_filepath "$netfile")" || missing_source_file "$netfile" + sum="$(openssl dgst -${integ} "$file")" + sum=${sum##* } + else + sum="SKIP" + fi + ;; + esac + + # indent checksum on lines after the first + printf "%*s%s" $(( idx ? indentsz : 0 )) '' "'$sum'" + + # print a newline on lines before the last + (( idx < (numsrc - 1) )) && echo + done + + echo ")" +} + +generate_checksums() { + msg "$(gettext "Generating checksums for source files...")" + + if ! type -p openssl >/dev/null; then + error "$(gettext "Cannot find the %s binary required for generating sourcefile checksums.")" "openssl" + exit 1 # $E_MISSING_PROGRAM + fi + + local integlist + if (( $# == 0 )); then + IFS=$'\n' read -rd '' -a integlist < <(get_integlist) + else + integlist=("$@") + fi + + local integ + for integ in "${integlist[@]}"; do + if ! in_array "$integ" "${known_hash_algos[@]}"; then + error "$(gettext "Invalid integrity algorithm '%s' specified.")" "$integ" + exit 1 # $E_CONFIG_ERROR + fi + + generate_one_checksum "$integ" + for a in "${arch[@]}"; do + generate_one_checksum "$integ" "$a" + done + done +} diff --git a/scripts/libmakepkg/integrity/generate_signature.sh.in b/scripts/libmakepkg/integrity/generate_signature.sh.in new file mode 100644 index 00000000..d7f7cb14 --- /dev/null +++ b/scripts/libmakepkg/integrity/generate_signature.sh.in @@ -0,0 +1,49 @@ +#!/bin/bash +# +# generate_signature.sh - functions for generating PGP signatures +# +# Copyright (c) 2008-2016 Pacman Development Team +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_GENERATE_SIGNATURE_SH" ]] && return +LIBMAKEPKG_INTEGRITY_GENERATE_SIGNATURE_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" + +create_signature() { + if [[ $SIGNPKG != 'y' ]]; then + return + fi + local ret=0 + local filename="$1" + msg "$(gettext "Signing package...")" + + local SIGNWITHKEY="" + if [[ -n $GPGKEY ]]; then + SIGNWITHKEY="-u ${GPGKEY}" + fi + + gpg --detach-sign --use-agent ${SIGNWITHKEY} --no-armor "$filename" &>/dev/null || ret=$? + + + if (( ! ret )); then + msg2 "$(gettext "Created signature file %s.")" "$filename.sig" + else + warning "$(gettext "Failed to sign package file.")" + fi +} diff --git a/scripts/libmakepkg/integrity/verify_checksum.sh.in b/scripts/libmakepkg/integrity/verify_checksum.sh.in new file mode 100644 index 00000000..44a2b2e1 --- /dev/null +++ b/scripts/libmakepkg/integrity/verify_checksum.sh.in @@ -0,0 +1,130 @@ +#!/bin/bash +# +# verify_checksum.sh - functions for checking source checksums +# +# Copyright (c) 2014-2016 Pacman Development Team +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_VERIFY_CHECKSUM_SH" ]] && return +LIBMAKEPKG_INTEGRITY_CHECKSUM_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + +check_checksums() { + local integ a + declare -A correlation + (( SKIPCHECKSUMS )) && return 0 + + # Initialize a map which we'll use to verify that every source array has at + # least some kind of checksum array associated with it. + (( ${#source[*]} )) && correlation['source']=1 + case $1 in + all) + for a in "${arch[@]}"; do + array_build _ source_"$a" && correlation["source_$a"]=1 + done + ;; + *) + array_build _ source_"$CARCH" && correlation["source_$CARCH"]=1 + ;; + esac + + for integ in "${known_hash_algos[@]}"; do + verify_integrity_sums "$integ" && unset "correlation[source]" + + case $1 in + all) + for a in "${arch[@]}"; do + verify_integrity_sums "$integ" "$a" && unset "correlation[source_$a]" + done + ;; + *) + verify_integrity_sums "$integ" "$CARCH" && unset "correlation[source_$CARCH]" + ;; + esac + done + + if (( ${#correlation[*]} )); then + error "$(gettext "Integrity checks are missing for: %s")" "${!correlation[*]}" + exit 1 # TODO: error code + fi +} + +verify_integrity_one() { + local source_name=$1 integ=$2 expectedsum=$3 + + local file="$(get_filename "$source_name")" + printf ' %s ... ' "$file" >&2 + + if [[ $expectedsum = 'SKIP' ]]; then + printf '%s\n' "$(gettext "Skipped")" >&2 + return + fi + + if ! file="$(get_filepath "$file")"; then + printf '%s\n' "$(gettext "NOT FOUND")" >&2 + return 1 + fi + + local realsum="$(openssl dgst -${integ} "$file")" + realsum="${realsum##* }" + if [[ ${expectedsum,,} = "$realsum" ]]; then + printf '%s\n' "$(gettext "Passed")" >&2 + else + printf '%s\n' "$(gettext "FAILED")" >&2 + return 1 + fi + + return 0 +} + +verify_integrity_sums() { + local integ=$1 arch=$2 integrity_sums=() sources=() srcname + + if [[ $arch ]]; then + array_build integrity_sums "${integ}sums_$arch" + srcname=source_$arch + else + array_build integrity_sums "${integ}sums" + srcname=source + fi + + array_build sources "$srcname" + if (( ${#integrity_sums[@]} == 0 && ${#sources[@]} == 0 )); then + return 1 + fi + + if (( ${#integrity_sums[@]} == ${#sources[@]} )); then + msg "$(gettext "Validating %s files with %s...")" "$srcname" "${integ}sums" + local idx errors=0 + for (( idx = 0; idx < ${#sources[*]}; idx++ )); do + verify_integrity_one "${sources[idx]}" "$integ" "${integrity_sums[idx]}" || errors=1 + done + + if (( errors )); then + error "$(gettext "One or more files did not pass the validity check!")" + exit 1 # TODO: error code + fi + elif (( ${#integrity_sums[@]} )); then + error "$(gettext "Integrity checks (%s) differ in size from the source array.")" "$integ" + exit 1 # TODO: error code + else + return 1 + fi +} diff --git a/scripts/libmakepkg/integrity/verify_signature.sh.in b/scripts/libmakepkg/integrity/verify_signature.sh.in new file mode 100644 index 00000000..6df62727 --- /dev/null +++ b/scripts/libmakepkg/integrity/verify_signature.sh.in @@ -0,0 +1,216 @@ +#!/bin/bash +# +# verify_signature.sh - functions for checking PGP signatures +# +# Copyright (c) 2011-2016 Pacman Development Team +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_VERIFY_SIGNATURE_SH" ]] && return +LIBMAKEPKG_INTEGRITY_VERIFY_SIGNATURE_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/util/pkgbuild.sh" + +check_pgpsigs() { + (( SKIPPGPCHECK )) && return 0 + ! source_has_signatures && return 0 + + msg "$(gettext "Verifying source file signatures with %s...")" "gpg" + + local file ext decompress found pubkey success status fingerprint trusted + local warning=0 + local errors=0 + local statusfile=$(mktemp) + local all_sources + + case $1 in + all) + get_all_sources 'all_sources' + ;; + *) + get_all_sources_for_arch 'all_sources' + ;; + esac + for file in "${all_sources[@]}"; do + file="$(get_filename "$file")" + if [[ $file != *.@(sig?(n)|asc) ]]; then + continue + fi + + printf " %s ... " "${file%.*}" >&2 + + if ! file="$(get_filepath "$file")"; then + printf '%s\n' "$(gettext "SIGNATURE NOT FOUND")" >&2 + errors=1 + continue + fi + + found=0 + for ext in "" gz bz2 xz lrz lzo Z; do + if sourcefile="$(get_filepath "${file%.*}${ext:+.$ext}")"; then + found=1 + break; + fi + done + if (( ! found )); then + printf '%s\n' "$(gettext "SOURCE FILE NOT FOUND")" >&2 + errors=1 + continue + fi + + case "$ext" in + gz) decompress="gzip -c -d -f" ;; + bz2) decompress="bzip2 -c -d -f" ;; + xz) decompress="xz -c -d" ;; + lrz) decompress="lrzip -q -d" ;; + lzo) decompress="lzop -c -d -q" ;; + Z) decompress="uncompress -c -f" ;; + "") decompress="cat" ;; + esac + + $decompress < "$sourcefile" | gpg --quiet --batch --status-file "$statusfile" --verify "$file" - 2> /dev/null + # these variables are assigned values in parse_gpg_statusfile + success=0 + status= + pubkey= + fingerprint= + trusted= + 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 + errors=1 + elif (( ${#validpgpkeys[@]} > 0 )) && ! in_array "$fingerprint" "${validpgpkeys[@]}"; then + printf "%s (%s %s)" "$(gettext "FAILED")" "$(gettext "invalid public key")" "$fingerprint" + errors=1 + else + printf '%s' "$(gettext "Passed")" >&2 + case "$status" in + "expired") + printf ' (%s)' "$(gettext "WARNING:") $(gettext "the signature has expired.")" >&2 + warnings=1 + ;; + "expiredkey") + printf ' (%s)' "$(gettext "WARNING:") $(gettext "the key has expired.")" >&2 + warnings=1 + ;; + esac + fi + fi + printf '\n' >&2 + done + + rm -f "$statusfile" + + if (( errors )); then + error "$(gettext "One or more PGP signatures could not be verified!")" + exit 1 + fi + + if (( warnings )); then + warning "$(gettext "Warnings have occurred while verifying the signatures.")" + plain "$(gettext "Please make sure you really trust them.")" + fi +} + +parse_gpg_statusfile() { + local type arg1 arg6 arg10 + + while read -r _ type arg1 _ _ _ _ arg6 _ _ _ arg10 _; do + case "$type" in + GOODSIG) + pubkey=$arg1 + success=1 + status="good" + ;; + EXPSIG) + pubkey=$arg1 + success=1 + status="expired" + ;; + EXPKEYSIG) + pubkey=$arg1 + success=1 + status="expiredkey" + ;; + REVKEYSIG) + pubkey=$arg1 + success=0 + status="revokedkey" + ;; + BADSIG) + pubkey=$arg1 + success=0 + status="bad" + ;; + ERRSIG) + pubkey=$arg1 + success=0 + if [[ $arg6 == 9 ]]; then + status="missingkey" + else + status="error" + fi + ;; + VALIDSIG) + if [[ $arg10 ]]; then + # If the file was signed with a subkey, arg10 contains + # the fingerprint of the primary key + fingerprint=$arg10 + else + fingerprint=$arg1 + fi + ;; + TRUST_UNDEFINED|TRUST_NEVER) + trusted=0 + ;; + TRUST_MARGINAL|TRUST_FULLY|TRUST_ULTIMATE) + trusted=1 + ;; + esac + done < "$1" +} + +source_has_signatures() { + local file all_sources + + get_all_sources_for_arch 'all_sources' + for file in "${all_sources[@]}"; do + if [[ ${file%%::*} = *.@(sig?(n)|asc) ]]; then + return 0 + fi + done + return 1 +} diff --git a/scripts/libmakepkg/util/pkgbuild.sh.in b/scripts/libmakepkg/util/pkgbuild.sh.in index 51d87329..1a4567dc 100644 --- a/scripts/libmakepkg/util/pkgbuild.sh.in +++ b/scripts/libmakepkg/util/pkgbuild.sh.in @@ -2,7 +2,7 @@ # # pkgbuild.sh - functions to extract information from PKGBUILD files # -# Copyright (c) 2014-2016 Pacman Development Team +# Copyright (c) 2009-2016 Pacman Development Team # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -189,3 +189,21 @@ get_all_sources_for_arch() { array_build "$1" "aggregate" } + +get_integlist() { + local integ + local integlist=() + + for integ in "${known_hash_algos[@]}"; do + local sumname="${integ}sums[@]" + if [[ -n ${!sumname} ]]; then + integlist+=("$integ") + fi + done + + if (( ${#integlist[@]} > 0 )); then + printf "%s\n" "${integlist[@]}" + else + printf "%s\n" "${INTEGRITY_CHECK[@]}" + fi +} diff --git a/scripts/makepkg.sh.in b/scripts/makepkg.sh.in index b87eb8a2..7b2ce511 100644 --- a/scripts/makepkg.sh.in +++ b/scripts/makepkg.sh.in @@ -204,18 +204,6 @@ missing_source_file() { exit 1 # $E_MISSING_FILE } -source_has_signatures() { - local file all_sources - - get_all_sources_for_arch 'all_sources' - for file in "${all_sources[@]}"; do - if [[ ${file%%::*} = *.@(sig?(n)|asc) ]]; then - return 0 - fi - done - return 1 -} - run_pacman() { local cmd if [[ $1 != -@(T|Qq) ]]; then @@ -332,399 +320,6 @@ remove_deps() { fi } -get_integlist() { - local integ - local integlist=() - - for integ in "${known_hash_algos[@]}"; do - local sumname="${integ}sums[@]" - if [[ -n ${!sumname} ]]; then - integlist+=("$integ") - fi - done - - if (( ${#integlist[@]} > 0 )); then - printf "%s\n" "${integlist[@]}" - else - printf "%s\n" "${INTEGRITY_CHECK[@]}" - fi -} - -generate_one_checksum() { - local integ=$1 arch=$2 sources numsrc indentsz idx - - if [[ $arch ]]; then - array_build sources "source_$arch" - else - array_build sources 'source' - fi - - numsrc=${#sources[*]} - if (( numsrc == 0 )); then - return - fi - - if [[ $arch ]]; then - printf "%ssums_%s=(%n" "$integ" "$arch" indentsz - else - printf "%ssums=(%n" "$integ" indentsz - fi - - for (( idx = 0; idx < numsrc; ++idx )); do - local netfile=${sources[idx]} - local proto sum - proto="$(get_protocol "$netfile")" - - case $proto in - bzr*|git*|hg*|svn*) - sum="SKIP" - ;; - *) - if [[ $netfile != *.@(sig?(n)|asc) ]]; then - local file - file="$(get_filepath "$netfile")" || missing_source_file "$netfile" - sum="$(openssl dgst -${integ} "$file")" - sum=${sum##* } - else - sum="SKIP" - fi - ;; - esac - - # indent checksum on lines after the first - printf "%*s%s" $(( idx ? indentsz : 0 )) '' "'$sum'" - - # print a newline on lines before the last - (( idx < (numsrc - 1) )) && echo - done - - echo ")" -} - -generate_checksums() { - msg "$(gettext "Generating checksums for source files...")" - - if ! type -p openssl >/dev/null; then - error "$(gettext "Cannot find the %s binary required for generating sourcefile checksums.")" "openssl" - exit 1 # $E_MISSING_PROGRAM - fi - - local integlist - if (( $# == 0 )); then - IFS=$'\n' read -rd '' -a integlist < <(get_integlist) - else - integlist=("$@") - fi - - local integ - for integ in "${integlist[@]}"; do - if ! in_array "$integ" "${known_hash_algos[@]}"; then - error "$(gettext "Invalid integrity algorithm '%s' specified.")" "$integ" - exit 1 # $E_CONFIG_ERROR - fi - - generate_one_checksum "$integ" - for a in "${arch[@]}"; do - generate_one_checksum "$integ" "$a" - done - done -} - -verify_integrity_one() { - local source_name=$1 integ=$2 expectedsum=$3 - - local file="$(get_filename "$source_name")" - printf ' %s ... ' "$file" >&2 - - if [[ $expectedsum = 'SKIP' ]]; then - printf '%s\n' "$(gettext "Skipped")" >&2 - return - fi - - if ! file="$(get_filepath "$file")"; then - printf '%s\n' "$(gettext "NOT FOUND")" >&2 - return 1 - fi - - local realsum="$(openssl dgst -${integ} "$file")" - realsum="${realsum##* }" - if [[ ${expectedsum,,} = "$realsum" ]]; then - printf '%s\n' "$(gettext "Passed")" >&2 - else - printf '%s\n' "$(gettext "FAILED")" >&2 - return 1 - fi - - return 0 -} - -verify_integrity_sums() { - local integ=$1 arch=$2 integrity_sums=() sources=() srcname - - if [[ $arch ]]; then - array_build integrity_sums "${integ}sums_$arch" - srcname=source_$arch - else - array_build integrity_sums "${integ}sums" - srcname=source - fi - - array_build sources "$srcname" - if (( ${#integrity_sums[@]} == 0 && ${#sources[@]} == 0 )); then - return 1 - fi - - if (( ${#integrity_sums[@]} == ${#sources[@]} )); then - msg "$(gettext "Validating %s files with %s...")" "$srcname" "${integ}sums" - local idx errors=0 - for (( idx = 0; idx < ${#sources[*]}; idx++ )); do - verify_integrity_one "${sources[idx]}" "$integ" "${integrity_sums[idx]}" || errors=1 - done - - if (( errors )); then - error "$(gettext "One or more files did not pass the validity check!")" - exit 1 # TODO: error code - fi - elif (( ${#integrity_sums[@]} )); then - error "$(gettext "Integrity checks (%s) differ in size from the source array.")" "$integ" - exit 1 # TODO: error code - else - return 1 - fi -} - -check_checksums() { - local integ a - declare -A correlation - (( SKIPCHECKSUMS )) && return 0 - - # Initialize a map which we'll use to verify that every source array has at - # least some kind of checksum array associated with it. - (( ${#source[*]} )) && correlation['source']=1 - case $1 in - all) - for a in "${arch[@]}"; do - array_build _ source_"$a" && correlation["source_$a"]=1 - done - ;; - *) - array_build _ source_"$CARCH" && correlation["source_$CARCH"]=1 - ;; - esac - - for integ in "${known_hash_algos[@]}"; do - verify_integrity_sums "$integ" && unset "correlation[source]" - - case $1 in - all) - for a in "${arch[@]}"; do - verify_integrity_sums "$integ" "$a" && unset "correlation[source_$a]" - done - ;; - *) - verify_integrity_sums "$integ" "$CARCH" && unset "correlation[source_$CARCH]" - ;; - esac - done - - if (( ${#correlation[*]} )); then - error "$(gettext "Integrity checks are missing for: %s")" "${!correlation[*]}" - exit 1 # TODO: error code - fi -} - -parse_gpg_statusfile() { - local type arg1 arg6 arg10 - - while read -r _ type arg1 _ _ _ _ arg6 _ _ _ arg10 _; do - case "$type" in - GOODSIG) - pubkey=$arg1 - success=1 - status="good" - ;; - EXPSIG) - pubkey=$arg1 - success=1 - status="expired" - ;; - EXPKEYSIG) - pubkey=$arg1 - success=1 - status="expiredkey" - ;; - REVKEYSIG) - pubkey=$arg1 - success=0 - status="revokedkey" - ;; - BADSIG) - pubkey=$arg1 - success=0 - status="bad" - ;; - ERRSIG) - pubkey=$arg1 - success=0 - if [[ $arg6 == 9 ]]; then - status="missingkey" - else - status="error" - fi - ;; - VALIDSIG) - if [[ $arg10 ]]; then - # If the file was signed with a subkey, arg10 contains - # the fingerprint of the primary key - fingerprint=$arg10 - else - fingerprint=$arg1 - fi - ;; - TRUST_UNDEFINED|TRUST_NEVER) - trusted=0 - ;; - TRUST_MARGINAL|TRUST_FULLY|TRUST_ULTIMATE) - trusted=1 - ;; - esac - done < "$1" -} - -check_pgpsigs() { - (( SKIPPGPCHECK )) && return 0 - ! source_has_signatures && return 0 - - msg "$(gettext "Verifying source file signatures with %s...")" "gpg" - - local file ext decompress found pubkey success status fingerprint trusted - local warning=0 - local errors=0 - local statusfile=$(mktemp) - local all_sources - - case $1 in - all) - get_all_sources 'all_sources' - ;; - *) - get_all_sources_for_arch 'all_sources' - ;; - esac - for file in "${all_sources[@]}"; do - file="$(get_filename "$file")" - if [[ $file != *.@(sig?(n)|asc) ]]; then - continue - fi - - printf " %s ... " "${file%.*}" >&2 - - if ! file="$(get_filepath "$file")"; then - printf '%s\n' "$(gettext "SIGNATURE NOT FOUND")" >&2 - errors=1 - continue - fi - - found=0 - for ext in "" gz bz2 xz lrz lzo Z; do - if sourcefile="$(get_filepath "${file%.*}${ext:+.$ext}")"; then - found=1 - break; - fi - done - if (( ! found )); then - printf '%s\n' "$(gettext "SOURCE FILE NOT FOUND")" >&2 - errors=1 - continue - fi - - case "$ext" in - gz) decompress="gzip -c -d -f" ;; - bz2) decompress="bzip2 -c -d -f" ;; - xz) decompress="xz -c -d" ;; - lrz) decompress="lrzip -q -d" ;; - lzo) decompress="lzop -c -d -q" ;; - Z) decompress="uncompress -c -f" ;; - "") decompress="cat" ;; - esac - - $decompress < "$sourcefile" | gpg --quiet --batch --status-file "$statusfile" --verify "$file" - 2> /dev/null - # these variables are assigned values in parse_gpg_statusfile - success=0 - status= - pubkey= - fingerprint= - trusted= - 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 - errors=1 - elif (( ${#validpgpkeys[@]} > 0 )) && ! in_array "$fingerprint" "${validpgpkeys[@]}"; then - printf "%s (%s %s)" "$(gettext "FAILED")" "$(gettext "invalid public key")" "$fingerprint" - errors=1 - else - printf '%s' "$(gettext "Passed")" >&2 - case "$status" in - "expired") - printf ' (%s)' "$(gettext "WARNING:") $(gettext "the signature has expired.")" >&2 - warnings=1 - ;; - "expiredkey") - printf ' (%s)' "$(gettext "WARNING:") $(gettext "the key has expired.")" >&2 - warnings=1 - ;; - esac - fi - fi - printf '\n' >&2 - done - - rm -f "$statusfile" - - if (( errors )); then - error "$(gettext "One or more PGP signatures could not be verified!")" - exit 1 - fi - - if (( warnings )); then - warning "$(gettext "Warnings have occurred while verifying the signatures.")" - plain "$(gettext "Please make sure you really trust them.")" - fi -} - -check_source_integrity() { - if (( SKIPCHECKSUMS && SKIPPGPCHECK )); then - warning "$(gettext "Skipping all source file integrity checks.")" - elif (( SKIPCHECKSUMS )); then - warning "$(gettext "Skipping verification of source file checksums.")" - check_pgpsigs "$@" - elif (( SKIPPGPCHECK )); then - warning "$(gettext "Skipping verification of source file PGP signatures.")" - check_checksums "$@" - else - check_checksums "$@" - check_pgpsigs "$@" - fi -} - error_function() { if [[ -p $logpipe ]]; then rm "$logpipe" @@ -1192,29 +787,6 @@ create_debug_package() { create_package } -create_signature() { - if [[ $SIGNPKG != 'y' ]]; then - return - fi - local ret=0 - local filename="$1" - msg "$(gettext "Signing package...")" - - local SIGNWITHKEY="" - if [[ -n $GPGKEY ]]; then - SIGNWITHKEY="-u ${GPGKEY}" - fi - - gpg --detach-sign --use-agent ${SIGNWITHKEY} --no-armor "$filename" &>/dev/null || ret=$? - - - if (( ! ret )); then - msg2 "$(gettext "Created signature file %s.")" "$filename.sig" - else - warning "$(gettext "Failed to sign package file.")" - fi -} - create_srcpackage() { local ret=0 msg "$(gettext "Creating source package...")" diff --git a/scripts/po/POTFILES.in b/scripts/po/POTFILES.in index d115d89b..0240ad96 100644 --- a/scripts/po/POTFILES.in +++ b/scripts/po/POTFILES.in @@ -8,6 +8,11 @@ scripts/pacman-key.sh.in scripts/pacman-optimize.sh.in scripts/pkgdelta.sh.in scripts/repo-add.sh.in +scripts/libmakepkg/integrity.sh +scripts/libmakepkg/integrity/generate_checksum.sh +scripts/libmakepkg/integrity/generate_signature.sh +scripts/libmakepkg/integrity/verify_checksum.sh +scripts/libmakepkg/integrity/verify_signature.sh scripts/libmakepkg/lint_package.sh.in scripts/libmakepkg/lint_package/build_references.sh.in scripts/libmakepkg/lint_package/missing_backup.sh.in -- cgit v1.2.3-70-g09d2