guix-verify raw

   1  #!/usr/bin/env bash
   2  export LC_ALL=C
   3  set -e -o pipefail
   4  
   5  # Source the common prelude, which:
   6  #   1. Checks if we're at the top directory of the Bitcoin Core repository
   7  #   2. Defines a few common functions and variables
   8  #
   9  # shellcheck source=libexec/prelude.bash
  10  source "$(dirname "${BASH_SOURCE[0]}")/libexec/prelude.bash"
  11  
  12  
  13  ###################
  14  ## Sanity Checks ##
  15  ###################
  16  
  17  ################
  18  # Required non-builtin commands should be invokable
  19  ################
  20  
  21  check_tools cat diff gpg
  22  
  23  ################
  24  # Required env vars should be non-empty
  25  ################
  26  
  27  cmd_usage() {
  28  cat <<EOF
  29  Synopsis:
  30  
  31      env GUIX_SIGS_REPO=<path/to/guix.sigs> [ SIGNER=<signer> ] ./contrib/guix/guix-verify
  32  
  33  Example overriding signer's manifest to use as base
  34  
  35      env GUIX_SIGS_REPO=/home/dongcarl/guix.sigs SIGNER=achow101 ./contrib/guix/guix-verify
  36  
  37  EOF
  38  }
  39  
  40  if [ -z "$GUIX_SIGS_REPO" ]; then
  41      cmd_usage
  42      exit 1
  43  fi
  44  
  45  ################
  46  # GUIX_SIGS_REPO should exist as a directory
  47  ################
  48  
  49  if [ ! -d "$GUIX_SIGS_REPO" ]; then
  50  cat << EOF
  51  ERR: The specified GUIX_SIGS_REPO is not an existent directory:
  52  
  53      '$GUIX_SIGS_REPO'
  54  
  55  Hint: Please clone the guix.sigs repository and point to it with the
  56        GUIX_SIGS_REPO environment variable.
  57  
  58  EOF
  59  cmd_usage
  60  exit 1
  61  fi
  62  
  63  ##############
  64  ##  Verify  ##
  65  ##############
  66  
  67  OUTSIGDIR_BASE="${GUIX_SIGS_REPO}/${VERSION}"
  68  echo "Looking for signature directories in '${OUTSIGDIR_BASE}'"
  69  echo ""
  70  
  71  # Usage: verify compare_manifest current_manifest
  72  verify() {
  73      local compare_manifest="$1"
  74      local current_manifest="$2"
  75      if ! gpg --quiet --batch --verify "$current_manifest".asc "$current_manifest" 1>&2; then
  76          echo "ERR: Failed to verify GPG signature in '${current_manifest}'"
  77          echo ""
  78          echo "Hint: Either the signature is invalid or the public key is missing"
  79          echo ""
  80          failure=1
  81      elif ! diff --report-identical "$compare_manifest" "$current_manifest" 1>&2; then
  82          echo "ERR: The SHA256SUMS attestation in these two directories differ:"
  83          echo "    '${compare_manifest}'"
  84          echo "    '${current_manifest}'"
  85          echo ""
  86          failure=1
  87      else
  88          echo "Verified: '${current_manifest}'"
  89          echo ""
  90      fi
  91  }
  92  
  93  shopt -s nullglob
  94  all_noncodesigned=( "$OUTSIGDIR_BASE"/*/noncodesigned.SHA256SUMS )
  95  shopt -u nullglob
  96  
  97  echo "--------------------"
  98  echo ""
  99  if (( ${#all_noncodesigned[@]} )); then
 100      compare_noncodesigned="${all_noncodesigned[0]}"
 101      if [[ -n "$SIGNER" ]]; then
 102          signer_noncodesigned="$OUTSIGDIR_BASE/$SIGNER/noncodesigned.SHA256SUMS"
 103          if [[ -f "$signer_noncodesigned" ]]; then
 104              echo "Using $SIGNER's manifest as the base to compare against"
 105              compare_noncodesigned="$signer_noncodesigned"
 106          else
 107              echo "Unable to find $SIGNER's manifest, using the first one found"
 108          fi
 109      else
 110          echo "No SIGNER provided, using the first manifest found"
 111      fi
 112  
 113      for current_manifest in "${all_noncodesigned[@]}"; do
 114          verify "$compare_noncodesigned" "$current_manifest"
 115      done
 116  
 117      echo "DONE: Checking output signatures for noncodesigned.SHA256SUMS"
 118      echo ""
 119  else
 120      echo "WARN: No signature directories with noncodesigned.SHA256SUMS found"
 121      echo ""
 122  fi
 123  
 124  shopt -s nullglob
 125  all_all=( "$OUTSIGDIR_BASE"/*/all.SHA256SUMS )
 126  shopt -u nullglob
 127  
 128  echo "--------------------"
 129  echo ""
 130  if (( ${#all_all[@]} )); then
 131      compare_all="${all_all[0]}"
 132      if [[ -n "$SIGNER" ]]; then
 133          signer_all="$OUTSIGDIR_BASE/$SIGNER/all.SHA256SUMS"
 134          if [[ -f "$signer_all" ]]; then
 135              echo "Using $SIGNER's manifest as the base to compare against"
 136              compare_all="$signer_all"
 137          else
 138              echo "Unable to find $SIGNER's manifest, using the first one found"
 139          fi
 140      else
 141          echo "No SIGNER provided, using the first manifest found"
 142      fi
 143  
 144      for current_manifest in "${all_all[@]}"; do
 145          verify "$compare_all" "$current_manifest"
 146      done
 147  
 148      # Sanity check: there should be no entries that exist in
 149      # noncodesigned.SHA256SUMS that doesn't exist in all.SHA256SUMS
 150      if [[ "$(comm -23 <(sort "$compare_noncodesigned") <(sort "$compare_all") | wc -c)" -ne 0 ]]; then
 151          echo "ERR: There are unique lines in noncodesigned.SHA256SUMS which"
 152          echo "     do not exist in all.SHA256SUMS, something went very wrong."
 153          exit 1
 154      fi
 155  
 156      echo "DONE: Checking output signatures for all.SHA256SUMS"
 157      echo ""
 158  else
 159      echo "WARN: No signature directories with all.SHA256SUMS found"
 160      echo ""
 161  fi
 162  
 163  echo "===================="
 164  echo ""
 165  if (( ${#all_noncodesigned[@]} + ${#all_all[@]} == 0 )); then
 166      echo "ERR: Unable to perform any verifications as no signature directories"
 167      echo "     were found"
 168      echo ""
 169      exit 1
 170  fi
 171  
 172  if [ -n "$failure" ]; then
 173      exit 1
 174  fi
 175