aboutsummaryrefslogtreecommitdiffstats
path: root/g10/import.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2005-01-20 17:21:40 +0000
committerWerner Koch <[email protected]>2005-01-20 17:21:40 +0000
commitb2b2786be1047e921fe50263915a565252a802ed (patch)
treeed076a7824239cba29acb3e4d3cda91a8a3d9d41 /g10/import.c
parentMinor changes (diff)
downloadgnupg-b2b2786be1047e921fe50263915a565252a802ed.tar.gz
gnupg-b2b2786be1047e921fe50263915a565252a802ed.zip
* gpgv.c (tty_fprintf): New stub.
* card-util.c (card_status): Create asecret key stub on the fly and print more information about a card key. * import.c (pub_to_sec_keyblock, auto_create_card_key_stub): New. * getkey.c (get_seckeyblock_byfprint): New. * keylist.c (print_card_key_info): New.
Diffstat (limited to '')
-rw-r--r--g10/import.c233
1 files changed, 231 insertions, 2 deletions
diff --git a/g10/import.c b/g10/import.c
index d0c1c01ac..4119b01c1 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -1,6 +1,6 @@
-/* import.c
+/* import.c - import a key into our key storage.
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003,
- * 2004 Free Software Foundation, Inc.
+ * 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -2118,3 +2118,232 @@ append_key( KBNODE keyblock, KBNODE node, int *n_sigs,
return 0;
}
+
+
+
+/* Walk a public keyblock and produce a secret keyblock out of it.
+ Instead of inserting the secret key parameters (which we don't
+ have), we insert a stub. */
+static KBNODE
+pub_to_sec_keyblock (KBNODE pub_keyblock)
+{
+ KBNODE pubnode, secnode;
+ KBNODE sec_keyblock = NULL;
+ KBNODE walkctx = NULL;
+
+ while((pubnode = walk_kbnode (pub_keyblock,&walkctx,0)))
+ {
+ if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY
+ || pubnode->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ /* Make a secret key. We only need to convert enough to
+ write the keyblock out. */
+ PKT_public_key *pk = pubnode->pkt->pkt.public_key;
+ PACKET *pkt = m_alloc_clear (sizeof *pkt);
+ PKT_secret_key *sk = m_alloc_clear (sizeof *sk);
+ int i, n;
+
+ if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY)
+ pkt->pkttype = PKT_SECRET_KEY;
+ else
+ pkt->pkttype = PKT_SECRET_SUBKEY;
+
+ pkt->pkt.secret_key = sk;
+
+ copy_public_parts_to_secret_key ( pk, sk );
+ sk->version = pk->version;
+ sk->timestamp = pk->timestamp;
+
+ n = pubkey_get_npkey (pk->pubkey_algo);
+ if (!n)
+ n = 1; /* Unknown number of parameters, however the data
+ is stored in the first mpi. */
+ for (i=0; i < n; i++ )
+ sk->skey[i] = mpi_copy (pk->pkey[i]);
+
+ sk->is_protected = 1;
+ sk->protect.s2k.mode = 1001;
+
+ secnode = new_kbnode (pkt);
+ }
+ else
+ {
+ secnode = clone_kbnode (pubnode);
+ }
+
+ if(!sec_keyblock)
+ sec_keyblock = secnode;
+ else
+ add_kbnode (sec_keyblock, secnode);
+ }
+
+ return sec_keyblock;
+}
+
+
+/* Walk over the secret keyring SEC_KEYBLOCK and update any simple
+ stub keys with the serial number SNNUM of the card if one of the
+ fingerprints FPR1, FPR2 or FPR3 match. Print a note if the key is
+ a duplicate (may happen in case of backed uped keys).
+
+ Returns: True if anything changed.
+*/
+static int
+update_sec_keyblock_with_cardinfo (KBNODE sec_keyblock,
+ const unsigned char *fpr1,
+ const unsigned char *fpr2,
+ const unsigned char *fpr3,
+ const char *serialnostr)
+{
+ KBNODE node;
+ KBNODE walkctx = NULL;
+ PKT_secret_key *sk;
+ byte array[MAX_FINGERPRINT_LEN];
+ size_t n;
+ int result = 0;
+ const char *s;
+
+ while((node = walk_kbnode (sec_keyblock, &walkctx, 0)))
+ {
+ if (node->pkt->pkttype != PKT_SECRET_KEY
+ && node->pkt->pkttype != PKT_SECRET_SUBKEY)
+ continue;
+ sk = node->pkt->pkt.secret_key;
+
+ fingerprint_from_sk (sk, array, &n);
+ if (n != 20)
+ continue; /* Can't be a card key. */
+ if ( !((fpr1 && !memcmp (array, fpr1, 20))
+ || (fpr2 && !memcmp (array, fpr2, 20))
+ || (fpr3 && !memcmp (array, fpr3, 20))) )
+ continue; /* No match. */
+
+ if (sk->is_protected == 1 && sk->protect.s2k.mode == 1001)
+ {
+ /* Standard case: migrate that stub to a key stub. */
+ sk->protect.s2k.mode = 1002;
+ s = serialnostr;
+ for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+ sk->protect.ivlen++, s += 2)
+ sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+ result = 1;
+ }
+ else if (sk->is_protected == 1 && sk->protect.s2k.mode == 1002)
+ {
+ s = serialnostr;
+ for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+ sk->protect.ivlen++, s += 2)
+ if (sk->protect.iv[sk->protect.ivlen] != xtoi_2 (s))
+ {
+ log_info (_("NOTE: a key's S/N does not "
+ "match the card's one\n"));
+ break;
+ }
+ }
+ else
+ {
+ if (node->pkt->pkttype != PKT_SECRET_KEY)
+ log_info (_("NOTE: primary key is online and stored on card\n"));
+ else
+ log_info (_("NOTE: secondary key is online and stored on card\n"));
+ }
+ }
+
+ return result;
+}
+
+
+
+/* Check whether a secret key stub exists for the public key PK. If
+ not create such a stub key and store it into the secring. If it
+ exists, add appropriate subkey stubs and update the secring.
+ Return 0 if the key could be created. */
+int
+auto_create_card_key_stub ( const char *serialnostr,
+ const unsigned char *fpr1,
+ const unsigned char *fpr2,
+ const unsigned char *fpr3)
+{
+ KBNODE pub_keyblock;
+ KBNODE sec_keyblock;
+ KEYDB_HANDLE hd;
+ int rc;
+
+ /* We only want to do this for an OpenPGP card. */
+ if (!serialnostr || strncmp (serialnostr, "D27600012401", 12)
+ || strlen (serialnostr) != 32 )
+ return G10ERR_GENERAL;
+
+ /* First get the public keyring from any of the provided fingerprints. */
+ if ( (fpr1 && !get_keyblock_byfprint (&pub_keyblock, fpr1, 20))
+ || (fpr2 && !get_keyblock_byfprint (&pub_keyblock, fpr2, 20))
+ || (fpr3 && !get_keyblock_byfprint (&pub_keyblock, fpr3, 20)))
+ ;
+ else
+ return G10ERR_GENERAL;
+
+ hd = keydb_new (1);
+
+ /* Now check whether there is a secret keyring. */
+ {
+ PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
+ byte afp[MAX_FINGERPRINT_LEN];
+ size_t an;
+
+ fingerprint_from_pk (pk, afp, &an);
+ memset (afp, 0, MAX_FINGERPRINT_LEN);
+ rc = keydb_search_fpr (hd, afp);
+ }
+
+ if (!rc)
+ {
+ rc = keydb_get_keyblock (hd, &sec_keyblock);
+ if (rc)
+ {
+ log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
+ rc = G10ERR_GENERAL;
+ }
+ else
+ {
+ merge_keys_and_selfsig (sec_keyblock);
+
+ /* FIXME: We need to add new subkeys first. */
+ if (update_sec_keyblock_with_cardinfo (sec_keyblock,
+ fpr1, fpr2, fpr3,
+ serialnostr))
+ {
+ rc = keydb_update_keyblock (hd, sec_keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ }
+ }
+ }
+ else /* A secret key does not exists - create it. */
+ {
+ sec_keyblock = pub_to_sec_keyblock (pub_keyblock);
+ update_sec_keyblock_with_cardinfo (sec_keyblock,
+ fpr1, fpr2, fpr3,
+ serialnostr);
+
+ rc = keydb_locate_writable (hd, NULL);
+ if (rc)
+ {
+ log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
+ rc = G10ERR_GENERAL;
+ }
+ else
+ {
+ rc = keydb_insert_keyblock (hd, sec_keyblock );
+ if (rc)
+ log_error (_("error writing keyring `%s': %s\n"),
+ keydb_get_resource_name (hd), g10_errstr(rc) );
+ }
+ }
+
+ release_kbnode (sec_keyblock);
+ release_kbnode (pub_keyblock);
+ keydb_release (hd);
+ return rc;
+}
+