Package: gnupg2 / 2.2.12-1+deb10u1

from-2.2.14/gpg-Allow-import-of-PGP-desktop-exported-secret-keys.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
From: Werner Koch <wk@gnupg.org>
Date: Mon, 18 Mar 2019 13:07:14 +0100
Subject: gpg: Allow import of PGP desktop exported secret keys.

* g10/import.c (NODE_TRANSFER_SECKEY): New.
(import): Add attic kludge.
(transfer_secret_keys): Add arg only_marked.
(resync_sec_with_pub_keyblock): Return removed seckeys via new arg
r_removedsecs.
(import_secret_one): New arg r_secattic.  Change to take ownership of
arg keyblock.  Implement extra secret key import logic.  Factor some
code out to ...
(do_transfer): New.
(import_matching_seckeys): New.
--

The PGP desktops exported secret keys are really stupid.  And they
even a have kind of exception in rfc4880 which does not rule that
out (section 11.2):

  [...]  Implementations SHOULD include self-signatures on any user
  IDs and subkeys, as this allows for a complete public key to be
  automatically extracted from the transferable secret key.
  Implementations MAY choose to omit the self-signatures, especially
  if a transferable public key accompanies the transferable secret
  key.

Now if they would only put the public key before the secret
key. Anyway we now have a workaround for that ugliness.

GnuPG-bug-id: 4392
Signed-off-by: Werner Koch <wk@gnupg.org>
(cherry picked from commit 5205512fc092c53c0a52c8379ef2a129ce6e58a9)
(cherry picked from commit 0e73214dd208fca4df26ac796416c6f25b3ae50d)
---
 g10/import.c  | 381 ++++++++++++++++++++++++++++++++++++++++++++++------------
 g10/keyedit.c |   2 +-
 g10/main.h    |   3 +-
 3 files changed, 307 insertions(+), 79 deletions(-)

diff --git a/g10/import.c b/g10/import.c
index 2a01814..f76ca0c 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -1,6 +1,6 @@
 /* import.c - import a key into our key storage.
  * Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
- * Copyright (C) 2014, 2016, 2017  Werner Koch
+ * Copyright (C) 2014, 2016, 2017, 2019  Werner Koch
  *
  * This file is part of GnuPG.
  *
@@ -75,6 +75,8 @@ struct import_stats_s
 #define NODE_DELETION_MARK 4
 /* A node flag used to temporary mark a node. */
 #define NODE_FLAG_A  8
+/* A flag used by transfer_secret_keys. */
+#define NODE_TRANSFER_SECKEY 16
 
 
 /* An object and a global instance to store selectors created from
@@ -110,10 +112,15 @@ static gpg_error_t import_one (ctrl_t ctrl,
                        unsigned int options, int from_sk, int silent,
                        import_screener_t screener, void *screener_arg,
                        int origin, const char *url, int *r_valid);
+static gpg_error_t import_matching_seckeys (
+                       ctrl_t ctrl, kbnode_t seckeys,
+                       const byte *mainfpr, size_t mainfprlen,
+                       struct import_stats_s *stats, int batch);
 static gpg_error_t import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
                               struct import_stats_s *stats, int batch,
                               unsigned int options, int for_migration,
-                              import_screener_t screener, void *screener_arg);
+                              import_screener_t screener, void *screener_arg,
+                              kbnode_t *r_secattic);
 static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
                                struct import_stats_s *stats);
 static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
@@ -562,6 +569,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
   kbnode_t keyblock = NULL;  /* Need to initialize because gcc can't
                                 grasp the return semantics of
                                 read_block. */
+  kbnode_t secattic = NULL;  /* Kludge for PGP desktop percularity */
   int rc = 0;
   int v3keys;
 
