aboutsummaryrefslogtreecommitdiff
path: root/contrib/verifybinaries
diff options
context:
space:
mode:
authorAndrew Chow <github@achow101.com>2023-03-22 22:07:50 -0400
committerCory Fields <cory-nospam-@coryfields.com>2023-03-28 22:16:05 +0000
commit6b2cebfa2f1526f7eae31eb645c71712f0a69e97 (patch)
tree0d7c7defaadeb4a1e6ea7ac10ce22088d424ca94 /contrib/verifybinaries
parente4d577822835d4866e2ad046f23ab411b2910d59 (diff)
downloadbitcoin-6b2cebfa2f1526f7eae31eb645c71712f0a69e97.tar.xz
contrib: Add verifybinaries command for specifying files to verify
In addition to verifying the published releases with the `pub` command, the verifybinaries script is updated to take a `bin` command where the user specifies the local files, sums, and sigs to verify.
Diffstat (limited to 'contrib/verifybinaries')
-rwxr-xr-xcontrib/verifybinaries/verify.py82
1 files changed, 79 insertions, 3 deletions
diff --git a/contrib/verifybinaries/verify.py b/contrib/verifybinaries/verify.py
index 4af7e40af2..76986aa090 100755
--- a/contrib/verifybinaries/verify.py
+++ b/contrib/verifybinaries/verify.py
@@ -42,7 +42,7 @@ import textwrap
import urllib.request
import enum
from hashlib import sha256
-from pathlib import Path
+from pathlib import PurePath
# The primary host; this will fail if we can't retrieve files from here.
HOST1 = "https://bitcoincore.org"
@@ -440,11 +440,11 @@ def verify_shasums_signature(
return (ReturnCode.SUCCESS, good_trusted, good_untrusted, unknown, bad)
-def parse_sums_file(sums_file_path: Path, filename_filter: str) -> t.List[t.List[str]]:
+def parse_sums_file(sums_file_path: str, filename_filter: t.List[str]) -> t.List[t.List[str]]:
# extract hashes/filenames of binaries to verify from hash file;
# each line has the following format: "<hash> <binary_filename>"
with open(sums_file_path, 'r', encoding='utf8') as hash_file:
- return [line.split()[:2] for line in hash_file if filename_filter in line]
+ return [line.split()[:2] for line in hash_file if len(filename_filter) == 0 or any(f in line for f in filename_filter)]
def verify_binary_hashes(hashes_to_verify: t.List[t.List[str]]) -> t.Tuple[ReturnCode, t.Dict[str, str]]:
@@ -579,6 +579,73 @@ def verify_published_handler(args: argparse.Namespace) -> ReturnCode:
return ReturnCode.SUCCESS
+def verify_binaries_handler(args: argparse.Namespace) -> ReturnCode:
+ binary_to_basename = {}
+ for file in args.binary:
+ binary_to_basename[PurePath(file).name] = file
+
+ sums_sig_path = None
+ if args.sums_sig_file:
+ sums_sig_path = Path(args.sums_sig_file)
+ else:
+ log.info(f"No signature file specified, assuming it is {args.sums_file}.asc")
+ sums_sig_path = Path(args.sums_file).with_suffix(".asc")
+
+ # Verify the signature on the SHA256SUMS file
+ sigs_status, good_trusted, good_untrusted, unknown, bad = verify_shasums_signature(sums_sig_path, args.sums_file, args)
+ if sigs_status != ReturnCode.SUCCESS:
+ return sigs_status
+
+ # Extract hashes and filenames
+ hashes_to_verify = parse_sums_file(args.sums_file, [k for k, n in binary_to_basename.items()])
+ if not hashes_to_verify:
+ log.error(f"No files in {args.sums_file} match the specified binaries")
+ return ReturnCode.NO_BINARIES_MATCH
+
+ # Make sure all files are accounted for
+ sums_file_path = Path(args.sums_file)
+ missing_files = []
+ files_to_hash = []
+ if len(binary_to_basename) > 0:
+ for file_hash, file in hashes_to_verify:
+ files_to_hash.append([file_hash, binary_to_basename[file]])
+ del binary_to_basename[file]
+ if len(binary_to_basename) > 0:
+ log.error(f"Not all specified binaries are in {args.sums_file}")
+ return ReturnCode.NO_BINARIES_MATCH
+ else:
+ log.info(f"No binaries specified, assuming all files specified in {args.sums_file} are located relatively")
+ for file_hash, file in hashes_to_verify:
+ file_path = Path(sums_file_path.parent.joinpath(file))
+ if file_path.exists():
+ files_to_hash.append([file_hash, str(file_path)])
+ else:
+ missing_files.append(file)
+
+ # verify hashes
+ hashes_status, files_to_hashes = verify_binary_hashes(files_to_hash)
+ if hashes_status != ReturnCode.SUCCESS:
+ return hashes_status
+
+ if args.json:
+ output = {
+ 'good_trusted_sigs': [str(s) for s in good_trusted],
+ 'good_untrusted_sigs': [str(s) for s in good_untrusted],
+ 'unknown_sigs': [str(s) for s in unknown],
+ 'bad_sigs': [str(s) for s in bad],
+ 'verified_binaries': files_to_hashes,
+ "missing_binaries": missing_files,
+ }
+ print(json.dumps(output, indent=2))
+ else:
+ for filename in files_to_hashes:
+ print(f"VERIFIED: {filename}")
+ for filename in missing_files:
+ print(f"MISSING: {filename}")
+
+ return ReturnCode.SUCCESS
+
+
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
@@ -638,6 +705,15 @@ def main():
'(Sometimes bitcoin.org lags behind bitcoincore.org.)')
)
+ bin_parser = subparsers.add_parser("bin", help="Verify local binaries.")
+ bin_parser.set_defaults(func=verify_binaries_handler)
+ bin_parser.add_argument("--sums-sig-file", "-s", help="Path to the SHA256SUMS.asc file to verify")
+ bin_parser.add_argument("sums_file", help="Path to the SHA256SUMS file to verify")
+ bin_parser.add_argument(
+ "binary", nargs="*",
+ help="Path to a binary distribution file to verify. Can be specified multiple times for multiple files to verify."
+ )
+
args = parser.parse_args()
if args.quiet:
log.setLevel(logging.WARNING)