From 95c2d2a6d658815fa2e696109ebd71e6dfeb630d Mon Sep 17 00:00:00 2001 From: John McQuah Date: Fri, 17 Feb 2023 15:35:54 -0500 Subject: [PATCH] pkgmeek: refactor the signature creation routines --- scripts/pkgmeek | 128 +++++++++++++++++++++++------------------------- 1 file changed, 61 insertions(+), 67 deletions(-) diff --git a/scripts/pkgmeek b/scripts/pkgmeek index 57d1c47..b9cf00d 100755 --- a/scripts/pkgmeek +++ b/scripts/pkgmeek @@ -8,12 +8,12 @@ main() { ######################## main routine ################################ -local pkg_dir src_dir work _local_ here url u f DIR TARGET pkg_utd -local errDL=0; local errUZ=0; +local pkg_dir src_dir work _local_ here url u pkg_utd f DIR TARGET +local errDL=0; local errUZ=0; local BSDTAR="/usr/bin/bsdtar --format=gnutar" parse_options "$@" # Exit early if refreshing an existing sha256 manifest was requested -[ "$PKGMK_REFRESH_SIG" = "yes" ] && { refresh_signature; exit $?; } +[ "$PKGMK_REFRESH_SIG" = "yes" ] && { make_signature refresh ; exit $?; } # # Read the Pkgfile to determine what to do next. But first ensure that # it came from a trusted source (FS#1851) @@ -101,21 +101,16 @@ check_pkg_mtime; pkg_utd=$? if [ "$PKGMK_UPDATE_FOOTPRINT" = "yes" ]; then [ -f "$pkg_dir$package" ] || \ { error "unable to update footprint. File '$package' not found."; - exit "$E_FOOTPRINT"; } + cleanup_work; exit "$E_FOOTPRINT"; } [ "$pkg_utd" = 1 ] || [ "$PKGMK_FORCE" = "yes" ] || \ { error "outdated package. Use '-f' to force the footprint update."; - exit "$E_FOOTPRINT"; } - cat_footprint > "$PKGMK_ROOT/.footprint" && info "footprint created." \ + cleanup_work; exit "$E_FOOTPRINT"; } + cat_footprint > "$PKGMK_ROOT/.footprint" && { info "footprint created."; exit 0; } \ || { error "Failed to write the footprint."; cleanup_work; exit "$E_DIRPERM"; } fi # Updating signatures (option -us) requires only sources and footprint, not a built package. -if [ "$PKGMK_UPDATE_SIG" = "yes" ]; then - cat_signature > "$PKGMK_ROOT/.signature" && info "Signature successfully created." \ - || { info "Could not create signature."; cleanup_work; exit "$E_DIRPERM"; } -fi - -# Exit after fulfilling any *explicit* requests for (signed) manifests -[[ "$PKGMK_UPDATE_FOOTPRINT $PKGMK_UPDATE_SIG" =~ yes ]] && { cleanup_work; exit 0; } +# As with -uf, exit after fulfilling the explicit request for a manifest. +[ "$PKGMK_UPDATE_SIG" = "yes" ] && { make_signature new; cleanup_work; exit $?; } # All the sources should be here by now, let's verify that we can trust them. readonly cs_fail_msg="Use '--ignore-signature' to override, if you have determined integrity by other means." @@ -178,8 +173,8 @@ if [ "$pkg_utd" = 0 ] || [ "$PKGMK_FORCE" = "yes" ]; then done } < <(find pkg -type l -path "*/man/man*/*" -printf '%f!%h\n') # Create the archive - [ $UID = 0 ] || fake_uid="--uid 0 --gid 0" - if (cd pkg; bsdtar --format=gnutar $fake_uid -cf "$pkg_dir$package" *); then + [ $UID = 0 ] || BSDTAR+=" --uid 0 --gid 0" + if (cd pkg; $BSDTAR -cf "$pkg_dir$package" -- *); then info "Package creation successful." else error "Unable to create the compressed package $package." @@ -202,8 +197,7 @@ if [ -n "$PKGMK_INSTALL_COMMAND" ]; then { error "Cannot run pkgadd as a non-root user."; exit "$E_INSTALL"; } $PKGMK_SU $PKGMK_INSTALL_COMMAND "$pkg_dir$package" \ && info "pkgadd $package succeeded." || \ - { error "pkgadd $package failed."; - exit "$E_INSTALL"; } + { error "pkgadd $package failed."; exit "$E_INSTALL"; } fi # Done! @@ -363,7 +357,7 @@ fetch_url() { # Did the port maintainer specify a branch other than 'main'? tag="${giturl##*\#}" [ "$tag" = "$giturl" ] || { giturl="${giturl%\#*}"; - CLONE_ARGS="-c advice.detachedHead=false --branch $tag"; } + CLONE_ARGS=(-c advice.detachedHead=false --branch "$tag"); } # # Has this project been downloaded before? if [ -d "$src_dir/$h.partial" ]; then @@ -371,7 +365,7 @@ fetch_url() { "$PKGMK_GIT_COMMAND" pull "$giturl" "$tag" finished=$?; cd .. else - "$PKGMK_GIT_COMMAND" clone "$giturl" $CLONE_ARGS "$h.partial" + "$PKGMK_GIT_COMMAND" clone "$giturl" "${CLONE_ARGS[@]}" "$h.partial" finished=$?; [ "$src_dir" = "" ] || { mv "$h.partial" "$src_dir"; ln -s "$src_dir/$h.partial" "$h"; } fi @@ -464,7 +458,9 @@ parse_signify_output() { # chomps the output of check_signature() check_signature() { # called from $PKGMK_ROOT in the case "when"="pre-Pkgfile", # otherwise called from within $work. local reqfiles=(Pkgfile); local s=0; local when="$1"; + local SIGNIFY_ARGS=(-C -x "$PKGMK_ROOT/.signature") + [ "$PKGMK_PUBLICKEY" ] || PKGMK_PUBLICKEY=$(repo_key public) if [ -f "$PKGMK_ROOT/.signature" ]; then [ "$when" = "pre-Pkgfile" ] || reqfiles=(.footprint) while [ "$when" = "pre-build" ] && [ "$s" -lt ${#_local_[@]} ]; do @@ -474,63 +470,62 @@ check_signature() { # called from $PKGMK_ROOT in the case "when"="pre-Pkgfile", for FILE in "${reqfiles[@]}"; do [ -e "$FILE" ] || ln -sf "$PKGMK_ROOT/$FILE" . done - if [ -f "$PKGMK_PUBLICKEY" ]; then - /usr/bin/signify -C -p "$PKGMK_PUBLICKEY" -x "$PKGMK_ROOT/.signature" \ - "${reqfiles[@]}" 2>&1 - else - /usr/bin/signify -C -x "$PKGMK_ROOT/.signature" \ - "${reqfiles[@]}" 2>&1 - fi + [ -f "$PKGMK_PUBLICKEY" ] && SIGNIFY_ARGS+=(-p "$PKGMK_PUBLICKEY") + /usr/bin/signify "${SIGNIFY_ARGS[@]}" "${reqfiles[@]}" 2>&1 else [ "$when" = "pre-Pkgfile" ] && echo "Pkgfile verification failed" [ "$when" != "pre-Pkgfile" ] && echo "signature verification failed" fi } -cat_signature() { - local ordered si key pub - [ -e "$PKGMK_ROOT/.footprint" ] || warning "Footprint not found, signature will be incomplete." - for key in ~/.ssh/*.sec /etc/ports/*.sec; do - [ -e "$key" ] || continue # workaround for brain-dead shell globbing - pub="/etc/ports/$(basename "${key%.sec}.pub")" - if [ -e "$pub" ]; then - pub=$(readlink -f "$pub") - for f in "$PKGMK_ROOT/Pkgfile" "$PKGMK_ROOT/.footprint"; do - [ -e "$f" ] && ordered+=( "$f" ) - done - for ((si=0; si < ${#source[@]}; si++)); do - # ignore git directories when writing the signature - [[ "${source[si]}" =~ ^__git__ ]] || ordered+=("${_local_[si]}"); done - sha256sum --tag "${ordered[@]}" \ - | sed 's|^SHA256 (.*/\(.*\))\(.* = .*\)|SHA256 (\1)\2|' \ - | /usr/bin/signify -S -e -x - -q -s "$key" -m - \ - | sed "s|${key%.sec}.pub|$pub|" - break - fi +repo_key() { + local typ="${1:0:3}" + for key in "/etc/ports/*.$typ" "$HOME/.ssh/*.$typ"; do + [ -e "$key" ] || continue + REPO="$(dirname "$PWD")"; REPO="$(basename -s .git "$REPO")"; + [ "$REPO" = "$(basename -s ".$typ" "$key")" ] && { echo "$key"; break; } done } -refresh_signature() { - [ -e ".signature" ] || { error "missing .signature, cannot refresh."; return $E_SIGNATURE; } - [ -w ".signature" ] || { error ".signature not writable."; return $E_DIRPERM; } +make_signature() { + local ordered si pub + [ -w "$PKGMK_ROOT/.signature" ] || { error ".signature not writable."; return $E_DIRPERM; } - local REPO - if [ -z "$PKGMK_PRIVATEKEY" ]; then - REPO="$(dirname "$PWD")" - REPO="${REPO##*/}" - REPO="${REPO%.git}" - [ -r "/etc/ports/${REPO}.sec" ] && \ - PKGMK_PRIVATEKEY="/etc/ports/${REPO}.sec" || \ - { error "No suitable secret key found. Specify one explicitly with '-sk'."; return $E_SIGNATURE; } - fi + [ "$PKGMK_PRIVATEKEY" ] || PKGMK_PRIVATEKEY="$(repo_key secret)" + [ -r "$PKGMK_PRIVATEKEY" ] && \ + pub="/etc/ports/$(basename -s ".sec" "$PKGMK_PRIVATEKEY").pub" || \ + { error "No suitable secret key found. Specify one explicitly with '-sk'."; + return $E_SIGNATURE; } - if ! tail -n +3 ".signature" | /usr/bin/signify -S -e -x - -q \ - -s "$PKGMK_PRIVATEKEY" -m - > .signature.tmp ; then - rm .signature.tmp - error "Refreshing signature failed"; return $E_SIGNATURE - else - mv .signature.tmp .signature; info "Signature refreshed." - fi + # distinguish between creating .signature anew, vs. refreshing an existing manifest + case "$1" in + new) + [ -e "$PKGMK_ROOT/.footprint" ] || \ + warning "Footprint not found, signature will be incomplete." + for f in "$PKGMK_ROOT/Pkgfile" "$PKGMK_ROOT/.footprint"; do + [ -e "$f" ] && ordered+=( "$f" ) + done + for ((si=0; si < ${#source[@]}; si++)); do + # ignore git directories when writing the signature + [[ "${source[si]}" =~ ^__git__ ]] || ordered+=("${_local_[si]}") + done + sha256sum --tag "${ordered[@]}" \ + | sed 's|^SHA256 (.*/\(.*\))\(.* = .*\)|SHA256 (\1)\2|' \ + | /usr/bin/signify -S -e -x - -q -s "$PKGMK_PRIVATEKEY" -m - \ + | sed "s|${PKGMK_PRIVATEKEY%.sec}.pub|$pub|" \ + > "$PKGMK_ROOT/.signature" + ;; + refresh) + [ -e ".signature" ] || \ + { error "missing .signature, cannot refresh."; return $E_SIGNATURE; } + if tail -n +3 ".signature" | /usr/bin/signify -S -e -x - -q \ + -s "$PKGMK_PRIVATEKEY" -m - > .signature.tmp; then + mv .signature.tmp .signature; info "Signature refreshed." + else + rm .signature.tmp; return $E_SIGNATURE + fi + ;; + esac } interrupted() { @@ -557,8 +552,7 @@ error() { ## Now ensure that they cannot be overwritten when sourcing Pkgfile ## readonly -f main info warning error print_help parse_options validate_pkgfile \ check_reqvars check_pkg_mtime fetch_url cat_footprint check_footprint \ - cat_signature check_signature parse_signify_output refresh_signature \ - cleanup_work + make_signature repo_key check_signature parse_signify_output cleanup_work trap "interrupted" SIGHUP SIGINT SIGQUIT SIGTERM export LC_ALL=C.UTF-8