@@ -582,18 +590,63 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
     {
       stats->v3keys += v3keys;
       if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
-        rc = import_one (ctrl, keyblock,
-                         stats, fpr, fpr_len, options, 0, 0,
-                         screener, screener_arg, origin, url, NULL);
+        {
+          rc = import_one (ctrl, keyblock,
+                           stats, fpr, fpr_len, options, 0, 0,
+                           screener, screener_arg, origin, url, NULL);
+          if (secattic)
+            {
+              byte tmpfpr[MAX_FINGERPRINT_LEN];
+              size_t tmpfprlen;
+
+              if (!rc && !(opt.dry_run || (options & IMPORT_DRY_RUN)))
+                {
+                  /* Kudge for PGP desktop - see below.  */
+                  fingerprint_from_pk (keyblock->pkt->pkt.public_key,
+                                       tmpfpr, &tmpfprlen);
+                  rc = import_matching_seckeys (ctrl, secattic,
+                                                tmpfpr, tmpfprlen,
+                                                stats, opt.batch);
+                }
+              release_kbnode (secattic);
+              secattic = NULL;
+            }
+        }
       else if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
-        rc = import_secret_one (ctrl, keyblock, stats,
-                                opt.batch, options, 0,
-                                screener, screener_arg);
+        {
+          release_kbnode (secattic);
+          secattic = NULL;
+          rc = import_secret_one (ctrl, keyblock, stats,
+                                  opt.batch, options, 0,
+                                  screener, screener_arg, &secattic);
+          keyblock = NULL;  /* Ownership was transferred.  */
+          if (secattic)
+            {
+              if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
+                rc = 0; /* Try import after the next pubkey.  */
+
+              /* The attic is a workaround for the peculiar PGP
+               * Desktop method of exporting a secret key: The
+               * exported file is the concatenation of two armored
+               * keyblocks; first the private one and then the public
+               * one.  The strange thing is that the secret one has no
+               * binding signatures at all and thus we have not
+               * imported it.  The attic stores that secret keys and
+               * we try to import it once after the very next public
+               * keyblock.  */
+            }
+        }
       else if (keyblock->pkt->pkttype == PKT_SIGNATURE
                && IS_KEY_REV (keyblock->pkt->pkt.signature) )
-        rc = import_revoke_cert (ctrl, keyblock, options, stats);
+        {
+          release_kbnode (secattic);
+          secattic = NULL;
+          rc = import_revoke_cert (ctrl, keyblock, options, stats);
+        }
       else
         {
+          release_kbnode (secattic);
+          secattic = NULL;
           log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
 	}
       release_kbnode (keyblock);
@@ -619,6 +672,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
   else if (rc && gpg_err_code (rc) != GPG_ERR_INV_KEYRING)
     log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (rc));
 
+  release_kbnode (secattic);
   return rc;
 }
 
@@ -655,8 +709,11 @@ import_old_secring (ctrl_t ctrl, const char *fname)
   while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys)))
     {
       if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
-        err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
-                                 NULL, NULL);
+        {
+          err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
+                                   NULL, NULL, NULL);
+          keyblock = NULL; /* Ownership was transferred.  */
+        }
       release_kbnode (keyblock);
       if (err)
         break;
