aboutsummaryrefslogtreecommitdiffstats
path: root/g10/import.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/import.c')
-rw-r--r--g10/import.c579
1 files changed, 464 insertions, 115 deletions
diff --git a/g10/import.c b/g10/import.c
index 73f795cd9..c2a1dd033 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
@@ -109,11 +111,16 @@ static gpg_error_t import_one (ctrl_t ctrl,
unsigned char **fpr, size_t *fpr_len,
unsigned int options, int from_sk, int silent,
import_screener_t screener, void *screener_arg,
- int origin, const char *url);
-static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
+ 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,
@@ -121,6 +128,7 @@ static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
u32 *keyid, unsigned int options);
static int any_uid_left (kbnode_t keyblock);
+static int remove_all_uids (kbnode_t *keyblock);
static int merge_blocks (ctrl_t ctrl, unsigned int options,
kbnode_t keyblock_orig,
kbnode_t keyblock, u32 *keyid,
@@ -181,6 +189,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
{"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
N_("remove as much as possible from key after import")},
+ {"import-drop-uids", IMPORT_DROP_UIDS, NULL,
+ N_("Do not import user id or attribute packets")},
+
{"import-export", IMPORT_EXPORT, NULL,
N_("run import filters and export key immediately")},
@@ -562,6 +573,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 +594,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);
+ {
+ 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 +676,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 +713,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;
@@ -924,6 +985,8 @@ read_block( IOBUF a, int with_meta,
add_kbnode (root, new_kbnode (pkt));
pkt = xmalloc (sizeof *pkt);
}
+ else
+ free_packet (pkt, &parsectx);
init_packet(pkt);
break;
}
@@ -1078,23 +1141,14 @@ print_import_ok (PKT_public_key *pk, unsigned int reason)
static void
print_import_check (PKT_public_key * pk, PKT_user_id * id)
{
- char * buf;
- byte fpr[24];
+ byte hexfpr[2*MAX_FINGERPRINT_LEN+1];
u32 keyid[2];
- size_t i, n;
- size_t pos = 0;
- buf = xmalloc (17+41+id->len+32);
keyid_from_pk (pk, keyid);
- sprintf (buf, "%08X%08X ", keyid[0], keyid[1]);
- pos = 17;
- fingerprint_from_pk (pk, fpr, &n);
- for (i = 0; i < n; i++, pos += 2)
- sprintf (buf+pos, "%02X", fpr[i]);
- strcat (buf, " ");
- strcat (buf, id->name);
- write_status_text (STATUS_IMPORT_CHECK, buf);
- xfree (buf);
+ hexfingerprint (pk, hexfpr, sizeof hexfpr);
+ write_status_printf (STATUS_IMPORT_CHECK, "%08X%08X %s %s",
+ keyid[0], keyid[1], hexfpr, id->name);
+
}
@@ -1258,7 +1312,7 @@ impex_filter_getval (void *cookie, const char *propname)
{
if (!uid->mbox)
{
- uid->mbox = mailbox_from_userid (uid->name);
+ uid->mbox = mailbox_from_userid (uid->name, 0);
}
result = uid->mbox;
}
@@ -1669,7 +1723,10 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url)
* the internal errorcount, so that invalid input can be detected by
* programs which called gpg. If SILENT is no messages are printed -
* even most error messages are suppressed. ORIGIN is the origin of
- * the key (0 for unknown) and URL the corresponding URL.
+ * the key (0 for unknown) and URL the corresponding URL. FROM_SK
+ * indicates that the key has been made from a secret key. If R_SAVED
+ * is not NULL a boolean will be stored indicating whether the keyblock
+ * has valid parts.
*/
static gpg_error_t
import_one (ctrl_t ctrl,
@@ -1677,7 +1734,7 @@ import_one (ctrl_t ctrl,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
int from_sk, int silent,
import_screener_t screener, void *screener_arg,
- int origin, const char *url)
+ int origin, const char *url, int *r_valid)
{
gpg_error_t err = 0;
PKT_public_key *pk;
@@ -1696,6 +1753,9 @@ import_one (ctrl_t ctrl,
int any_filter = 0;
KEYDB_HANDLE hd = NULL;
+ if (r_valid)
+ *r_valid = 0;
+
/* If show-only is active we don't won't any extra output. */
if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN)))
silent = 1;
@@ -1713,9 +1773,11 @@ import_one (ctrl_t ctrl,
keyid_from_pk( pk, keyid );
uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
- if (opt.verbose && !opt.interactive && !silent)
+ if (opt.verbose && !opt.interactive && !silent && !from_sk)
{
- log_info( "pub %s/%s %s ",
+ /* Note that we do not print this info in FROM_SK mode
+ * because import_secret_one already printed that. */
+ log_info ("pub %s/%s %s ",
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
keystr_from_pk(pk), datestr_from_pk(pk) );
if (uidnode)
@@ -1726,7 +1788,9 @@ import_one (ctrl_t ctrl,
}
- if (!uidnode )
+ /* Unless import-drop-uids has been requested we don't allow import
+ * of a key without UIDs. */
+ if (!uidnode && !(options & IMPORT_DROP_UIDS))
{
if (!silent)
log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
@@ -1746,14 +1810,18 @@ import_one (ctrl_t ctrl,
print_import_check (pk, uidnode->pkt->pkt.user_id);
merge_keys_and_selfsig (ctrl, keyblock);
tty_printf ("\n");
- show_basic_key_info (ctrl, keyblock);
+ show_basic_key_info (ctrl, keyblock, from_sk);
tty_printf ("\n");
if (!cpr_get_answer_is_yes ("import.okay",
"Do you want to import this key? (y/N) "))
return 0;
}
- collapse_uids(&keyblock);
+ /* Remove or collapse the user ids. */
+ if ((options & IMPORT_DROP_UIDS))
+ remove_all_uids (&keyblock);
+ else
+ collapse_uids (&keyblock);
/* Clean the key that we're about to import, to cut down on things
that we have to clean later. This has no practical impact on the
@@ -1800,7 +1868,10 @@ import_one (ctrl_t ctrl,
}
}
- if (!delete_inv_parts (ctrl, keyblock, keyid, options ) )
+ /* Delete invalid parts and without the drop option bail out if
+ * there are no user ids. */
+ if (!delete_inv_parts (ctrl, keyblock, keyid, options)
+ && !(options & IMPORT_DROP_UIDS) )
{
if (!silent)
{
@@ -1840,6 +1911,10 @@ import_one (ctrl_t ctrl,
return 0;
}
+ /* The keyblock is valid and ready for real import. */
+ if (r_valid)
+ *r_valid = 1;
+
/* Show the key in the form it is merged or inserted. We skip this
* if "import-export" is also active without --armor or the output
* file has explicily been given. */
@@ -2163,12 +2238,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;
@@ -2209,12 +2287,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;
@@ -2454,14 +2536,21 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
/* Walk a secret keyblock and produce a public keyblock out of it.
- Returns a new node or NULL on error. */
+ * Returns a new node or NULL on error. Modifies the tag field of the
+ * nodes. */
static kbnode_t
sec_to_pub_keyblock (kbnode_t sec_keyblock)
{
kbnode_t pub_keyblock = NULL;
kbnode_t ctx = NULL;
kbnode_t secnode, pubnode;
+ unsigned int tag = 0;
+
+ /* Set a tag to all nodes. */
+ for (secnode = sec_keyblock; secnode; secnode = secnode->next)
+ secnode->tag = ++tag;
+ /* Copy. */
while ((secnode = walk_kbnode (sec_keyblock, &ctx, 0)))
{
if (secnode->pkt->pkttype == PKT_SECRET_KEY
@@ -2491,6 +2580,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
{
pubnode = clone_kbnode (secnode);
}
+ pubnode->tag = secnode->tag;
if (!pub_keyblock)
pub_keyblock = pubnode;
@@ -2501,25 +2591,223 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
return pub_keyblock;
}
-/****************
- * 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.
+
+/* 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,
+ kbnode_t *r_removedsecs)
+{
+ kbnode_t sec_keyblock = *r_keyblock;
+ 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)
+ ntaglist++;
+ taglist = xtrycalloc (ntaglist, sizeof *taglist);
+ if (!taglist)
+ return gpg_error_from_syserror ();
+ for (ntaglist = 0, node = pub_keyblock; node; node = node->next)
+ taglist[ntaglist++] = node->tag;
+
+ /* Walks over the secret keyblock and delete all nodes which are not
+ * 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) /* 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 and a list of removed secret key nodes. */
+ commit_kbnode (&sec_keyblock);
+ *r_keyblock = sec_keyblock;
+ *r_removedsecs = attic;
+ return 0;
+}
+
+
+/* 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 int
+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)
+ struct import_stats_s *stats, int batch,
+ unsigned int options, int for_migration,
+ import_screener_t screener, void *screener_arg,
+ kbnode_t *r_secattic)
{
PKT_public_key *pk;
struct seckey_info *ski;
kbnode_t node, uidnode;
u32 keyid[2];
- int rc = 0;
+ 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 */
@@ -2529,6 +2817,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);
@@ -2536,12 +2825,13 @@ 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;
}
if (opt.verbose && !for_migration)
{
- log_info ("sec %s/%s %s ",
+ log_info ("sec %s/%s %s ",
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
keystr_from_pk (pk), datestr_from_pk (pk));
if (uidnode)
@@ -2555,6 +2845,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;
}
@@ -2562,6 +2853,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;
}
@@ -2570,6 +2862,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;
}
@@ -2580,6 +2873,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;
}
@@ -2590,6 +2884,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
@@ -2601,20 +2896,62 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
/* Make a public key out of the key. */
pub_keyblock = sec_to_pub_keyblock (keyblock);
if (!pub_keyblock)
- log_error ("key %s: failed to create public key from secret key\n",
- keystr_from_pk (pk));
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("key %s: failed to create public key from secret key\n",
+ keystr_from_pk (pk));
+ }
else
{
+ int valid;
+
/* Note that this outputs an IMPORT_OK status message for the
public key block, and below we will output another one for
the secret keys. FIXME? */
import_one (ctrl, pub_keyblock, stats,
NULL, NULL, options, 1, for_migration,
- screener, screener_arg, 0, NULL);
+ screener, screener_arg, 0, NULL, &valid);
+
+ /* The secret keyblock may not have nodes which are deleted in
+ * 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, &attic);
+ if (err)
+ goto leave;
+
+ if (!valid)
+ {
+ /* 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;
+ }
- /* Fixme: We should check for an invalid keyblock and
- cancel the secret key import in this case. */
- release_kbnode (pub_keyblock);
+ /* 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
@@ -2622,63 +2959,40 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
if (!(opt.dry_run || (options & IMPORT_DRY_RUN))
&& stats->skipped_new_keys <= nr_prev)
{
- /* Read the keyblock again to get the effects of a merge. */
- /* 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));
+ /* Read the keyblock again to get the effects of a merge for
+ * the public key. */
+ 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
{
- gpg_error_t err;
-
- /* 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);
}
}
}
- return rc;
+ leave:
+ release_kbnode (keyblock);
+ release_kbnode (pub_keyblock);
+ if (r_secattic)
+ *r_secattic = attic;
+ else
+ release_kbnode (attic);
+ return err;
}
@@ -2942,9 +3256,7 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
size_t an;
fingerprint_from_pk (pk, afp, &an);
- while (an < MAX_FINGERPRINT_LEN)
- afp[an++] = 0;
- rc = keydb_search_fpr (hd, afp);
+ rc = keydb_search_fpr (hd, afp, an);
}
if (rc)
{
@@ -3058,7 +3370,7 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
kbnode_t bsnode = NULL; /* Subkey binding signature node. */
u32 bsdate = 0; /* Timestamp of that node. */
kbnode_t rsnode = NULL; /* Subkey recocation signature node. */
- u32 rsdate = 0; /* Timestamp of tha node. */
+ u32 rsdate = 0; /* Timestamp of that node. */
PKT_signature *sig;
int rc;
kbnode_t n;
@@ -3415,14 +3727,51 @@ any_uid_left (kbnode_t keyblock)
-/****************
+/* Delete all user ids from KEYBLOCK.
+ * Returns: True if the keyblock has changed. */
+static int
+remove_all_uids (kbnode_t *keyblock)
+{
+ kbnode_t node;
+ int any = 0;
+
+ for (node = *keyblock; node; node = node->next)
+ {
+ if (is_deleted_kbnode (node))
+ continue;
+
+ if (node->pkt->pkttype != PKT_USER_ID)
+ continue;
+
+ /* We are at the first user id. Delete everything up to the
+ * first subkey. */
+ for (; node; node = node->next)
+ {
+ if (is_deleted_kbnode (node))
+ continue;
+
+ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ || node->pkt->pkttype == PKT_SECRET_SUBKEY)
+ break;
+ delete_kbnode (node);
+ any = 1;
+ }
+ break; /* All done. */
+ }
+
+ commit_kbnode (keyblock);
+ return any;
+}
+
+
+/*
* It may happen that the imported keyblock has duplicated user IDs.
* We check this here and collapse those user IDs together with their
* sigs into one.
* Returns: True if the keyblock has changed.
*/
int
-collapse_uids( kbnode_t *keyblock )
+collapse_uids (kbnode_t *keyblock)
{
kbnode_t uid1;
int any=0;
@@ -3562,7 +3911,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
u32 keyid[2];
keyid_from_fingerprint (ctrl, sig->revkey[idx].fpr,
- MAX_FINGERPRINT_LEN, keyid);
+ sig->revkey[idx].fprlen, keyid);
for(inode=keyblock->next;inode;inode=inode->next)
{
@@ -3582,7 +3931,7 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
err = get_pubkey_byfprint_fast (NULL,
sig->revkey[idx].fpr,
- MAX_FINGERPRINT_LEN);
+ sig->revkey[idx].fprlen);
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY
|| gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
{
@@ -3598,13 +3947,13 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
tempkeystr,keystr(keyid));
keyserver_import_fprint (ctrl,
sig->revkey[idx].fpr,
- MAX_FINGERPRINT_LEN,
+ sig->revkey[idx].fprlen,
opt.keyserver, 0);
/* Do we have it now? */
err = get_pubkey_byfprint_fast (NULL,
sig->revkey[idx].fpr,
- MAX_FINGERPRINT_LEN);
+ sig->revkey[idx].fprlen);
}
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY