From 23106ac0f55623a155c1e74633890f7fb7d52d36 Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Thu, 26 Aug 2021 21:59:44 +0200 Subject: Set pubkey trust to ultimate during `gpg trust` (#24976) * Set pubkey trust to ultimate during `gpg trust` Tries to solve the same problem as #24760 without surpressing stderr from gpg commands. This PR makes every imported key trusted in the gpg database. Note: I've outlined [here](https://github.com/spack/spack/pull/24760#issuecomment-883183175) that gpg's trust model makes sense, since how can we trust a random public key we download from a binary cache? * Fix test --- lib/spack/spack/util/gpg.py | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/lib/spack/spack/util/gpg.py b/lib/spack/spack/util/gpg.py index 787f205a13..ddc69c9579 100644 --- a/lib/spack/spack/util/gpg.py +++ b/lib/spack/spack/util/gpg.py @@ -133,20 +133,33 @@ def _parse_secret_keys_output(output): def _parse_public_keys_output(output): + """ + Returns a list of public keys with their fingerprints + """ keys = [] found_pub = False + current_pub_key = '' for line in output.split('\n'): if found_pub: if line.startswith('fpr'): - keys.append(line.split(':')[9]) + keys.append((current_pub_key, line.split(':')[9])) found_pub = False elif line.startswith('ssb'): found_pub = False elif line.startswith('pub'): + current_pub_key = line.split(':')[4] found_pub = True return keys +def _get_unimported_public_keys(output): + keys = [] + for line in output.split('\n'): + if line.startswith('pub'): + keys.append(line.split(':')[4]) + return keys + + class SpackGPGError(spack.error.SpackError): """Class raised when GPG errors are detected.""" @@ -182,7 +195,7 @@ def signing_keys(*args): @_autoinit -def public_keys(*args): +def public_keys_to_fingerprint(*args): """Return the keys that can be used to verify binaries.""" output = GPG( '--list-public-keys', '--with-colons', '--fingerprint', @@ -191,6 +204,13 @@ def public_keys(*args): return _parse_public_keys_output(output) +@_autoinit +def public_keys(*args): + """Return a list of fingerprints""" + keys_and_fpr = public_keys_to_fingerprint(*args) + return [key_and_fpr[1] for key_and_fpr in keys_and_fpr] + + @_autoinit def export_keys(location, keys, secret=False): """Export public keys to a location passed as argument. @@ -208,13 +228,32 @@ def export_keys(location, keys, secret=False): @_autoinit def trust(keyfile): - """Import a public key from a file. + """Import a public key from a file and trust it. Args: keyfile (str): file with the public key """ + # Get the public keys we are about to import + output = GPG('--with-colons', keyfile, output=str, error=str) + keys = _get_unimported_public_keys(output) + + # Import them GPG('--import', keyfile) + # Set trust to ultimate + key_to_fpr = dict(public_keys_to_fingerprint()) + for key in keys: + # Skip over keys we cannot find a fingerprint for. + if key not in key_to_fpr: + continue + + fpr = key_to_fpr[key] + r, w = os.pipe() + with contextlib.closing(os.fdopen(r, 'r')) as r: + with contextlib.closing(os.fdopen(w, 'w')) as w: + w.write("{0}:6:\n".format(fpr)) + GPG('--import-ownertrust', input=r) + @_autoinit def untrust(signing, *keys): -- cgit v1.2.3-70-g09d2