@@ -2159,12 +2216,15 @@ import_one (ctrl_t ctrl,
 
 
 /* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent.  The
-   function prints diagnostics and returns an error code.  If BATCH is
-   true the secret keys are stored by gpg-agent in the transfer format
-   (i.e. no re-protection and aksing for passphrases). */
+ * function prints diagnostics and returns an error code.  If BATCH is
+ * true the secret keys are stored by gpg-agent in the transfer format
+ * (i.e. no re-protection and aksing for passphrases). If ONLY_MARKED
+ * is set, only those nodes with flag NODE_TRANSFER_SECKEY are
+ * processed.  */
 gpg_error_t
 transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
-                      kbnode_t sec_keyblock, int batch, int force)
+                      kbnode_t sec_keyblock, int batch, int force,
+                      int only_marked)
 {
   gpg_error_t err = 0;
   void *kek = NULL;
@@ -2205,12 +2265,16 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
   xfree (kek);
   kek = NULL;
 
+  /* Note: We need to use walk_kbnode so that we skip nodes which are
+   * marked as deleted.  */
   main_pk = NULL;
   while ((node = walk_kbnode (sec_keyblock, &ctx, 0)))
     {
       if (node->pkt->pkttype != PKT_SECRET_KEY
           && node->pkt->pkttype != PKT_SECRET_SUBKEY)
         continue;
+      if (only_marked && !(node->flag & NODE_TRANSFER_SECKEY))
+        continue;
       pk = node->pkt->pkt.public_key;
       if (!main_pk)
         main_pk = pk;
@@ -2508,12 +2572,15 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
 /* Delete all notes in the keyblock at R_KEYBLOCK which are not in
  * PUB_KEYBLOCK.  Modifies the tags of both keyblock's nodes.  */
 static gpg_error_t
-resync_sec_with_pub_keyblock (kbnode_t *r_keyblock, kbnode_t pub_keyblock)
+resync_sec_with_pub_keyblock (kbnode_t *r_keyblock, kbnode_t pub_keyblock,
+                              kbnode_t *r_removedsecs)
 {
   kbnode_t sec_keyblock = *r_keyblock;
-  kbnode_t node;
+  kbnode_t node, prevnode;
   unsigned int *taglist;
   unsigned int ntaglist, n;
+  kbnode_t attic = NULL;
+  kbnode_t *attic_head = &attic;
 
   /* Collect all tags in an array for faster searching.  */
   for (ntaglist = 0, node = pub_keyblock; node; node = node->next)
@@ -2525,40 +2592,188 @@ resync_sec_with_pub_keyblock (kbnode_t *r_keyblock, kbnode_t pub_keyblock)
     taglist[ntaglist++] = node->tag;
 
   /* Walks over the secret keyblock and delete all nodes which are not
-   * in the tag list.  Those nodes have been delete in the
-   * pub_keyblock.  Sequential search is a bit lazt and could be
-   * optimized by sorting and bsearch; however secret key rings are
-   * short and there are easier weaus to DoS gpg.  */
-  for (node = sec_keyblock; node; node = node->next)
+   * in the tag list.  Those nodes have been deleted in the
+   * pub_keyblock.  Sequential search is a bit lazy and could be
+   * optimized by sorting and bsearch; however secret keyrings are
+   * short and there are easier ways to DoS the import.  */
+ again:
+  for (prevnode=NULL, node=sec_keyblock; node; prevnode=node, node=node->next)
     {
       for (n=0; n < ntaglist; n++)
         if (taglist[n] == node->tag)
           break;
-      if (n == ntaglist)
-        delete_kbnode (node);
+      if (n == ntaglist)  /* Not in public keyblock.  */
+        {
+          if (node->pkt->pkttype == PKT_SECRET_KEY
+              || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+            {
+              if (!prevnode)
+                sec_keyblock = node->next;
+              else
+                prevnode->next = node->next;
+              node->next = NULL;
+              *attic_head = node;
+              attic_head = &node->next;
+              goto again;  /* That's lame; I know.  */
+            }
+          else
+            delete_kbnode (node);
+        }
     }
 
   xfree (taglist);
 
   /* Commit the as deleted marked nodes and return the possibly
-   * modified keyblock.  */
+   * modified keyblock and a list of removed secret key nodes.  */
   commit_kbnode (&sec_keyblock);
   *r_keyblock = sec_keyblock;
+  *r_removedsecs = attic;
   return 0;
 }
 
 
-/****************
- * Ditto for secret keys.  Handling is simpler than for public keys.
- * We allow secret key importing only when allow is true, this is so
- * that a secret key can not be imported accidentally and thereby tampering
- * with the trust calculation.
+/* Helper for import_secret_one.  */
+static gpg_error_t
+do_transfer (ctrl_t ctrl, kbnode_t keyblock, PKT_public_key *pk,
+             struct import_stats_s *stats, int batch, int only_marked)
+
+{
+  gpg_error_t err;
+  struct import_stats_s subkey_stats = {0};
+
+  err = transfer_secret_keys (ctrl, &subkey_stats, keyblock,
+                              batch, 0, only_marked);
+  if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
+    {
+      /* TRANSLATORS: For a smartcard, each private key on host has a
+       * reference (stub) to a smartcard and actual private key data
+       * is stored on the card.  A single smartcard can have up to
+       * three private key data.  Importing private key stub is always
+       * skipped in 2.1, and it returns GPG_ERR_NOT_PROCESSED.
+       * Instead, user should be suggested to run 'gpg --card-status',
+       * then, references to a card will be automatically created
+       * again.  */
+      log_info (_("To migrate '%s', with each smartcard, "
+                  "run: %s\n"), "secring.gpg", "gpg --card-status");
+      err = 0;
+    }
+
+  if (!err)
+    {
+      int status = 16;
+
+      if (!opt.quiet)
+        log_info (_("key %s: secret key imported\n"), keystr_from_pk (pk));
+      if (subkey_stats.secret_imported)
+        {
+          status |= 1;
+          stats->secret_imported += 1;
+        }
+      if (subkey_stats.secret_dups)
+        stats->secret_dups += 1;
+
+      if (is_status_enabled ())
+        print_import_ok (pk, status);
+    }
+
+  return err;
+}
+
+
+/* If the secret keys (main or subkey) in SECKEYS have a corresponding
+ * public key in the public key described by (FPR,FPRLEN) import these
+ * parts.
+ */
+static gpg_error_t
+import_matching_seckeys (ctrl_t ctrl, kbnode_t seckeys,
+                         const byte *mainfpr, size_t mainfprlen,
+                         struct import_stats_s *stats, int batch)
+{
+  gpg_error_t err;
+  kbnode_t pub_keyblock = NULL;
+  kbnode_t node;
+  struct { byte fpr[MAX_FINGERPRINT_LEN]; size_t fprlen; } *fprlist = NULL;
+  size_t n, nfprlist;
+  byte fpr[MAX_FINGERPRINT_LEN];
+  size_t fprlen;
+  PKT_public_key *pk;
+
+  /* Get the entire public key block from our keystore and put all its
+   * fingerprints into an array.  */
+  err = get_pubkey_byfprint (ctrl, NULL, &pub_keyblock, mainfpr, mainfprlen);
+  if (err)
+    goto leave;
+  log_assert (pub_keyblock && pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+  pk = pub_keyblock->pkt->pkt.public_key;
+
+  for (nfprlist = 0, node = pub_keyblock; node; node = node->next)
+    if (node->pkt->pkttype == PKT_PUBLIC_KEY
+        || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+      nfprlist++;
+  log_assert (nfprlist);
+  fprlist = xtrycalloc (nfprlist, sizeof *fprlist);
+  if (!fprlist)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
+  for (n = 0, node = pub_keyblock; node; node = node->next)
+    if (node->pkt->pkttype == PKT_PUBLIC_KEY
+        || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+      {
+        fingerprint_from_pk (node->pkt->pkt.public_key,
+                             fprlist[n].fpr, &fprlist[n].fprlen);
+        n++;
+      }
+  log_assert (n == nfprlist);
+
+  /* for (n=0; n < nfprlist; n++) */
+  /*   log_printhex (fprlist[n].fpr, fprlist[n].fprlen, "pubkey %zu:", n); */
+
+  /* Mark all secret keys which have a matching public key part in
+   * PUB_KEYBLOCK.  */
+  for (node = seckeys; node; node = node->next)
+    {
+      if (node->pkt->pkttype != PKT_SECRET_KEY
+          && node->pkt->pkttype != PKT_SECRET_SUBKEY)
+        continue; /* Should not happen.  */
+      fingerprint_from_pk (node->pkt->pkt.public_key, fpr, &fprlen);
+      node->flag &= ~NODE_TRANSFER_SECKEY;
+      for (n=0; n < nfprlist; n++)
+        if (fprlist[n].fprlen == fprlen && !memcmp (fprlist[n].fpr,fpr,fprlen))
+          {
+            node->flag |= NODE_TRANSFER_SECKEY;
+            /* log_debug ("found matching seckey\n"); */
+            break;
+          }
+    }
+
+  /* Transfer all marked keys.  */
+  err = do_transfer (ctrl, seckeys, pk, stats, batch, 1);
+
+ leave:
+  xfree (fprlist);
+  release_kbnode (pub_keyblock);
+  return err;
+}
+
+
+/* Import function for a single secret keyblock.  Handling is simpler
+ * than for public keys.  We allow secret key importing only when
+ * allow is true, this is so that a secret key can not be imported
+ * accidentally and thereby tampering with the trust calculation.
+ *
+ * Ownership of KEYBLOCK is transferred to this function!
+ *
+ * If R_SECATTIC is not null the last special sec_keyblock is stored
+ * there.
  */
 static gpg_error_t
 import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
                    struct import_stats_s *stats, int batch,
                    unsigned int options, int for_migration,
-                   import_screener_t screener, void *screener_arg)
+                   import_screener_t screener, void *screener_arg,
+                   kbnode_t *r_secattic)
 {
   PKT_public_key *pk;
   struct seckey_info *ski;
@@ -2567,6 +2782,9 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
   gpg_error_t err = 0;
   int nr_prev;
   kbnode_t pub_keyblock;
+  kbnode_t attic = NULL;
+  byte fpr[MAX_FINGERPRINT_LEN];
+  size_t fprlen;
   char pkstrbuf[PUBKEY_STRING_SIZE];
 
   /* Get the key and print some info about it */
@@ -2576,6 +2794,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
 
   pk = node->pkt->pkt.public_key;
 
+  fingerprint_from_pk (pk, fpr, &fprlen);
   keyid_from_pk (pk, keyid);
   uidnode = find_next_kbnode (keyblock, PKT_USER_ID);
 
@@ -2583,6 +2802,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
     {
       log_error (_("secret key %s: %s\n"), keystr_from_pk (pk),
                  _("rejected by import screener"));
+      release_kbnode (keyblock);
       return 0;
   }
 
@@ -2602,6 +2822,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
     {
       if (!for_migration)
         log_error (_("importing secret keys not allowed\n"));
+      release_kbnode (keyblock);
       return 0;
     }
 
@@ -2609,6 +2830,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
     {
       if (!for_migration)
         log_error( _("key %s: no user ID\n"), keystr_from_pk (pk));
+      release_kbnode (keyblock);
       return 0;
     }
 
@@ -2617,6 +2839,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
     {
       /* Actually an internal error.  */
       log_error ("key %s: secret key info missing\n", keystr_from_pk (pk));
+      release_kbnode (keyblock);
       return 0;
     }
 
@@ -2627,6 +2850,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
       if (!for_migration)
         log_error (_("key %s: secret key with invalid cipher %d"
                      " - skipped\n"), keystr_from_pk (pk), ski->algo);
+      release_kbnode (keyblock);
       return 0;
     }
 
@@ -2637,6 +2861,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
          to put a secret key into the keyring and the user might later
          be tricked into signing stuff with that key.  */
       log_error (_("importing secret keys not allowed\n"));
+      release_kbnode (keyblock);
       return 0;
     }
 #endif
@@ -2668,16 +2893,43 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
        * the public keyblock.  Otherwise we would import just the
        * secret key without having the public key.  That would be
        * surprising and clutters out private-keys-v1.d.  */
-      err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock);
+      err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic);
       if (err)
         goto leave;
 
       if (!valid)
         {
-          err = gpg_error (GPG_ERR_NO_SECKEY);
+          /* If the block was not valid the primary key is left in the
+           * original keyblock because we require that for the first
+           * node.   Move it to ATTIC.  */
+          if (keyblock && keyblock->pkt->pkttype == PKT_SECRET_KEY)
+            {
+              node = keyblock;
+              keyblock = node->next;
+              node->next = NULL;
+              if (attic)
+                {
+                  node->next = attic;
+                  attic = node;
+                }
+              else
+                attic = node;
+            }
+
+          /* Try to import the secret key iff we have a public key.  */
+          if (attic && !(opt.dry_run || (options & IMPORT_DRY_RUN)))
+            err = import_matching_seckeys (ctrl, attic, fpr, fprlen,
+                                           stats, batch);
+          else
+            err = gpg_error (GPG_ERR_NO_SECKEY);
           goto leave;
         }
 
+      /* log_debug ("attic is:\n"); */
+      /* dump_kbnode (attic); */
+
+      /* Proceed with the valid parts of PUBKEYBLOCK. */
+
       /* At least we cancel the secret key import when the public key
 	 import was skipped due to MERGE_ONLY option and a new
 	 key.  */
@@ -2686,62 +2938,37 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
 	{
           /* Read the keyblock again to get the effects of a merge for
            * the public key.  */
-          /* Fixme: we should do this based on the fingerprint or
-             even better let import_one return the merged
-             keyblock.  */
-          node = get_pubkeyblock (ctrl, keyid);
-          if (!node)
-            log_error ("key %s: failed to re-lookup public key\n",
-                       keystr_from_pk (pk));
+          err = get_pubkey_byfprint (ctrl, NULL, &node, fpr, fprlen);
+          if (err || !node)
+            log_error ("key %s: failed to re-lookup public key: %s\n",
+                       keystr_from_pk (pk), gpg_strerror (err));
           else
             {
-              /* transfer_secret_keys collects subkey stats.  */
-              struct import_stats_s subkey_stats = {0};
+              err = do_transfer (ctrl, keyblock, pk, stats, batch, 0);
+              if (!err)
+                check_prefs (ctrl, node);
+              release_kbnode (node);
 
-              err = transfer_secret_keys (ctrl, &subkey_stats, keyblock,
-                                          batch, 0);
-              if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
+              if (!err && attic)
                 {
-                  /* TRANSLATORS: For smartcard, each private key on
-                     host has a reference (stub) to a smartcard and
-                     actual private key data is stored on the card.  A
-                     single smartcard can have up to three private key
-                     data.  Importing private key stub is always
-                     skipped in 2.1, and it returns
-                     GPG_ERR_NOT_PROCESSED.  Instead, user should be
-                     suggested to run 'gpg --card-status', then,
-                     references to a card will be automatically
-                     created again.  */
-                  log_info (_("To migrate '%s', with each smartcard, "
-                              "run: %s\n"), "secring.gpg", "gpg --card-status");
-                  err = 0;
+                  /* Try to import invalid subkeys.  This can be the
+                   * case if the primary secret key was imported due
+                   * to --allow-non-selfsigned-uid.  */
+                  err = import_matching_seckeys (ctrl, attic, fpr, fprlen,
+                                                 stats, batch);
                 }
-              if (!err)
-                {
-		  int status = 16;
-                  if (!opt.quiet)
-                    log_info (_("key %s: secret key imported\n"),
-                              keystr_from_pk (pk));
-		  if (subkey_stats.secret_imported)
-                    {
-                      status |= 1;
-                      stats->secret_imported += 1;
-                    }
-		  if (subkey_stats.secret_dups)
-                    stats->secret_dups += 1;
-
-                  if (is_status_enabled ())
-                    print_import_ok (pk, status);
 
-                  check_prefs (ctrl, node);
-                }
-              release_kbnode (node);
             }
         }
     }
 
  leave:
+  release_kbnode (keyblock);
   release_kbnode (pub_keyblock);
+  if (r_secattic)
+    *r_secattic = attic;
+  else
+    release_kbnode (attic);
   return err;
 }
 
diff --git a/g10/keyedit.c b/g10/keyedit.c
index f95f02f..742dfba 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1894,7 +1894,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
 	    node = new_kbnode (pkt);
 
             /* Transfer it to gpg-agent which handles secret keys.  */
-            err = transfer_secret_keys (ctrl, NULL, node, 1, 1);
+            err = transfer_secret_keys (ctrl, NULL, node, 1, 1, 0);
 
             /* Treat the pkt as a public key.  */
             pkt->pkttype = PKT_PUBLIC_KEY;
diff --git a/g10/main.h b/g10/main.h
index dcd3767..d3d6060 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -376,7 +376,8 @@ struct impex_filter_parm_s
 
 const char *impex_filter_getval (void *cookie, const char *propname);
 gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
-                                  kbnode_t sec_keyblock, int batch, int force);
+                                  kbnode_t sec_keyblock, int batch, int force,
+                                  int only_marked);
 
 int collapse_uids( KBNODE *keyblock );