[pacman-dev] Proposal to split out makepkg integrity methods
Hello everyone, I'm looking to split some makepkg methods out into a of makepkg.sh.in and into a new libmakepkg module. My plan is to have an "integrity" folder in libmakepkg. In this folder there would be a "generate.sh" file with the `generate_checksums`, `generate_one_checksum`, and `create_signature` methods. Another file, "check.sh" would contain `check_source_integrity`and it's dependencies; namely `check_checksums`, `check_pgpsigs`, `parse_gpg_statusfile`, `verify_integrity_sums`, and `verify_integrity_one`. "integrity" would depend on "util/pkgbuild.sh" as `check_checksums` and `verify_integrity_sum` both call `array_build`, and `check_pgpsigs` calls `get_all_sources` and `get_all_sources_for_arch`. I also plan on moving `get_integlist` into "util/pkgbuild.sh", or maybe into an "integrity/util.sh" file (but "util/pkgbuild.sh" makes more sense to me). Another option would be to have an "integrity.sh" file under "integrity" (or maybe some other name) and also a "signature.sh" file, and to split the methods by whether they are related to strictly integrity checking or signature checking. Are there any thoughts or suggestions on this plan of attack? Ashley
On 29/04/16 07:01, Ashley Whetter wrote:
Another option would be to have an "integrity.sh" file under "integrity" (or maybe some other name) and also a "signature.sh" file, and to split the methods by whether they are related to strictly integrity checking or signature checking.
The plan sounds good to me. I'd like if signature checking was split from checksum checking as they are quite different. Allan
Signed-off-by: Ashley Whetter <ashley@awhetter.co.uk> --- scripts/Makefile.am | 4 + scripts/libmakepkg/.gitignore | 2 + scripts/libmakepkg/integrity.sh.in | 43 +++ scripts/libmakepkg/integrity/checksum.sh.in | 210 +++++++++++++ scripts/libmakepkg/integrity/signature.sh.in | 239 +++++++++++++++ scripts/libmakepkg/util/pkgbuild.sh.in | 18 ++ scripts/makepkg.sh.in | 428 --------------------------- 7 files changed, 516 insertions(+), 428 deletions(-) create mode 100644 scripts/libmakepkg/integrity.sh.in create mode 100644 scripts/libmakepkg/integrity/checksum.sh.in create mode 100644 scripts/libmakepkg/integrity/signature.sh.in diff --git a/scripts/Makefile.am b/scripts/Makefile.am index 1e6a40b..a2e6f53 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,9 @@ LIBMAKEPKG = \ libmakepkg/util/util.sh LIBMAKEPKG_IN = \ + libmakepkg/integrity.sh \ + libmakepkg/integrity/checksum.sh \ + libmakepkg/integrity/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 211a088..941d39a 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 0000000..3625de9 --- /dev/null +++ b/scripts/libmakepkg/integrity.sh.in @@ -0,0 +1,43 @@ +#!/bin/bash +# +# integrity.sh - functions relating to source integrity checking +# +# Copyright (c) 2016 Pacman Development Team <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_SH" ]] && return +LIBMAKEPKG_INTEGRITY_SH=1 + +LIBRARY=${LIBRARY:-'@libmakepkgdir@'} + +source "$LIBRARY/util/message.sh" +source "$LIBRARY/integrity/checksum.sh" +source "$LIBRARY/integrity/signature.sh" + +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/checksum.sh.in b/scripts/libmakepkg/integrity/checksum.sh.in new file mode 100644 index 0000000..a97d243 --- /dev/null +++ b/scripts/libmakepkg/integrity/checksum.sh.in @@ -0,0 +1,210 @@ +#!/bin/bash +# +# checksum.sh - functions for checking and generating source checksums +# +# Copyright (c) 2016 Pacman Development Team <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_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 +} + +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/signature.sh.in b/scripts/libmakepkg/integrity/signature.sh.in new file mode 100644 index 0000000..f21b70f --- /dev/null +++ b/scripts/libmakepkg/integrity/signature.sh.in @@ -0,0 +1,239 @@ +#!/bin/bash +# +# signature.sh - functions for checking and generating pgp signatures +# +# Copyright (c) 2016 Pacman Development Team <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -n "$LIBMAKEPKG_INTEGRITY_SIGNATURE_SH" ]] && return +LIBMAKEPKG_INTEGRITY_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 +} + +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/util/pkgbuild.sh.in b/scripts/libmakepkg/util/pkgbuild.sh.in index 51d8732..6ce1cb1 100644 --- a/scripts/libmakepkg/util/pkgbuild.sh.in +++ b/scripts/libmakepkg/util/pkgbuild.sh.in @@ -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 f80e37a..837dc85 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" @@ -1189,29 +784,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...")" -- 2.8.0
On 01/05/16 06:00, Ashley Whetter wrote:
Signed-off-by: Ashley Whetter <ashley@awhetter.co.uk> --- scripts/Makefile.am | 4 + scripts/libmakepkg/.gitignore | 2 + scripts/libmakepkg/integrity.sh.in | 43 +++ scripts/libmakepkg/integrity/checksum.sh.in | 210 +++++++++++++ scripts/libmakepkg/integrity/signature.sh.in | 239 +++++++++++++++ scripts/libmakepkg/util/pkgbuild.sh.in | 18 ++ scripts/makepkg.sh.in | 428 --------------------------- 7 files changed, 516 insertions(+), 428 deletions(-) create mode 100644 scripts/libmakepkg/integrity.sh.in create mode 100644 scripts/libmakepkg/integrity/checksum.sh.in create mode 100644 scripts/libmakepkg/integrity/signature.sh.in
A few comments that should be fast to implement: - These has translatable strings so will need added to scripts/po/POTFILES.in - Capitalise PGP in signature.sh.in header - Can you split "checksum.sh" into "verify_checksum" and "generate_checksum"? Same for "signature" too (even though this is a single function). I think those function don't really group together well. - Use git blame to look at the sections you are moving and what years that code was written (excluding trivial things like brackets). Use that to set the year range. Thanks, Allan
Signed-off-by: Ashley Whetter <ashley@awhetter.co.uk> --- 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 1e6a40b..e4f9fb1 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 211a088..941d39a 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 0000000..cb8159d --- /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 <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -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 0000000..7a56710 --- /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 <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -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 0000000..d7f7cb1 --- /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 <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -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 0000000..44a2b2e --- /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 <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -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 0000000..6df6272 --- /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 <pacman-dev@archlinux.org> +# +# 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 <http://www.gnu.org/licenses/>. +# + +[[ -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 51d8732..1a4567d 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 <pacman-dev@archlinux.org> +# Copyright (c) 2009-2016 Pacman Development Team <pacman-dev@archlinux.org> # # 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 f80e37a..837dc85 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" @@ -1189,29 +784,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 d115d89..0240ad9 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 -- 2.8.0
On 09/05/16 02:28, Ashley Whetter wrote:
Signed-off-by: Ashley Whetter <ashley@awhetter.co.uk> ---
Ack For the future, it is helpful if you include a list of changes for v2 of the patch after the "---" in the patch.
participants (2)
-
Allan McRae
-
Ashley Whetter