5

From the gpg manual:

--refresh-keys Request updates from a keyserver for keys that already exist on the local keyring. This is useful for updating a key with the latest signatures, user IDs, etc. Calling this with no arguments will refresh the entire keyring.

But there is no claim about how secure this is.

So the questions is:

Is it secure to use gpg --refresh-keys to refresh keys from a malicious keyserver?

This implies the answer to the question, where you can get more information about why this process is considered secure, as without such documentation, the update process is not trustworthy.

Here is the scenario:


Somebody with high power (say somebody between the power of Google and the power of NSA) hacks into a keyserver. The one has enough power to run cryptoanalysis against all keys on the keyserver and is able to break everything which is not cryptographically secure in the current common sense including the forseeable future.

Hence RSA 768 can be broken by the attacker, RSA 4096 not yet, MD5 can be broken with known plaintext (so for any MD5 the attacker can create a document with this MD5), SHA1 can be broken with precomputed collision attack (so an arbitrary SHA1 cannot be broken, but the attacker can create 2 documents with the same SHA1) and so on.

Also this attacker is the perfect MitM between you and the keyserver, because the attacker has 101% control of the keyserver (more than the rightful owner).


Does such a malicious keyserver impose any threat to the the --refresh-keys feature or not?

If not, why not? Where is the proof for this? Where is it documented that the command is safe to use?


Assumptions:

  • The attacker is capable of state-of-the-art cryptoanalysis available to us in 2020 today, on a level of Bruce Schneier.

  • There is no secret knowledge of the attacker. So the attacker neither has unknown knowledge except what is our deepest public knowledge in the cryptoanalysis area today (in 2020).

  • The attacker uses hardware of the edge of state of the art today. So if there are - today - known how we could build special hardware like FPGA or render engines to break security, the attacker already has it available as of today.

  • The attacker does not use hardware from the future, so no design we do not already know how to build or really could manufacture today. But he has access to hardware of FABs which are currently in planning already (so we know how to manufacture, but currently are just lacking the FABs for this. So the attacker has access to all such technology we can build in a few years with the knowledge of today).

  • The attacker has the available computing power and storage capacity of 2030, so can mount attacks already today which would be very expensive with our today's computing power. Say, the attacker is able to use the estimated computing power today which can be bought in 2030 for $10,000,000 (ten million dollars) which should cost more than 1 billion dollars today. So the power is around what the clouds of Google/AWS/Azure offer for extreme customers, so is just a bit less than what the NSA could do.

  • There is no zero-day exploit which imposes a danger to the GPG-client doing the request against the malicious keyserver. Also the computer used and the OS used are secure with no backdoors nor remote exploits.


My current fallback to --refresh-keys:

  • Download the new key
  • Compare the cryptographic hash of both, the old and the new key (output of gpg key.pgp)
  • Only update the old key if both hashes are the same

Perhaps --refresh-keys does exactly that? Why doesn't it tell so?


Example:

$ gpg yarnpkg.gpg.pub                                                                                                                                                                        
gpg: WARNING: no command supplied.  Trying to guess what you mean ...                                                                                                                        
pub   rsa4096 2016-10-05 [SC]
      72ECF46A56B4AD39C907BBB71646B01B86E50310
uid           Yarn Packaging <yarn@dan.cx>
sub   rsa4096 2016-10-05 [E]
sub   rsa4096 2016-10-05 [S] [expired: 2017-10-05]
sub   rsa4096 2016-10-30 [S] [expired: 2019-01-01]
sub   rsa4096 2017-09-10 [S] [expired: 2019-01-01]
sub   rsa4096 2019-01-02 [S] [expires: 2021-02-03]
sub   rsa4096 2019-01-11 [S] [expires: 2021-02-03]
$ gpg /etc/apt/trusted.gpg.d/yarnpkg.gpg
gpg: WARNING: no command supplied.  Trying to guess what you mean ...
pub   rsa4096 2016-10-05 [SC]
      72ECF46A56B4AD39C907BBB71646B01B86E50310
uid           Yarn Packaging <yarn@dan.cx>
sub   rsa4096 2016-10-05 [E]
sub   rsa4096 2016-10-05 [S] [expired: 2017-10-05]
sub   rsa4096 2016-10-30 [S] [expired: 2019-01-01]
sub   rsa4096 2017-09-10 [S] [expired: 2019-01-01]
sub   rsa4096 2019-01-02 [S] [expired: 2020-02-02]
sub   rsa4096 2019-01-11 [S] [expired: 2020-02-02]

Here we see that 72ECF46A56B4AD39C907BBB71646B01B86E50310 is the same on both.

Hence the new one (with subkey which expires 2021) can be considered a safe successor to the old own (with subkey which already is expired).

But this is a manual and clumsy way of updating. And I cannot see that --refresh-keys has - at least - the same safe properties as the manual process, if the manual process is properly done.

Notes:

  • In this case we do not have other information available like the web-of-trust etc.

  • And it is not the question if I can trust the old key. The question is, can I trust the new key after --refresh-keys at the same level as after the update example above.

  • I tried to google for is gpg refresh-keys secure and similar, but this did not reveal any trace of an answer to me nor any documentation about what --refresh-keys is supposed to do.

  • I even tried to understand the source, but failed to build up enough understanding, what this command exactly does and I cannot make sure that it cannot have some bad sideffect (possibly unknown to me due to lack of some details of the GPG source code).

  • Also please forgive me that I lack the ability to shorten this answer without leaving out perhaps important details or nuances as English is not my native language.

Tino
  • 191
  • 6

1 Answers1

1

The 72ECF46A56B4AD39C907BBB71646B01B86E50310 in your post is called the fingerprint.

I just looked at the source code (commit 5986310866527e37c6df118b1582177934522e39, for future reference) for --refresh-keys. One of the things it does is this:

  /* We switch merge-only on during a refresh, as 'refresh' should
     never import new keys, even if their keyids match. */
  opt.keyserver_options.import_options|=IMPORT_MERGE_ONLY;

This implies --import-options merge-only. When this option is enabled, only keys with a matching fingerprint are updated—keys with a non-matching fingerprint are skipped:

  /* Do we have this key already in one of our pubrings ? */
  err = get_keyblock_byfprint_fast (ctrl, &keyblock_orig, &hd,
                                    fpr2, fpr2len, 1/*locked*/);
  /* ... */
  else if (err && (opt.import_options&IMPORT_MERGE_ONLY) )
    {
      if (opt.verbose && !silent )
        log_info( _("key %s: new key - skipped\n"), keystr(keyid));
      err = 0;
      stats->skipped_new_keys++;
    }

This does the same thing as your manual fingerprint check. Thus it's safe in that an attacker cannot inject arbitrary keys into your keyring.

C. K. Young
  • 111
  • 4
  • But is that even relevant? Your answer seems correct, but ultimately your trust on sig checks is based on the input trust you gave to known good keys and derived trust from keys signed by these trusted keys. If Bob trust Alice's X key, and before expiry Alice creates Y and signs her new key, Y, using X, then you end up trusting Y. It doesn't matter if you even trust the keyserver that provided Y because you can verify that Alice's trusted X key signed it. – Thomas Guyot-Sionnest Jul 07 '22 at 12:21