On 07/09/13 07:10 AM, Peter Lebbing wrote:
On 27/06/13 18:55, Jack Bates wrote:
except that I am using the key id of a subkey, with an exclamation
mark, to export just one subkey instead of all the subkeys belonging to the
primary key. The subkey with that key id definitely doesn't already exist in the
destination keyring, although the destination keyring does already contain a
different subkey.

I believe once GnuPG has a secret key, it won't update it anymore with any
subsequent imports. So to get the additional subkey, re-export the whole thing,
delete the existing one on the other system and import your re-exported whole 
thing.

I'm also wondering why you're being so explicit about it in the first place,
with transferring little chunks at a time using the exclamation mark instead of
the whole thing. Is there something specific you're trying to achieve?

    gpg:  secret keys unchanged: 1

This message to me implies it is actually possible to change something about a
secret key. I haven't figured out what yet.

Thank you for following up Peter, I looked again and I think it's a difference between public vs. secret subkeys. It will merge a new public subkey with existing subkeys, but it won't merge a new secret subkey with existing ones. Here is a first crack at a patch to merge new secret subkeys similar to how it already handles public ones:

   http://nottheoilrig.com/gnupg/201309120/merge.patch

I'd love to contribute a change like this to GnuPG, would a change like this be welcome? (considered for inclusion?) If so, can anyone help me review it and get it into shape? What is the right way to submit a patch to GnuPG?

Here's what GnuPG does before and after the patch:

   # Generate primary key
   $ gpg2 --gen-key

   pub   4096R/B575FAD1 2013-09-12
Key fingerprint = 19C1 3488 6B2A A80C E30A 6A96 4CB2 EAFB B575 FAD1
   uid                  John Doe <j...@example.com>

   # Add subkey
   $ gpg2 --edit-key B575FAD1 addkey

pub 4096R/B575FAD1 created: 2013-09-12 expires: never usage: SC
                        trust: ultimate      validity: ultimate
sub 4096R/3BEA5E48 created: 2013-09-12 expires: 2013-09-13 usage: S

   # Export secret subkey
   $ gpg2 --export-secret-subkeys 3BEA5E48! > 3BEA5E48

   # Add another subkey
   gpg2 --edit-key B575FAD1 addkey

pub 4096R/B575FAD1 created: 2013-09-12 expires: never usage: SC
                        trust: ultimate      validity: ultimate
sub 4096R/3BEA5E48 created: 2013-09-12 expires: 2013-09-13 usage: S sub 4096R/1F01C58C created: 2013-09-12 expires: 2013-09-13 usage: S

   # Export other secret subkey
   $ gpg2 --export-secret-subkeys 1F01C58C! > 1F01C58C

   # Start over with an empty keyring
   $ rm -r ~/.gnupg

   # Import first subkey
   $ gpg2 --import 3BEA5E48

   gpg: key B575FAD1: secret key imported
   gpg: key B575FAD1: public key "John Doe <j...@example.com>" imported
   gpg: Total number processed: 1
   gpg:               imported: 1  (RSA: 1)
   gpg:       secret keys read: 1
   gpg:   secret keys imported: 1

Here's what it does before the patch:

   # Import second subkey
   $ gpg2 --import 1F01C58C

   gpg: key B575FAD1: already in secret keyring
   gpg: Total number processed: 1
   gpg:       secret keys read: 1
   gpg:  secret keys unchanged: 1

   $ gpg2 -K

   sec#  4096R/B575FAD1 2013-09-12
   uid                  John Doe <j...@example.com>
   ssb   4096R/3BEA5E48 2013-09-12

And here's what happens after the patch:

   # Import second subkey
   $ gpg2 --import 1F01C58C

   gpg: key B575FAD1: "John Doe <j...@example.com>" 1 new signature
   gpg: key B575FAD1: "John Doe <j...@example.com>" 1 new subkey
   gpg: key B575FAD1: "John Doe <j...@example.com>" 1 new signature
   gpg: key B575FAD1: "John Doe <j...@example.com>" 1 new subkey
   gpg: Total number processed: 1
   gpg:            new subkeys: 2
   gpg:         new signatures: 2
   gpg:       secret keys read: 1

   $ gpg2 -K

   sec#  4096R/B575FAD1 2013-09-12
   uid                  John Doe <j...@example.com>
   ssb   4096R/3BEA5E48 2013-09-12
   ssb   4096R/1F01C58C 2013-09-12

I looked at the code in gnupg/g10/import.c and when you import something, the import() procedure gets called once by import_keys_internal(), etc. The import_one() procedure gets called if import() finds a PKT_PUBLIC_KEY keyblock and import_secret_one() gets called if it finds a PKT_SECRET_KEY keyblock. After import_secret_one() imports a new secret key, it converts it to a public key with sec_to_pub_keyblock() and passes that to import_one().

import_one() and import_secret_one() both check if the key already exists in the keyring. If import_one() finds that it does, it reads the existing keyblock, calls merge_blocks(), and if anything changed it writes back the updated keyblock.

However if import_secret_one() finds that the key already exists, currently it just says:

1273     else if( !rc )
1274       { /* we can't merge secret keys */
1275         log_error( _("key %s: already in secret keyring\n"),
1276                    keystr_from_sk(sk));
1277         stats->secret_dups++;
1278         if (is_status_enabled ())
1279           print_import_ok (NULL, sk, 16);
1280
1281         /* TODO: if we ever do merge secret keys, make sure to handle
1282            the sec_to_pub_keyblock feature as well. */
1283       }

To make the patch, I cargo-culted a combination of code from where import_secret_one() imports new secret keys and where import_one() merges new public subkeys with existing ones. It reads the existing keyblock, calls merge_blocks(), and writes back the updated keyblock if anything changed.

I am grateful for feedback or help getting the patch into shape, if this is a welcome change.

Thanks!

_______________________________________________
Gnupg-users mailing list
Gnupg-users@gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-users

Reply via email to