aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/Makefile.am1
-rw-r--r--g10/armor.c4
-rw-r--r--g10/build-packet.c8
-rw-r--r--g10/call-agent.c489
-rw-r--r--g10/call-agent.h25
-rw-r--r--g10/card-util.c80
-rw-r--r--g10/cpr.c2
-rw-r--r--g10/decrypt-data.c4
-rw-r--r--g10/decrypt.c7
-rw-r--r--g10/delkey.c109
-rw-r--r--g10/exec.c110
-rw-r--r--g10/export.c15
-rw-r--r--g10/getkey.c379
-rw-r--r--g10/gpg.c15
-rw-r--r--g10/gpgcompose.c15
-rw-r--r--g10/import.c256
-rw-r--r--g10/keydb.c15
-rw-r--r--g10/keydb.h18
-rw-r--r--g10/keyedit.c30
-rw-r--r--g10/keygen.c246
-rw-r--r--g10/keyid.c122
-rw-r--r--g10/keylist.c104
-rw-r--r--g10/keyring.c9
-rw-r--r--g10/keyserver.c11
-rw-r--r--g10/main.h12
-rw-r--r--g10/mainproc.c146
-rw-r--r--g10/objcache.c689
-rw-r--r--g10/objcache.h29
-rw-r--r--g10/options.h3
-rw-r--r--g10/packet.h10
-rw-r--r--g10/parse-packet.c15
-rw-r--r--g10/photoid.c16
-rw-r--r--g10/pkclist.c19
-rw-r--r--g10/plaintext.c3
-rw-r--r--g10/pubkey-enc.c46
-rw-r--r--g10/revoke.c26
-rw-r--r--g10/sig-check.c2
-rw-r--r--g10/sign.c49
-rw-r--r--g10/skclist.c55
-rw-r--r--g10/tofu.c32
40 files changed, 2366 insertions, 860 deletions
diff --git a/g10/Makefile.am b/g10/Makefile.am
index 3b4464364..884b4749b 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -121,6 +121,7 @@ common_source = \
sig-check.c \
keylist.c \
pkglue.c pkglue.h \
+ objcache.c objcache.h \
ecdh.c
gpg_sources = server.c \
diff --git a/g10/armor.c b/g10/armor.c
index 972766503..eb2d28bca 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -1394,10 +1394,10 @@ armor_filter( void *opaque, int control,
}
/* write the comment strings */
- for(s=comment->d;comment;comment=comment->next,s=comment->d)
+ for(;comment;comment=comment->next)
{
iobuf_writestr(a, "Comment: " );
- for( ; *s; s++ )
+ for( s=comment->d; *s; s++ )
{
if( *s == '\n' )
iobuf_writestr(a, "\\n" );
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 07fccb099..2a95df694 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -447,15 +447,21 @@ do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
* Without forcing HDRLEN to 2 in this case an indeterminate length
* packet would be written which is not allowed. Note that we are
* always called with a CTB indicating an old packet header format,
- * so that forcing a 2 octet header works. */
+ * so that forcing a 2 octet header works. We also check for the
+ * maximum allowed packet size by the parser using an arbitrary
+ * extra 10 bytes for header data. */
if (uid->attrib_data)
{
+ if (uid->attrib_len > MAX_ATTR_PACKET_LENGTH - 10)
+ return gpg_error (GPG_ERR_TOO_LARGE);
hdrlen = uid->attrib_len? 0 : 2;
write_header2 (out, ctb, uid->attrib_len, hdrlen);
rc = iobuf_write( out, uid->attrib_data, uid->attrib_len );
}
else
{
+ if (uid->len > MAX_UID_PACKET_LENGTH - 10)
+ return gpg_error (GPG_ERR_TOO_LARGE);
hdrlen = uid->len? 0 : 2;
write_header2 (out, ctb, uid->len, hdrlen);
rc = iobuf_write( out, uid->name, uid->len );
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 83777534e..19deb73d7 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -41,6 +41,7 @@
#include "../common/status.h"
#include "../common/shareddefs.h"
#include "../common/host2net.h"
+#include "../common/ttyio.h"
#define CONTROL_D ('D' - 'A' + 1)
@@ -48,6 +49,13 @@
static assuan_context_t agent_ctx = NULL;
static int did_early_card_test;
+struct confirm_parm_s
+{
+ char *desc;
+ char *ok;
+ char *notok;
+};
+
struct default_inq_parm_s
{
ctrl_t ctrl;
@@ -57,6 +65,7 @@ struct default_inq_parm_s
u32 *mainkeyid;
int pubkey_algo;
} keyinfo;
+ struct confirm_parm_s *confirm;
};
struct cipher_parm_s
@@ -136,6 +145,7 @@ default_inq_cb (void *opaque, const char *line)
{
gpg_error_t err = 0;
struct default_inq_parm_s *parm = opaque;
+ const char *s;
if (has_leading_keyword (line, "PINENTRY_LAUNCHED"))
{
@@ -151,7 +161,7 @@ default_inq_cb (void *opaque, const char *line)
{
if (have_static_passphrase ())
{
- const char *s = get_static_passphrase ();
+ s = get_static_passphrase ();
err = assuan_send_data (parm->ctx, s, strlen (s));
}
else
@@ -176,6 +186,27 @@ default_inq_cb (void *opaque, const char *line)
xfree (pw);
}
}
+ else if ((s = has_leading_keyword (line, "CONFIRM"))
+ && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK
+ && parm->confirm)
+ {
+ int ask = atoi (s);
+ int yes;
+
+ if (ask)
+ {
+ yes = cpr_get_answer_is_yes (NULL, parm->confirm->desc);
+ if (yes)
+ err = assuan_send_data (parm->ctx, NULL, 0);
+ else
+ err = gpg_error (GPG_ERR_NOT_CONFIRMED);
+ }
+ else
+ {
+ tty_printf ("%s", parm->confirm->desc);
+ err = assuan_send_data (parm->ctx, NULL, 0);
+ }
+ }
else
log_debug ("ignoring gpg-agent inquiry '%s'\n", line);
@@ -336,7 +367,7 @@ start_agent (ctrl_t ctrl, int flag_for_card)
if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
if (!rc)
- rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
+ rc = assuan_transact (agent_ctx, "SCD SERIALNO",
NULL, NULL, NULL, NULL,
learn_status_cb, &info);
if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
@@ -352,7 +383,7 @@ start_agent (ctrl_t ctrl, int flag_for_card)
break;
default:
write_status_text (STATUS_CARDCTRL, "4");
- log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
+ log_info ("selecting card failed: %s\n", gpg_strerror (rc));
break;
}
}
@@ -726,7 +757,15 @@ learn_status_cb (void *opaque, const char *line)
return 0;
}
-/* Call the scdaemon to learn about a smartcard */
+
+/* Call the scdaemon to learn about a smartcard. Note that in
+ * contradiction to the function's name, gpg-agent's LEARN command is
+ * used and not the low-level "SCD LEARN".
+ * Used by:
+ * card-util.c
+ * keyedit_menu
+ * card_store_key_with_backup (Woth force to remove secret key data)
+ */
int
agent_scd_learn (struct agent_card_info_s *info, int force)
{
@@ -759,10 +798,109 @@ agent_scd_learn (struct agent_card_info_s *info, int force)
}
+
+/* Callback for the agent_scd_keypairinfo function. */
+static gpg_error_t
+scd_keypairinfo_status_cb (void *opaque, const char *line)
+{
+ strlist_t *listaddr = opaque;
+ const char *keyword = line;
+ int keywordlen;
+ strlist_t sl;
+ char *p;
+
+ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+ ;
+ while (spacep (line))
+ line++;
+
+ if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
+ {
+ sl = append_to_strlist (listaddr, line);
+ p = sl->d;
+ /* Make sure that we only have two tokens so that future
+ * extensions of the format won't change the format expected by
+ * the caller. */
+ while (*p && !spacep (p))
+ p++;
+ if (*p)
+ {
+ while (spacep (p))
+ p++;
+ while (*p && !spacep (p))
+ p++;
+ if (*p)
+ {
+ *p++ = 0;
+ while (spacep (p))
+ p++;
+ while (*p && !spacep (p))
+ {
+ switch (*p++)
+ {
+ case 'c': sl->flags |= GCRY_PK_USAGE_CERT; break;
+ case 's': sl->flags |= GCRY_PK_USAGE_SIGN; break;
+ case 'e': sl->flags |= GCRY_PK_USAGE_ENCR; break;
+ case 'a': sl->flags |= GCRY_PK_USAGE_AUTH; break;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/* Read the keypairinfo lines of the current card directly from
+ * scdaemon. The list is returned as a string made up of the keygrip,
+ * a space and the keyref. The flags of the string carry the usage
+ * bits. If KEYREF is not NULL, only a single string is returned
+ * which matches the given keyref. */
+gpg_error_t
+agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref, strlist_t *r_list)
+{
+ gpg_error_t err;
+ strlist_t list = NULL;
+ struct default_inq_parm_s inq_parm;
+ char line[ASSUAN_LINELENGTH];
+
+ *r_list = NULL;
+ err= start_agent (ctrl, 1);
+ if (err)
+ return err;
+ memset (&inq_parm, 0, sizeof inq_parm);
+ inq_parm.ctx = agent_ctx;
+
+ if (keyref)
+ snprintf (line, DIM(line), "SCD READKEY --info-only %s", keyref);
+ else
+ snprintf (line, DIM(line), "SCD LEARN --keypairinfo");
+
+ err = assuan_transact (agent_ctx, line,
+ NULL, NULL,
+ default_inq_cb, &inq_parm,
+ scd_keypairinfo_status_cb, &list);
+ if (!err && !list)
+ err = gpg_error (GPG_ERR_NO_DATA);
+ if (err)
+ {
+ free_strlist (list);
+ return err;
+ }
+ *r_list = list;
+ return 0;
+}
+
+
+
/* Send an APDU to the current card. On success the status word is
- stored at R_SW. With HEXAPDU being NULL only a RESET command is
- send to scd. With HEXAPDU being the string "undefined" the command
- "SERIALNO undefined" is send to scd. */
+ * stored at R_SW. With HEXAPDU being NULL only a RESET command is
+ * send to scd. With HEXAPDU being the string "undefined" the command
+ * "SERIALNO undefined" is send to scd.
+ * Used by:
+ * card-util.c
+ */
gpg_error_t
agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
{
@@ -816,6 +954,10 @@ agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
}
+/* Used by:
+ * card_store_subkey
+ * card_store_key_with_backup
+ */
int
agent_keytocard (const char *hexgrip, int keyno, int force,
const char *serialno, const char *timestamp)
@@ -844,9 +986,99 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
+/* Object used with the agent_scd_getattr_one. */
+struct getattr_one_parm_s {
+ const char *keyword; /* Keyword to look for. */
+ char *data; /* Malloced and unescaped data. */
+ gpg_error_t err; /* Error code or 0 on success. */
+};
+
+
+/* Callback for agent_scd_getattr_one. */
+static gpg_error_t
+getattr_one_status_cb (void *opaque, const char *line)
+{
+ struct getattr_one_parm_s *parm = opaque;
+ const char *s;
+
+ if (parm->data)
+ return 0; /* We want only the first occurrence. */
+
+ if ((s=has_leading_keyword (line, parm->keyword)))
+ {
+ parm->data = percent_plus_unescape (s, 0xff);
+ if (!parm->data)
+ parm->err = gpg_error_from_syserror ();
+ }
+
+ return 0;
+}
+
+
+/* Simplified version of agent_scd_getattr. This function returns
+ * only the first occurance of the attribute NAME and stores it at
+ * R_VALUE. A nul in the result is silennly replaced by 0xff. On
+ * error NULL is stored at R_VALUE. */
+gpg_error_t
+agent_scd_getattr_one (const char *name, char **r_value)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+ struct default_inq_parm_s inqparm;
+ struct getattr_one_parm_s parm;
+
+ *r_value = NULL;
+
+ if (!*name)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ memset (&inqparm, 0, sizeof inqparm);
+ inqparm.ctx = agent_ctx;
+
+ memset (&parm, 0, sizeof parm);
+ parm.keyword = name;
+
+ /* We assume that NAME does not need escaping. */
+ if (12 + strlen (name) > DIM(line)-1)
+ return gpg_error (GPG_ERR_TOO_LARGE);
+ stpcpy (stpcpy (line, "SCD GETATTR "), name);
+
+ err = start_agent (NULL, 1);
+ if (err)
+ return err;
+
+ err = assuan_transact (agent_ctx, line,
+ NULL, NULL,
+ default_inq_cb, &inqparm,
+ getattr_one_status_cb, &parm);
+ if (!err && parm.err)
+ err = parm.err;
+ else if (!err && !parm.data)
+ err = gpg_error (GPG_ERR_NO_DATA);
+
+ if (!err)
+ *r_value = parm.data;
+ else
+ xfree (parm.data);
+
+ return err;
+}
+
+
+
/* Call the agent to retrieve a data object. This function returns
- the data in the same structure as used by the learn command. It is
- allowed to update such a structure using this command. */
+ * the data in the same structure as used by the learn command. It is
+ * allowed to update such a structure using this command.
+ *
+ * Used by:
+ * build_sk_list
+ * enum_secret_keys
+ * get_signature_count
+ * card-util.c
+ * generate_keypair (KEY-ATTR)
+ * card_store_key_with_backup (SERIALNO)
+ * generate_card_subkeypair (KEY-ATTR)
+ */
int
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
{
@@ -875,24 +1107,23 @@ agent_scd_getattr (const char *name, struct agent_card_info_s *info)
return rc;
}
+
-/* Send an setattr command to the SCdaemon. SERIALNO is not actually
- used here but required by gpg 1.4's implementation of this code in
- cardglue.c. */
-int
-agent_scd_setattr (const char *name,
- const unsigned char *value, size_t valuelen,
- const char *serialno)
+/* Send an setattr command to the SCdaemon.
+ * Used by:
+ * card-util.c
+ */
+gpg_error_t
+agent_scd_setattr (const char *name, const void *value_arg, size_t valuelen)
{
- int rc;
+ gpg_error_t err;
+ const unsigned char *value = value_arg;
char line[ASSUAN_LINELENGTH];
char *p;
struct default_inq_parm_s parm;
memset (&parm, 0, sizeof parm);
- (void)serialno;
-
if (!*name || !valuelen)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -918,16 +1149,16 @@ agent_scd_setattr (const char *name,
}
*p = 0;
- rc = start_agent (NULL, 1);
- if (!rc)
+ err = start_agent (NULL, 1);
+ if (!err)
{
parm.ctx = agent_ctx;
- rc = assuan_transact (agent_ctx, line, NULL, NULL,
+ err = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, &parm, NULL, NULL);
}
- status_sc_op_failure (rc);
- return rc;
+ status_sc_op_failure (err);
+ return err;
}
@@ -953,7 +1184,10 @@ inq_writecert_parms (void *opaque, const char *line)
}
-/* Send a WRITECERT command to the SCdaemon. */
+/* Send a WRITECERT command to the SCdaemon.
+ * Used by:
+ * card-util.c
+ */
int
agent_scd_writecert (const char *certidstr,
const unsigned char *certdata, size_t certdatalen)
@@ -985,60 +1219,6 @@ agent_scd_writecert (const char *certidstr,
-/* Handle a KEYDATA inquiry. Note, we only send the data,
- assuan_transact takes care of flushing and writing the end */
-static gpg_error_t
-inq_writekey_parms (void *opaque, const char *line)
-{
- int rc;
- struct writekey_parm_s *parm = opaque;
-
- if (has_leading_keyword (line, "KEYDATA"))
- {
- rc = assuan_send_data (parm->dflt->ctx, parm->keydata, parm->keydatalen);
- }
- else
- rc = default_inq_cb (parm->dflt, line);
-
- return rc;
-}
-
-
-/* Send a WRITEKEY command to the SCdaemon. */
-int
-agent_scd_writekey (int keyno, const char *serialno,
- const unsigned char *keydata, size_t keydatalen)
-{
- int rc;
- char line[ASSUAN_LINELENGTH];
- struct writekey_parm_s parms;
- struct default_inq_parm_s dfltparm;
-
- memset (&dfltparm, 0, sizeof dfltparm);
-
- (void)serialno;
-
- rc = start_agent (NULL, 1);
- if (rc)
- return rc;
-
- memset (&parms, 0, sizeof parms);
-
- snprintf (line, DIM(line), "SCD WRITEKEY --force OPENPGP.%d", keyno);
- dfltparm.ctx = agent_ctx;
- parms.dflt = &dfltparm;
- parms.keydata = keydata;
- parms.keydatalen = keydatalen;
-
- rc = assuan_transact (agent_ctx, line, NULL, NULL,
- inq_writekey_parms, &parms, NULL, NULL);
-
- status_sc_op_failure (rc);
- return rc;
-}
-
-
-
/* Status callback for the SCD GENKEY command. */
static gpg_error_t
scd_genkey_cb (void *opaque, const char *line)
@@ -1065,10 +1245,13 @@ scd_genkey_cb (void *opaque, const char *line)
}
/* Send a GENKEY command to the SCdaemon. If *CREATETIME is not 0,
- the value will be passed to SCDAEMON with --timestamp option so that
- the key is created with this. Otherwise, timestamp was generated by
- SCDEAMON. On success, creation time is stored back to
- CREATETIME. */
+ * the value will be passed to SCDAEMON with --timestamp option so that
+ * the key is created with this. Otherwise, timestamp was generated by
+ * SCDEAMON. On success, creation time is stored back to
+ * CREATETIME.
+ * Used by:
+ * gen_card_key
+ */
int
agent_scd_genkey (int keyno, int force, u32 *createtime)
{
@@ -1101,9 +1284,17 @@ agent_scd_genkey (int keyno, int force, u32 *createtime)
status_sc_op_failure (rc);
return rc;
}
+
+
/* Return the serial number of the card or an appropriate error. The
- serial number is returned as a hexstring. */
+ * serial number is returned as a hexstring. With DEMAND the active
+ * card is switched to the card with that serialno.
+ * Used by:
+ * card-util.c
+ * build_sk_list
+ * enum_secret_keys
+ */
int
agent_scd_serialno (char **r_serialno, const char *demand)
{
@@ -1111,7 +1302,7 @@ agent_scd_serialno (char **r_serialno, const char *demand)
char *serialno = NULL;
char line[ASSUAN_LINELENGTH];
- err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS);
+ err = start_agent (NULL, (1 | FLAG_FOR_CARD_SUPPRESS_ERRORS));
if (err)
return err;
@@ -1132,8 +1323,13 @@ agent_scd_serialno (char **r_serialno, const char *demand)
*r_serialno = serialno;
return 0;
}
+
+
-/* Send a READCERT command to the SCdaemon. */
+/* Send a READCERT command to the SCdaemon.
+ * Used by:
+ * card-util.c
+ */
int
agent_scd_readcert (const char *certidstr,
void **r_buf, size_t *r_buflen)
@@ -1171,6 +1367,51 @@ agent_scd_readcert (const char *certidstr,
return 0;
}
+
+
+/* This is a variant of agent_readkey which sends a READKEY command
+ * directly Scdaemon. On success a new s-expression is stored at
+ * R_RESULT. */
+gpg_error_t
+agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result)
+{
+ gpg_error_t err;
+ char line[ASSUAN_LINELENGTH];
+ membuf_t data;
+ unsigned char *buf;
+ size_t len, buflen;
+ struct default_inq_parm_s dfltparm;
+
+ memset (&dfltparm, 0, sizeof dfltparm);
+ dfltparm.ctx = agent_ctx;
+
+ *r_result = NULL;
+ err = start_agent (NULL, 1);
+ if (err)
+ return err;
+
+ init_membuf (&data, 1024);
+ snprintf (line, DIM(line), "SCD READKEY %s", keyrefstr);
+ err = assuan_transact (agent_ctx, line,
+ put_membuf_cb, &data,
+ default_inq_cb, &dfltparm,
+ NULL, NULL);
+ if (err)
+ {
+ xfree (get_membuf (&data, &len));
+ return err;
+ }
+ buf = get_membuf (&data, &buflen);
+ if (!buf)
+ return gpg_error_from_syserror ();
+
+ err = gcry_sexp_new (r_result, buf, buflen, 0);
+ xfree (buf);
+
+ return err;
+}
+
+
struct card_cardlist_parm_s {
int error;
@@ -1208,7 +1449,12 @@ card_cardlist_cb (void *opaque, const char *line)
return 0;
}
-/* Return cardlist. */
+
+/* Return a list of currently available cards.
+ * Used by:
+ * card-util.c
+ * skclist.c
+ */
int
agent_scd_cardlist (strlist_t *result)
{
@@ -1237,16 +1483,20 @@ agent_scd_cardlist (strlist_t *result)
return 0;
}
+
+
/* Change the PIN of an OpenPGP card or reset the retry counter.
- CHVNO 1: Change the PIN
- 2: For v1 cards: Same as 1.
- For v2 cards: Reset the PIN using the Reset Code.
- 3: Change the admin PIN
- 101: Set a new PIN and reset the retry counter
- 102: For v1 cars: Same as 101.
- For v2 cards: Set a new Reset Code.
- SERIALNO is not used.
+ * CHVNO 1: Change the PIN
+ * 2: For v1 cards: Same as 1.
+ * For v2 cards: Reset the PIN using the Reset Code.
+ * 3: Change the admin PIN
+ * 101: Set a new PIN and reset the retry counter
+ * 102: For v1 cars: Same as 101.
+ * For v2 cards: Set a new Reset Code.
+ * SERIALNO is not used.
+ * Used by:
+ * card-util.c
*/
int
agent_scd_change_pin (int chvno, const char *serialno)
@@ -1280,8 +1530,11 @@ agent_scd_change_pin (int chvno, const char *serialno)
/* Perform a CHECKPIN operation. SERIALNO should be the serial
- number of the card - optionally followed by the fingerprint;
- however the fingerprint is ignored here. */
+ * number of the card - optionally followed by the fingerprint;
+ * however the fingerprint is ignored here.
+ * Used by:
+ * card-util.c
+ */
int
agent_scd_checkpin (const char *serialno)
{
@@ -1306,15 +1559,6 @@ agent_scd_checkpin (const char *serialno)
}
-/* Dummy function, only used by the gpg 1.4 implementation. */
-void
-agent_clear_pin_cache (const char *sn)
-{
- (void)sn;
-}
-
-
-
/* Note: All strings shall be UTF-8. On success the caller needs to
free the string stored at R_PASSPHRASE. On error NULL will be
@@ -2299,6 +2543,31 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
}
+/* Status callback for handling confirmation. */
+static gpg_error_t
+confirm_status_cb (void *opaque, const char *line)
+{
+ struct confirm_parm_s *parm = opaque;
+ const char *s;
+
+ if ((s = has_leading_keyword (line, "SETDESC")))
+ {
+ xfree (parm->desc);
+ parm->desc = unescape_status_string (s);
+ }
+ else if ((s = has_leading_keyword (line, "SETOK")))
+ {
+ xfree (parm->ok);
+ parm->ok = unescape_status_string (s);
+ }
+ else if ((s = has_leading_keyword (line, "SETNOTOK")))
+ {
+ xfree (parm->notok);
+ parm->notok = unescape_status_string (s);
+ }
+
+ return 0;
+}
/* Ask the agent to delete the key identified by HEXKEYGRIP. If DESC
is not NULL, display DESC instead of the default description
@@ -2311,9 +2580,12 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct default_inq_parm_s dfltparm;
+ struct confirm_parm_s confirm_parm;
+ memset (&confirm_parm, 0, sizeof confirm_parm);
memset (&dfltparm, 0, sizeof dfltparm);
dfltparm.ctrl = ctrl;
+ dfltparm.confirm = &confirm_parm;
err = start_agent (ctrl, 0);
if (err)
@@ -2335,7 +2607,10 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
force? " --force":"", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, &dfltparm,
- NULL, NULL);
+ confirm_status_cb, &confirm_parm);
+ xfree (confirm_parm.desc);
+ xfree (confirm_parm.ok);
+ xfree (confirm_parm.notok);
return err;
}
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 8619a34f8..c4d0a9de1 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -84,6 +84,10 @@ void agent_release_card_info (struct agent_card_info_s *info);
/* Return card info. */
int agent_scd_learn (struct agent_card_info_s *info, int force);
+/* Get the keypariinfo directly from scdaemon. */
+gpg_error_t agent_scd_keypairinfo (ctrl_t ctrl, const char *keyref,
+ strlist_t *r_list);
+
/* Return list of cards. */
int agent_scd_cardlist (strlist_t *result);
@@ -93,6 +97,9 @@ int agent_scd_serialno (char **r_serialno, const char *demand);
/* Send an APDU to the card. */
gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
+/* Get attribute NAME from the card and store at R_VALUE. */
+gpg_error_t agent_scd_getattr_one (const char *name, char **r_value);
+
/* Update INFO with the attribute NAME. */
int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
@@ -101,35 +108,29 @@ int agent_keytocard (const char *hexgrip, int keyno, int force,
const char *serialno, const char *timestamp);
/* Send a SETATTR command to the SCdaemon. */
-int agent_scd_setattr (const char *name,
- const unsigned char *value, size_t valuelen,
- const char *serialno);
+gpg_error_t agent_scd_setattr (const char *name,
+ const void *value, size_t valuelen);
/* Send a WRITECERT command to the SCdaemon. */
int agent_scd_writecert (const char *certidstr,
const unsigned char *certdata, size_t certdatalen);
-/* Send a WRITEKEY command to the SCdaemon. */
-int agent_scd_writekey (int keyno, const char *serialno,
- const unsigned char *keydata, size_t keydatalen);
-
/* Send a GENKEY command to the SCdaemon. */
int agent_scd_genkey (int keyno, int force, u32 *createtime);
-/* Send a READKEY command to the SCdaemon. */
+/* Send a READCERT command to the SCdaemon. */
int agent_scd_readcert (const char *certidstr,
void **r_buf, size_t *r_buflen);
+/* Send a READKEY command to the SCdaemon. */
+gpg_error_t agent_scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result);
+
/* Change the PIN of an OpenPGP card or reset the retry counter. */
int agent_scd_change_pin (int chvno, const char *serialno);
/* Send the CHECKPIN command to the SCdaemon. */
int agent_scd_checkpin (const char *serialno);
-/* Dummy function, only implemented by gpg 1.4. */
-void agent_clear_pin_cache (const char *sn);
-
-
/* Send the GET_PASSPHRASE command to the agent. */
gpg_error_t agent_get_passphrase (const char *cache_id,
const char *err_msg,
diff --git a/g10/card-util.c b/g10/card-util.c
index 08844bae3..1b9461e0a 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -91,8 +91,6 @@ change_pin (int unblock_v2, int allow_admin)
log_info (_("OpenPGP card no. %s detected\n"),
info.serialno? info.serialno : "[none]");
- agent_clear_pin_cache (info.serialno);
-
if (opt.batch)
{
agent_release_card_info (&info);
@@ -421,36 +419,43 @@ current_card_status (ctrl_t ctrl, estream_t fp,
if (!info.serialno || strncmp (info.serialno, "D27600012401", 12)
|| strlen (info.serialno) != 32 )
{
+ const char *name1, *name2;
if (info.apptype && !strcmp (info.apptype, "NKS"))
{
- if (opt.with_colons)
- es_fputs ("netkey-card:\n", fp);
- log_info ("this is a NetKey card\n");
+ name1 = "netkey";
+ name2 = "NetKey";
}
else if (info.apptype && !strcmp (info.apptype, "DINSIG"))
{
- if (opt.with_colons)
- es_fputs ("dinsig-card:\n", fp);
- log_info ("this is a DINSIG compliant card\n");
+ name1 = "dinsig";
+ name2 = "DINSIG";
}
else if (info.apptype && !strcmp (info.apptype, "P15"))
{
- if (opt.with_colons)
- es_fputs ("pkcs15-card:\n", fp);
- log_info ("this is a PKCS#15 compliant card\n");
+ name1 = "pkcs15";
+ name2 = "PKCS#15";
}
else if (info.apptype && !strcmp (info.apptype, "GELDKARTE"))
{
- if (opt.with_colons)
- es_fputs ("geldkarte-card:\n", fp);
- log_info ("this is a Geldkarte compliant card\n");
+ name1 = "geldkarte";
+ name2 = "Geldkarte";
+ }
+ else if (info.apptype && !strcmp (info.apptype, "PIV"))
+ {
+ name1 = "piv";
+ name2 = "PIV";
}
else
{
- if (opt.with_colons)
- es_fputs ("unknown:\n", fp);
+ name1 = "unknown";
+ name2 = "Unknown";
}
- log_info ("not an OpenPGP card\n");
+
+ if (opt.with_colons)
+ es_fprintf (fp, "%s-card:\n", name1);
+ else
+ tty_fprintf (fp, "Application type .: %s\n", name2);
+
agent_release_card_info (&info);
xfree (pk);
return;
@@ -465,6 +470,8 @@ current_card_status (ctrl_t ctrl, estream_t fp,
if (opt.with_colons)
es_fputs ("openpgp-card:\n", fp);
+ else
+ tty_fprintf (fp, "Application type .: %s\n", "OpenPGP");
if (opt.with_colons)
@@ -673,9 +680,8 @@ current_card_status (ctrl_t ctrl, estream_t fp,
if ( thefpr && !fpr_is_ff (thefpr, thefprlen)
&& !get_pubkey_byfprint (ctrl, pk, &keyblock, thefpr, thefprlen))
{
- print_pubkey_info (ctrl, fp, pk);
- if (keyblock)
- print_card_key_info (fp, keyblock);
+ print_key_info (ctrl, fp, 0, pk, 0);
+ print_card_key_info (fp, keyblock);
}
else
tty_fprintf (fp, "[none]\n");
@@ -697,6 +703,7 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
strlist_t card_list, sl;
char *serialno0, *serialno1;
int all_cards = 0;
+ int any_card = 0;
if (serialno == NULL)
{
@@ -724,6 +731,10 @@ card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
if (!all_cards && strcmp (serialno, sl->d))
continue;
+ if (any_card && !opt.with_colons)
+ tty_fprintf (fp, "\n");
+ any_card = 1;
+
err = agent_scd_serialno (&serialno1, sl->d);
if (err)
{
@@ -816,7 +827,7 @@ change_name (void)
return -1;
}
- rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname), NULL );
+ rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname));
if (rc)
log_error ("error setting Name: %s\n", gpg_strerror (rc));
@@ -837,7 +848,7 @@ change_url (void)
trim_spaces (url);
cpr_kill_prompt ();
- rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url), NULL );
+ rc = agent_scd_setattr ("PUBKEY-URL", url, strlen (url));
if (rc)
log_error ("error setting URL: %s\n", gpg_strerror (rc));
xfree (url);
@@ -995,7 +1006,7 @@ change_login (const char *args)
n = strlen (data);
}
- rc = agent_scd_setattr ("LOGIN-DATA", data, n, NULL );
+ rc = agent_scd_setattr ("LOGIN-DATA", data, n);
if (rc)
log_error ("error setting login data: %s\n", gpg_strerror (rc));
xfree (data);
@@ -1033,7 +1044,7 @@ change_private_do (const char *args, int nr)
n = strlen (data);
}
- rc = agent_scd_setattr (do_name, data, n, NULL );
+ rc = agent_scd_setattr (do_name, data, n);
if (rc)
log_error ("error setting private DO: %s\n", gpg_strerror (rc));
xfree (data);
@@ -1132,7 +1143,7 @@ change_lang (void)
return -1;
}
- rc = agent_scd_setattr ("DISP-LANG", data, strlen (data), NULL );
+ rc = agent_scd_setattr ("DISP-LANG", data, strlen (data));
if (rc)
log_error ("error setting lang: %s\n", gpg_strerror (rc));
xfree (data);
@@ -1168,7 +1179,7 @@ change_sex (void)
return -1;
}
- rc = agent_scd_setattr ("DISP-SEX", str, 1, NULL );
+ rc = agent_scd_setattr ("DISP-SEX", str, 1);
if (rc)
log_error ("error setting salutation: %s\n", gpg_strerror (rc));
xfree (data);
@@ -1216,7 +1227,7 @@ change_cafpr (int fprno)
rc = agent_scd_setattr (fprno==1?"CA-FPR-1":
fprno==2?"CA-FPR-2":
- fprno==3?"CA-FPR-3":"x", fpr, fprlen, NULL );
+ fprno==3?"CA-FPR-3":"x", fpr, fprlen);
if (rc)
log_error ("error setting cafpr: %s\n", gpg_strerror (rc));
write_sc_op_status (rc);
@@ -1242,7 +1253,7 @@ toggle_forcesig (void)
newstate = !info.chv1_cached;
agent_release_card_info (&info);
- rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1, NULL);
+ rc = agent_scd_setattr ("CHV-STATUS-1", newstate? "\x01":"", 1);
if (rc)
log_error ("error toggling signature PIN flag: %s\n", gpg_strerror (rc));
write_sc_op_status (rc);
@@ -1285,14 +1296,12 @@ check_pin_for_key_operation (struct agent_card_info_s *info, int *forced_chv1)
{
int rc = 0;
- agent_clear_pin_cache (info->serialno);
-
*forced_chv1 = !info->chv1_cached;
if (*forced_chv1)
{ /* Switch off the forced mode so that during key generation we
don't get bothered with PIN queries for each
self-signature. */
- rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1, info->serialno);
+ rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1);
if (rc)
{
log_error ("error clearing forced signature PIN flag: %s\n",
@@ -1323,7 +1332,7 @@ restore_forced_chv1 (int *forced_chv1)
if (*forced_chv1)
{ /* Switch back to forced state. */
- rc = agent_scd_setattr ("CHV-STATUS-1", "", 1, NULL);
+ rc = agent_scd_setattr ("CHV-STATUS-1", "", 1);
if (rc)
{
log_error ("error setting forced signature PIN flag: %s\n",
@@ -1570,7 +1579,7 @@ do_change_keyattr (int keyno, const struct key_attr *key_attr)
return gpg_error (GPG_ERR_PUBKEY_ALGO);
}
- err = agent_scd_setattr ("KEY-ATTR", args, strlen (args), NULL);
+ err = agent_scd_setattr ("KEY-ATTR", args, strlen (args));
if (err)
log_error (_("error changing key attribute for key %d: %s\n"),
keyno+1, gpg_strerror (err));
@@ -2116,8 +2125,7 @@ kdf_setup (const char *args)
goto leave_error;
err = agent_scd_setattr ("KDF", kdf_data,
- single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX,
- NULL);
+ single ? KDF_DATA_LENGTH_MIN : KDF_DATA_LENGTH_MAX);
if (err)
goto leave_error;
@@ -2169,7 +2177,7 @@ uif (int arg_number, const char *arg_rest)
data[1] = 0x20;
- err = agent_scd_setattr (name, data, 2, NULL);
+ err = agent_scd_setattr (name, data, 2);
if (err)
log_error (_("error for setup UIF: %s\n"), gpg_strerror (err));
}
diff --git a/g10/cpr.c b/g10/cpr.c
index 3d39d6bda..d502e8b52 100644
--- a/g10/cpr.c
+++ b/g10/cpr.c
@@ -62,7 +62,7 @@ progress_cb (void *ctx, const char *what, int printchar,
/* Return true if the status message NO may currently be issued. We
- need this to avoid syncronisation problem while auto retrieving a
+ need this to avoid synchronization problem while auto retrieving a
key. There it may happen that a status NODATA is issued for a non
available key and the user may falsely interpret this has a missing
signature. */
diff --git a/g10/decrypt-data.c b/g10/decrypt-data.c
index 4d9dc86d9..c73d5fb45 100644
--- a/g10/decrypt-data.c
+++ b/g10/decrypt-data.c
@@ -471,6 +471,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
{
char *filename = NULL;
estream_t fp;
+
rc = get_output_file ("", 0, ed->buf, &filename, &fp);
if (! rc)
{
@@ -492,8 +493,7 @@ decrypt_data (ctrl_t ctrl, void *procctx, PKT_encrypted *ed, DEK *dek)
filename, gpg_strerror (rc));
iobuf_close (output);
- if (afx)
- release_armor_context (afx);
+ release_armor_context (afx);
}
xfree (filename);
}
diff --git a/g10/decrypt.c b/g10/decrypt.c
index 4d6734d40..9589aff58 100644
--- a/g10/decrypt.c
+++ b/g10/decrypt.c
@@ -48,7 +48,6 @@ decrypt_message (ctrl_t ctrl, const char *filename)
armor_filter_context_t *afx = NULL;
progress_filter_context_t *pfx;
int rc;
- int no_out = 0;
pfx = new_progress_context ();
@@ -82,11 +81,13 @@ decrypt_message (ctrl_t ctrl, const char *filename)
if (!opt.outfile)
{
- no_out = 1;
opt.outfile = "-";
+ opt.flags.dummy_outfile = 1;
}
+ else
+ opt.flags.dummy_outfile = 0;
rc = proc_encryption_packets (ctrl, NULL, fp );
- if (no_out)
+ if (opt.flags.dummy_outfile)
opt.outfile = NULL;
iobuf_close (fp);
diff --git a/g10/delkey.c b/g10/delkey.c
index cc5673846..b5ab47434 100644
--- a/g10/delkey.c
+++ b/g10/delkey.c
@@ -1,7 +1,7 @@
/* delkey.c - delete keys
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004,
* 2005, 2006 Free Software Foundation, Inc.
- * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2014, 2019 Werner Koch
*
* This file is part of GnuPG.
*
@@ -53,13 +53,15 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
gpg_error_t err;
kbnode_t keyblock = NULL;
kbnode_t node, kbctx;
+ kbnode_t targetnode;
KEYDB_HANDLE hd;
PKT_public_key *pk = NULL;
u32 keyid[2];
int okay=0;
int yes;
KEYDB_SEARCH_DESC desc;
- int exactmatch;
+ int exactmatch; /* True if key was found by fingerprint. */
+ int thiskeyonly; /* 0 = false, 1 = is primary key, 2 = is a subkey. */
*r_sec_avail = 0;
@@ -70,6 +72,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
/* Search the userid. */
err = classify_user_id (username, &desc, 1);
exactmatch = (desc.mode == KEYDB_SEARCH_MODE_FPR);
+ thiskeyonly = desc.exact;
if (!err)
err = keydb_search (hd, &desc, 1, NULL);
if (err)
@@ -95,7 +98,35 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
- pk = node->pkt->pkt.public_key;
+
+ /* If an operation only on a subkey is requested, find that subkey
+ * now. */
+ if (thiskeyonly)
+ {
+ kbnode_t tmpnode;
+
+ for (kbctx=NULL; (tmpnode = walk_kbnode (keyblock, &kbctx, 0)); )
+ {
+ if (!(tmpnode->pkt->pkttype == PKT_PUBLIC_KEY
+ || tmpnode->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+ continue;
+ if (exact_subkey_match_p (&desc, tmpnode))
+ break;
+ }
+ if (!tmpnode)
+ {
+ log_error ("Oops; requested subkey not found anymore!\n");
+ err = gpg_error (GPG_ERR_GENERAL);
+ goto leave;
+ }
+ /* Set NODE to this specific subkey or primary key. */
+ thiskeyonly = node == tmpnode? 1 : 2;
+ targetnode = tmpnode;
+ }
+ else
+ targetnode = node;
+
+ pk = targetnode->pkt->pkt.public_key;
keyid_from_pk (pk, keyid);
if (!secret && !force)
@@ -135,11 +166,33 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
}
else
{
- if (secret)
- print_seckey_info (ctrl, pk);
- else
- print_pubkey_info (ctrl, NULL, pk );
- tty_printf( "\n" );
+ print_key_info (ctrl, NULL, 0, pk, secret);
+ tty_printf ("\n");
+ if (thiskeyonly == 1 && !secret)
+ {
+ /* We need to delete the entire public key despite the use
+ * of the thiskeyonly request. */
+ tty_printf (_("Note: The public primary key and all its subkeys"
+ " will be deleted.\n"));
+ }
+ else if (thiskeyonly == 2 && !secret)
+ {
+ tty_printf (_("Note: Only the shown public subkey"
+ " will be deleted.\n"));
+ }
+ if (thiskeyonly == 1 && secret)
+ {
+ tty_printf (_("Note: Only the secret part of the shown primary"
+ " key will be deleted.\n"));
+ }
+ else if (thiskeyonly == 2 && secret)
+ {
+ tty_printf (_("Note: Only the secret part of the shown subkey"
+ " will be deleted.\n"));
+ }
+
+ if (thiskeyonly)
+ tty_printf ("\n");
yes = cpr_get_answer_is_yes
(secret? "delete_key.secret.okay": "delete_key.okay",
@@ -176,6 +229,9 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
continue;
+ if (thiskeyonly && targetnode != node)
+ continue;
+
if (agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
continue; /* No secret key for that public (sub)key. */
@@ -188,7 +244,7 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
* pre-caution is that since 2.1 the secret key may also
* be used for other protocols and thus deleting it from
* the gpg would also delete the key for other tools. */
- if (!err)
+ if (!err && !opt.dry_run)
err = agent_delete_key (NULL, hexgrip, prompt,
opt.answer_yes);
xfree (prompt);
@@ -217,6 +273,35 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
if (firsterr)
goto leave;
}
+ else if (thiskeyonly == 2)
+ {
+ int selected = 0;
+
+ /* Delete the specified public subkey. */
+ for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+ {
+ if (thiskeyonly && targetnode != node)
+ continue;
+
+ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ selected = targetnode == node;
+ if (selected)
+ delete_kbnode (node);
+ }
+ else if (selected && node->pkt->pkttype == PKT_SIGNATURE)
+ delete_kbnode (node);
+ else
+ selected = 0;
+ }
+ commit_kbnode (&keyblock);
+ err = keydb_update_keyblock (ctrl, hd, keyblock);
+ if (err)
+ {
+ log_error (_("update failed: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+ }
else
{
err = keydb_delete_keyblock (hd);
@@ -232,7 +317,8 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
revalidation_mark(). This makes sense - only deleting keys
that have ownertrust set should trigger this. */
- if (!secret && pk && clear_ownertrusts (ctrl, pk))
+ if (!secret && pk && !opt.dry_run && thiskeyonly != 2
+ && clear_ownertrusts (ctrl, pk))
{
if (opt.verbose)
log_info (_("ownertrust information cleared\n"));
@@ -245,7 +331,8 @@ do_delete_key (ctrl_t ctrl, const char *username, int secret, int force,
return err;
}
-/****************
+
+/*
* Delete a public or secret key from a keyring.
*/
gpg_error_t
diff --git a/g10/exec.c b/g10/exec.c
index 74a83970e..3e5dc278b 100644
--- a/g10/exec.c
+++ b/g10/exec.c
@@ -77,37 +77,99 @@ set_exec_path(const char *path) { return GPG_ERR_GENERAL; }
static int
w32_system(const char *command)
{
-#ifdef HAVE_W32CE_SYSTEM
-#warning Change this code to use common/exechelp.c
-#else
- PROCESS_INFORMATION pi;
- STARTUPINFO si;
- char *string;
+ if (!strncmp (command, "!ShellExecute ", 14))
+ {
+ SHELLEXECUTEINFOW see;
+ wchar_t *wname;
+ int waitms;
+
+ command = command + 14;
+ while (spacep (command))
+ command++;
+ waitms = atoi (command);
+ if (waitms < 0)
+ waitms = 0;
+ else if (waitms > 60*1000)
+ waitms = 60000;
+ while (*command && !spacep (command))
+ command++;
+ while (spacep (command))
+ command++;
+
+ wname = utf8_to_wchar (command);
+ if (!wname)
+ return -1;
+
+ memset (&see, 0, sizeof see);
+ see.cbSize = sizeof see;
+ see.fMask = (SEE_MASK_NOCLOSEPROCESS
+ | SEE_MASK_NOASYNC
+ | SEE_MASK_FLAG_NO_UI
+ | SEE_MASK_NO_CONSOLE);
+ see.lpVerb = L"open";
+ see.lpFile = (LPCWSTR)wname;
+ see.nShow = SW_SHOW;
+
+ if (DBG_EXTPROG)
+ log_debug ("running ShellExecuteEx(open,'%s')\n", command);
+ if (!ShellExecuteExW (&see))
+ {
+ if (DBG_EXTPROG)
+ log_debug ("ShellExecuteEx failed: rc=%d\n", (int)GetLastError ());
+ xfree (wname);
+ return -1;
+ }
+ if (DBG_EXTPROG)
+ log_debug ("ShellExecuteEx succeeded (hProcess=%p,hInstApp=%d)\n",
+ see.hProcess, (int)see.hInstApp);
+
+ if (!see.hProcess)
+ {
+ gnupg_usleep (waitms*1000);
+ if (DBG_EXTPROG)
+ log_debug ("ShellExecuteEx ready (wait=%dms)\n", waitms);
+ }
+ else
+ {
+ WaitForSingleObject (see.hProcess, INFINITE);
+ if (DBG_EXTPROG)
+ log_debug ("ShellExecuteEx ready\n");
+ }
+ CloseHandle (see.hProcess);
+
+ xfree (wname);
+ }
+ else
+ {
+ char *string;
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
- /* We must use a copy of the command as CreateProcess modifies this
- argument. */
- string=xstrdup(command);
+ /* We must use a copy of the command as CreateProcess modifies
+ * this argument. */
+ string = xstrdup (command);
- memset(&pi,0,sizeof(pi));
- memset(&si,0,sizeof(si));
- si.cb=sizeof(si);
+ memset (&pi, 0, sizeof(pi));
+ memset (&si, 0, sizeof(si));
+ si.cb = sizeof (si);
- if(!CreateProcess(NULL,string,NULL,NULL,FALSE,
- DETACHED_PROCESS,
- NULL,NULL,&si,&pi))
- return -1;
+ if (!CreateProcess (NULL, string, NULL, NULL, FALSE,
+ DETACHED_PROCESS,
+ NULL, NULL, &si, &pi))
+ return -1;
- /* Wait for the child to exit */
- WaitForSingleObject(pi.hProcess,INFINITE);
+ /* Wait for the child to exit */
+ WaitForSingleObject (pi.hProcess, INFINITE);
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- xfree(string);
+ CloseHandle (pi.hProcess);
+ CloseHandle (pi.hThread);
+ xfree (string);
+ }
return 0;
-#endif
}
-#endif
+#endif /*_W32*/
+
/* Replaces current $PATH */
int
@@ -508,7 +570,7 @@ exec_read(struct exec_info *info)
if(info->flags.use_temp_files)
{
if(DBG_EXTPROG)
- log_debug("system() command is %s\n",info->command);
+ log_debug ("running command: %s\n",info->command);
#if defined (_WIN32)
info->progreturn=w32_system(info->command);
diff --git a/g10/export.c b/g10/export.c
index 4f6c9137e..e8bf14cf5 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -436,8 +436,8 @@ new_subkey_list_item (KBNODE node)
(keyID or fingerprint) and does match the one at NODE. It is
assumed that the packet at NODE is either a public or secret
subkey. */
-static int
-exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, KBNODE node)
+int
+exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node)
{
u32 kid[2];
byte fpr[MAX_FINGERPRINT_LEN];
@@ -596,7 +596,10 @@ cleartext_secret_key_to_openpgp (gcry_sexp_t s_key, PKT_public_key *pk)
top_list = gcry_sexp_find_token (s_key, "private-key", 0);
if (!top_list)
goto bad_seckey;
- if (gcry_sexp_length(top_list) != 2)
+
+ /* ignore all S-expression after the first sublist -- we assume that
+ they are comments or otherwise irrelevant to OpenPGP */
+ if (gcry_sexp_length(top_list) < 2)
goto bad_seckey;
key = gcry_sexp_nth (top_list, 1);
if (!key)
@@ -2171,10 +2174,10 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
{
getkey_ctx_t getkeyctx;
- err = get_pubkey_byname (ctrl, &getkeyctx, NULL, userid, &keyblock,
+ err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ &getkeyctx, NULL, userid, &keyblock,
NULL,
- 0 /* Only usable keys or given exact. */,
- 1 /* No AKL lookup. */);
+ 0 /* Only usable keys or given exact. */);
if (!err)
{
err = getkey_next (ctrl, getkeyctx, NULL, NULL);
diff --git a/g10/getkey.c b/g10/getkey.c
index 9dae879d2..57617a0a9 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -36,6 +36,7 @@
#include "../common/i18n.h"
#include "keyserver-internal.h"
#include "call-agent.h"
+#include "objcache.h"
#include "../common/host2net.h"
#include "../common/mbox-util.h"
#include "../common/status.h"
@@ -112,6 +113,7 @@ static struct
typedef struct keyid_list
{
struct keyid_list *next;
+ byte fprlen;
char fpr[MAX_FINGERPRINT_LEN];
u32 keyid[2];
} *keyid_list_t;
@@ -132,15 +134,6 @@ static int pk_cache_disabled;
#if MAX_UID_CACHE_ENTRIES < 5
#error we really need the userid cache
#endif
-typedef struct user_id_db
-{
- struct user_id_db *next;
- keyid_list_t keyids;
- int len;
- char name[1];
-} *user_id_db_t;
-static user_id_db_t user_id_db;
-static int uid_cache_entries; /* Number of entries in uid cache. */
static void merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock);
static int lookup (ctrl_t ctrl, getkey_ctx_t ctx, int want_secret,
@@ -262,112 +255,6 @@ user_id_not_found_utf8 (void)
-/* Return the user ID from the given keyblock.
- * We use the primary uid flag which has been set by the merge_selfsigs
- * function. The returned value is only valid as long as the given
- * keyblock is not changed. */
-static const char *
-get_primary_uid (KBNODE keyblock, size_t * uidlen)
-{
- KBNODE k;
- const char *s;
-
- for (k = keyblock; k; k = k->next)
- {
- if (k->pkt->pkttype == PKT_USER_ID
- && !k->pkt->pkt.user_id->attrib_data
- && k->pkt->pkt.user_id->flags.primary)
- {
- *uidlen = k->pkt->pkt.user_id->len;
- return k->pkt->pkt.user_id->name;
- }
- }
- s = user_id_not_found_utf8 ();
- *uidlen = strlen (s);
- return s;
-}
-
-
-static void
-release_keyid_list (keyid_list_t k)
-{
- while (k)
- {
- keyid_list_t k2 = k->next;
- xfree (k);
- k = k2;
- }
-}
-
-/****************
- * Store the association of keyid and userid
- * Feed only public keys to this function.
- */
-static void
-cache_user_id (KBNODE keyblock)
-{
- user_id_db_t r;
- const char *uid;
- size_t uidlen;
- keyid_list_t keyids = NULL;
- KBNODE k;
-
- for (k = keyblock; k; k = k->next)
- {
- if (k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
- {
- keyid_list_t a = xmalloc_clear (sizeof *a);
- /* Hmmm: For a long list of keyids it might be an advantage
- * to append the keys. */
- fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL);
- keyid_from_pk (k->pkt->pkt.public_key, a->keyid);
- /* First check for duplicates. */
- for (r = user_id_db; r; r = r->next)
- {
- keyid_list_t b;
-
- for (b = r->keyids; b; b = b->next)
- {
- if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN))
- {
- if (DBG_CACHE)
- log_debug ("cache_user_id: already in cache\n");
- release_keyid_list (keyids);
- xfree (a);
- return;
- }
- }
- }
- /* Now put it into the cache. */
- a->next = keyids;
- keyids = a;
- }
- }
- if (!keyids)
- BUG (); /* No key no fun. */
-
-
- uid = get_primary_uid (keyblock, &uidlen);
-
- if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES)
- {
- /* fixme: use another algorithm to free some cache slots */
- r = user_id_db;
- user_id_db = r->next;
- release_keyid_list (r->keyids);
- xfree (r);
- uid_cache_entries--;
- }
- r = xmalloc (sizeof *r + uidlen - 1);
- r->keyids = keyids;
- r->len = uidlen;
- memcpy (r->name, uid, r->len);
- r->next = user_id_db;
- user_id_db = r;
- uid_cache_entries++;
-}
-
/* Disable and drop the public key cache (which is filled by
cache_public_key and get_pubkey). Note: there is currently no way
@@ -948,11 +835,21 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
/* Find a public key identified by NAME.
*
- * If name appears to be a valid RFC822 mailbox (i.e., email
- * address) and auto key lookup is enabled (no_akl == 0), then the
- * specified auto key lookup methods (--auto-key-lookup) are used to
- * import the key into the local keyring. Otherwise, just the local
- * keyring is consulted.
+ * If name appears to be a valid RFC822 mailbox (i.e., email address)
+ * and auto key lookup is enabled (mode != GET_PUBKEY_NO_AKL), then
+ * the specified auto key lookup methods (--auto-key-lookup) are used
+ * to import the key into the local keyring. Otherwise, just the
+ * local keyring is consulted.
+ *
+ * MODE can be one of:
+ * GET_PUBKEY_NORMAL - The standard mode
+ * GET_PUBKEY_NO_AKL - The auto key locate functionality is
+ * disabled and only the local key ring is
+ * considered. Note: the local key ring is
+ * consulted even if local is not in the
+ * auto-key-locate option list!
+ * GET_PUBKEY_NO_LOCAL - Only the auto key locate functionaly is
+ * used and no local search is done.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
@@ -988,18 +885,14 @@ key_byname (ctrl_t ctrl, GETKEY_CTX *retctx, strlist_t namelist,
* documentation for skip_unusable for an exact definition) are
* skipped unless they are looked up by key id or by fingerprint.
*
- * If NO_AKL is set, then the auto key locate functionality is
- * disabled and only the local key ring is considered. Note: the
- * local key ring is consulted even if local is not in the
- * --auto-key-locate option list!
- *
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found. */
int
-get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
+get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
+ GETKEY_CTX * retctx, PKT_public_key * pk,
const char *name, KBNODE * ret_keyblock,
- KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl)
+ KEYDB_HANDLE * ret_kdbhd, int include_unusable)
{
int rc;
strlist_t namelist = NULL;
@@ -1035,7 +928,9 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
* Note: we only save the search context in RETCTX if the local
* method is the first method tried (either explicitly or
* implicitly). */
- if (!no_akl)
+ if (mode == GET_PUBKEY_NO_LOCAL)
+ nodefault = 1; /* Auto-key-locate but ignore "local". */
+ else if (mode != GET_PUBKEY_NO_AKL)
{
/* auto-key-locate is enabled. */
@@ -1064,7 +959,13 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
anylocalfirst = 1;
}
- if (nodefault && is_mbox)
+ if (mode == GET_PUBKEY_NO_LOCAL)
+ {
+ /* Force using the AKL. If IS_MBOX is not set this is the final
+ * error code. */
+ rc = GPG_ERR_NO_PUBKEY;
+ }
+ else if (nodefault && is_mbox)
{
/* Either "nodefault" or "local" (explicitly) appeared in the
* auto key locate list and NAME appears to be an email address.
@@ -1085,7 +986,9 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
/* If the requested name resembles a valid mailbox and automatic
retrieval has been enabled, we try to import the key. */
- if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && !no_akl && is_mbox)
+ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
+ && mode != GET_PUBKEY_NO_AKL
+ && is_mbox)
{
/* NAME wasn't present in the local keyring (or we didn't try
* the local keyring). Since the auto key locate feature is
@@ -1104,22 +1007,30 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
{
case AKL_NODEFAULT:
/* This is a dummy mechanism. */
- mechanism_string = "None";
+ mechanism_string = "";
rc = GPG_ERR_NO_PUBKEY;
break;
case AKL_LOCAL:
- mechanism_string = "Local";
- did_akl_local = 1;
- if (retctx)
- {
- getkey_end (ctrl, *retctx);
- *retctx = NULL;
- }
- add_to_strlist (&namelist, name);
- rc = key_byname (ctrl, anylocalfirst ? retctx : NULL,
- namelist, pk, 0,
- include_unusable, ret_keyblock, ret_kdbhd);
+ if (mode == GET_PUBKEY_NO_LOCAL)
+ {
+ mechanism_string = "";
+ rc = GPG_ERR_NO_PUBKEY;
+ }
+ else
+ {
+ mechanism_string = "Local";
+ did_akl_local = 1;
+ if (retctx)
+ {
+ getkey_end (ctrl, *retctx);
+ *retctx = NULL;
+ }
+ add_to_strlist (&namelist, name);
+ rc = key_byname (ctrl, anylocalfirst ? retctx : NULL,
+ namelist, pk, 0,
+ include_unusable, ret_keyblock, ret_kdbhd);
+ }
break;
case AKL_CERT:
@@ -1246,15 +1157,14 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
name, mechanism_string);
break;
}
- if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY
- || opt.verbose || no_fingerprint)
+ if ((gpg_err_code (rc) != GPG_ERR_NO_PUBKEY
+ || opt.verbose || no_fingerprint) && *mechanism_string)
log_info (_("error retrieving '%s' via %s: %s\n"),
name, mechanism_string,
no_fingerprint ? _("No fingerprint") : gpg_strerror (rc));
}
}
-
if (rc && retctx)
{
getkey_end (ctrl, *retctx);
@@ -1315,7 +1225,7 @@ subkey_is_ok (const PKT_public_key *sub)
/* Return true if KEYBLOCK has only expired encryption subkyes. Note
* that the function returns false if the key has no encryption
- * subkeys at all or the subkecys are revoked. */
+ * subkeys at all or the subkeys are revoked. */
static int
only_expired_enc_subkeys (kbnode_t keyblock)
{
@@ -1407,7 +1317,8 @@ pubkey_cmp (ctrl_t ctrl, const char *name, struct pubkey_cmp_cookie *old,
* resembles a mail address, the results are ranked and only the best
* result is returned. */
gpg_error_t
-get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
+get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
+ GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
int include_unusable)
{
@@ -1430,8 +1341,9 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
getkey_end (ctrl, ctx);
ctx = NULL;
}
- err = get_pubkey_byname (ctrl, &ctx, pk, name, ret_keyblock,
- NULL, include_unusable, 0);
+ err = get_pubkey_byname (ctrl, mode,
+ &ctx, pk, name, ret_keyblock,
+ NULL, include_unusable);
if (err)
{
getkey_end (ctrl, ctx);
@@ -1493,15 +1405,14 @@ get_best_pubkey_byname (ctrl_t ctrl, GETKEY_CTX *retctx, PKT_public_key *pk,
/* Old key is better. */
release_public_key_parts (&new.key);
free_user_id (new.uid);
- new.uid = NULL;
}
else
{
/* A tie. Keep the old key. */
release_public_key_parts (&new.key);
free_user_id (new.uid);
- new.uid = NULL;
}
+ new.uid = NULL;
}
getkey_end (ctrl, ctx);
ctx = NULL;
@@ -1637,7 +1548,7 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
*
* FPRINT is a byte array whose contents is the fingerprint to use as
* the search term. FPRINT_LEN specifies the length of the
- * fingerprint (in bytes). Currently, only 16 and 20-byte
+ * fingerprint (in bytes). Currently, only 16, 20, and 32-byte
* fingerprints are supported.
*
* FIXME: We should replace this with the _byname function. This can
@@ -3291,7 +3202,11 @@ merge_selfsigs (ctrl_t ctrl, kbnode_t keyblock)
memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
}
if (main_pk->has_expired)
- pk->has_expired = main_pk->has_expired;
+ {
+ pk->has_expired = main_pk->has_expired;
+ if (!pk->expiredate || pk->expiredate > main_pk->expiredate)
+ pk->expiredate = main_pk->expiredate;
+ }
}
}
return;
@@ -3623,7 +3538,7 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
xfree (tempkeystr);
}
- cache_user_id (keyblock);
+ cache_put_keyblock (keyblock);
return latest_key ? latest_key : keyblock; /* Found. */
}
@@ -3836,67 +3751,40 @@ get_seckey_default_or_card (ctrl_t ctrl, PKT_public_key *pk,
* this string must be freed by xfree. If R_NOUID is not NULL it is
* set to true if a user id was not found; otherwise to false. */
static char *
-get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len,
- int *r_nouid)
+get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode)
{
- user_id_db_t r;
- keyid_list_t a;
- int pass = 0;
+ char *name;
+ unsigned int namelen;
char *p;
- if (r_nouid)
- *r_nouid = 0;
+ log_assert (mode != 2);
- /* Try it two times; second pass reads from the database. */
- do
+ name = cache_get_uid_bykid (keyid, &namelen);
+ if (!name)
{
- for (r = user_id_db; r; r = r->next)
- {
- for (a = r->keyids; a; a = a->next)
- {
- if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
- {
- if (mode == 2)
- {
- /* An empty string as user id is possible. Make
- sure that the malloc allocates one byte and
- does not bail out. */
- p = xmalloc (r->len? r->len : 1);
- memcpy (p, r->name, r->len);
- if (r_len)
- *r_len = r->len;
- }
- else
- {
- if (mode)
- p = xasprintf ("%08lX%08lX %.*s",
- (ulong) keyid[0], (ulong) keyid[1],
- r->len, r->name);
- else
- p = xasprintf ("%s %.*s", keystr (keyid),
- r->len, r->name);
- if (r_len)
- *r_len = strlen (p);
- }
-
- return p;
- }
- }
- }
+ /* Get it so that the cache will be filled. */
+ if (!get_pubkey (ctrl, NULL, keyid))
+ name = cache_get_uid_bykid (keyid, &namelen);
}
- while (++pass < 2 && !get_pubkey (ctrl, NULL, keyid));
- if (mode == 2)
- p = xstrdup (user_id_not_found_utf8 ());
- else if (mode)
- p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
+ if (name)
+ {
+ if (mode)
+ p = xasprintf ("%08lX%08lX %.*s",
+ (ulong) keyid[0], (ulong) keyid[1], namelen, name);
+ else
+ p = xasprintf ("%s %.*s", keystr (keyid), namelen, name);
+
+ xfree (name);
+ }
else
- p = xasprintf ("%s [?]", keystr (keyid));
+ {
+ if (mode)
+ p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
+ else
+ p = xasprintf ("%s [?]", keystr (keyid));
+ }
- if (r_nouid)
- *r_nouid = 1;
- if (r_len)
- *r_len = strlen (p);
return p;
}
@@ -3904,7 +3792,7 @@ get_user_id_string (ctrl_t ctrl, u32 * keyid, int mode, size_t *r_len,
char *
get_user_id_string_native (ctrl_t ctrl, u32 * keyid)
{
- char *p = get_user_id_string (ctrl, keyid, 0, NULL, NULL);
+ char *p = get_user_id_string (ctrl, keyid, 0);
char *p2 = utf8_to_native (p, strlen (p), 0);
xfree (p);
return p2;
@@ -3914,7 +3802,7 @@ get_user_id_string_native (ctrl_t ctrl, u32 * keyid)
char *
get_long_user_id_string (ctrl_t ctrl, u32 * keyid)
{
- return get_user_id_string (ctrl, keyid, 1, NULL, NULL);
+ return get_user_id_string (ctrl, keyid, 1);
}
@@ -3922,7 +3810,31 @@ get_long_user_id_string (ctrl_t ctrl, u32 * keyid)
char *
get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid)
{
- return get_user_id_string (ctrl, keyid, 2, rn, r_nouid);
+ char *name;
+ unsigned int namelen;
+
+ if (r_nouid)
+ *r_nouid = 0;
+
+ name = cache_get_uid_bykid (keyid, &namelen);
+ if (!name)
+ {
+ /* Get it so that the cache will be filled. */
+ if (!get_pubkey (ctrl, NULL, keyid))
+ name = cache_get_uid_bykid (keyid, &namelen);
+ }
+
+ if (!name)
+ {
+ name = xstrdup (user_id_not_found_utf8 ());
+ namelen = strlen (name);
+ if (r_nouid)
+ *r_nouid = 1;
+ }
+
+ if (rn && name)
+ *rn = namelen;
+ return name;
}
@@ -3943,49 +3855,36 @@ get_user_id_native (ctrl_t ctrl, u32 *keyid)
returned string, which must be freed using xfree, may not be NUL
terminated. To determine the length of the string, you must use
*RN. */
-char *
-get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn)
+static char *
+get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t fprlen, size_t *rn)
{
- user_id_db_t r;
- char *p;
- int pass = 0;
+ char *name;
- /* Try it two times; second pass reads from the database. */
- do
+ name = cache_get_uid_byfpr (fpr, fprlen, rn);
+ if (!name)
{
- for (r = user_id_db; r; r = r->next)
- {
- keyid_list_t a;
- for (a = r->keyids; a; a = a->next)
- {
- if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN))
- {
- /* An empty string as user id is possible. Make
- sure that the malloc allocates one byte and does
- not bail out. */
- p = xmalloc (r->len? r->len : 1);
- memcpy (p, r->name, r->len);
- *rn = r->len;
- return p;
- }
- }
- }
+ /* Get it so that the cache will be filled. */
+ if (!get_pubkey_byfprint (ctrl, NULL, NULL, fpr, fprlen))
+ name = cache_get_uid_byfpr (fpr, fprlen, rn);
}
- while (++pass < 2
- && !get_pubkey_byfprint (ctrl, NULL, NULL, fpr, MAX_FINGERPRINT_LEN));
- p = xstrdup (user_id_not_found_utf8 ());
- *rn = strlen (p);
- return p;
+
+ if (!name)
+ {
+ name = xstrdup (user_id_not_found_utf8 ());
+ *rn = strlen (name);
+ }
+
+ return name;
}
/* Like get_user_id_byfpr, but convert the string to the native
encoding. The returned string needs to be freed. Unlike
get_user_id_byfpr, the returned string is NUL terminated. */
char *
-get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr)
+get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen)
{
size_t rn;
- char *p = get_user_id_byfpr (ctrl, fpr, &rn);
+ char *p = get_user_id_byfpr (ctrl, fpr, fprlen, &rn);
char *p2 = utf8_to_native (p, rn, 0);
xfree (p);
return p2;
diff --git a/g10/gpg.c b/g10/gpg.c
index 1ab7b0497..0bbe72394 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -59,6 +59,7 @@
#include "../common/asshelp.h"
#include "call-dirmngr.h"
#include "tofu.h"
+#include "objcache.h"
#include "../common/init.h"
#include "../common/mbox-util.h"
#include "../common/shareddefs.h"
@@ -148,6 +149,7 @@ enum cmd_and_opt_values
aSendKeys,
aRecvKeys,
aLocateKeys,
+ aLocateExtKeys,
aSearchKeys,
aRefreshKeys,
aFetchKeys,
@@ -502,6 +504,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aRefreshKeys, "refresh-keys",
N_("update all keys from a keyserver")),
ARGPARSE_c (aLocateKeys, "locate-keys", "@"),
+ ARGPARSE_c (aLocateExtKeys, "locate-external-keys", "@"),
ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
ARGPARSE_c (aShowKeys, "show-keys" , "@" ),
ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
@@ -2421,7 +2424,9 @@ main (int argc, char **argv)
opt.import_options = IMPORT_REPAIR_KEYS;
opt.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.import_options = (IMPORT_REPAIR_KEYS
- | IMPORT_REPAIR_PKS_SUBKEY_BUG);
+ | IMPORT_REPAIR_PKS_SUBKEY_BUG
+ | IMPORT_SELF_SIGS_ONLY
+ | IMPORT_CLEAN);
opt.keyserver_options.export_options = EXPORT_ATTRIBUTES;
opt.keyserver_options.options = KEYSERVER_HONOR_PKA_RECORD;
opt.verify_options = (LIST_SHOW_UID_VALIDITY
@@ -2611,6 +2616,7 @@ main (int argc, char **argv)
#endif /* ENABLE_CARD_SUPPORT*/
case aListKeys:
case aLocateKeys:
+ case aLocateExtKeys:
case aListSigs:
case aExportSecret:
case aExportSecretSub:
@@ -4511,7 +4517,7 @@ main (int argc, char **argv)
sl = NULL;
for( ; argc; argc--, argv++ )
add_to_strlist2( &sl, *argv, utf8_strings );
- public_key_list (ctrl, sl, 0);
+ public_key_list (ctrl, sl, 0, 0);
free_strlist(sl);
break;
case aListSecretKeys:
@@ -4522,10 +4528,11 @@ main (int argc, char **argv)
free_strlist(sl);
break;
case aLocateKeys:
+ case aLocateExtKeys:
sl = NULL;
for (; argc; argc--, argv++)
add_to_strlist2( &sl, *argv, utf8_strings );
- public_key_list (ctrl, sl, 1);
+ public_key_list (ctrl, sl, 1, cmd == aLocateExtKeys);
free_strlist (sl);
break;
@@ -5223,12 +5230,14 @@ g10_exit( int rc )
{
keydb_dump_stats ();
sig_check_dump_stats ();
+ objcache_dump_stats ();
gcry_control (GCRYCTL_DUMP_MEMORY_STATS);
gcry_control (GCRYCTL_DUMP_RANDOM_STATS);
}
if (opt.debug)
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
+ gnupg_block_all_signals ();
emergency_cleanup ();
rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0;
diff --git a/g10/gpgcompose.c b/g10/gpgcompose.c
index e882fa8e3..7b7e1dc9a 100644
--- a/g10/gpgcompose.c
+++ b/g10/gpgcompose.c
@@ -1200,7 +1200,8 @@ sig_revocation_key (const char *option, int argc, char *argv[], void *cookie)
option, argv[0]);
pk.req_usage = PUBKEY_USAGE_SIG;
- err = get_pubkey_byname (NULL, NULL, &pk, argv[1], NULL, NULL, 1, 1);
+ err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL,
+ NULL, &pk, argv[1], NULL, NULL, 1);
if (err)
log_fatal ("looking up key %s: %s\n", argv[1], gpg_strerror (err));
@@ -1799,12 +1800,19 @@ signature (const char *option, int argc, char *argv[], void *cookie)
keyid_copy (si.issuer_pk->keyid, pk_keyid (pripk));
}
+ /* The reuse of core gpg stuff by this tool is questionable when it
+ * requires adding extra code to the actual gpg code. It does not
+ * make sense to pass an extra parameter and in particular not given
+ * that gpg already has opt.cert_digest_algo to override it. */
+ if (si.digest_algo)
+ log_info ("note: digest algo can't be passed to make_keysig_packet\n");
+
/* Changing the issuer's key id is fragile. Check to make sure
make_keysig_packet didn't recompute the keyid. */
keyid_copy (keyid, si.issuer_pk->keyid);
err = make_keysig_packet (global_ctrl,
&sig, si.pk, si.uid, si.sk, si.issuer_pk,
- si.class, si.digest_algo,
+ si.class,
si.timestamp, si.expiration,
mksubpkt_callback, &si, NULL);
log_assert (keyid_cmp (keyid, si.issuer_pk->keyid) == 0);
@@ -2450,7 +2458,8 @@ pk_esk (const char *option, int argc, char *argv[], void *cookie)
memset (&pk, 0, sizeof (pk));
pk.req_usage = PUBKEY_USAGE_ENC;
- err = get_pubkey_byname (NULL, NULL, &pk, pi.keyid, NULL, NULL, 1, 1);
+ err = get_pubkey_byname (NULL, GET_PUBKEY_NO_AKL,
+ NULL, &pk, pi.keyid, NULL, NULL, 1);
if (err)
log_fatal ("%s: looking up key %s: %s\n",
option, pi.keyid, gpg_strerror (err));
diff --git a/g10/import.c b/g10/import.c
index c2a1dd033..c32dbf059 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -102,7 +102,7 @@ static int import (ctrl_t ctrl,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
import_screener_t screener, void *screener_arg,
int origin, const char *url);
-static int read_block (IOBUF a, int with_meta,
+static int read_block (IOBUF a, unsigned int options,
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys);
static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
static gpg_error_t import_one (ctrl_t ctrl,
@@ -129,6 +129,7 @@ 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 void remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid);
static int merge_blocks (ctrl_t ctrl, unsigned int options,
kbnode_t keyblock_orig,
kbnode_t keyblock, u32 *keyid,
@@ -190,7 +191,10 @@ parse_import_options(char *str,unsigned int *options,int noisy)
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")},
+ N_("do not import user id or attribute packets")},
+
+ {"self-sigs-only", IMPORT_SELF_SIGS_ONLY, NULL,
+ N_("ignore key-signatures which are not self-signatures")},
{"import-export", IMPORT_EXPORT, NULL,
N_("run import filters and export key immediately")},
@@ -589,8 +593,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
release_armor_context (afx);
}
- while (!(rc = read_block (inp, !!(options & IMPORT_RESTORE),
- &pending_pkt, &keyblock, &v3keys)))
+ while (!(rc = read_block (inp, options, &pending_pkt, &keyblock, &v3keys)))
{
stats->v3keys += v3keys;
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
@@ -669,6 +672,18 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
if (!(++stats->count % 100) && !opt.quiet)
log_info (_("%lu keys processed so far\n"), stats->count );
+
+ if (origin == KEYORG_WKD && stats->count >= 5)
+ {
+ /* We limit the number of keys _received_ from the WKD to 5.
+ * In fact there should be only one key but some sites want
+ * to store a few expired keys there also. gpg's key
+ * selection will later figure out which key to use. Note
+ * that for WKD we always return the fingerprint of the
+ * first imported key. */
+ log_info ("import from WKD stopped after %d keys\n", 5);
+ break;
+ }
}
stats->v3keys += v3keys;
if (rc == -1)
@@ -677,6 +692,13 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (rc));
release_kbnode (secattic);
+
+ /* When read_block loop was stopped by error, we have PENDING_PKT left. */
+ if (pending_pkt)
+ {
+ free_packet (pending_pkt, NULL);
+ xfree (pending_pkt);
+ }
return rc;
}
@@ -826,31 +848,39 @@ valid_keyblock_packet (int pkttype)
}
-/****************
- * Read the next keyblock from stream A.
- * Meta data (ring trust packets) are only considered of WITH_META is set.
- * PENDING_PKT should be initialized to NULL and not changed by the caller.
- * Return: 0 = okay, -1 no more blocks or another errorcode.
- * The int at R_V3KEY counts the number of unsupported v3
- * keyblocks.
+/* Read the next keyblock from stream A. Meta data (ring trust
+ * packets) are only considered if OPTIONS has the IMPORT_RESTORE flag
+ * set. PENDING_PKT should be initialized to NULL and not changed by
+ * the caller.
+ *
+ * Returns 0 for okay, -1 no more blocks, or any other errorcode. The
+ * integer at R_V3KEY counts the number of unsupported v3 keyblocks.
*/
static int
-read_block( IOBUF a, int with_meta,
+read_block( IOBUF a, unsigned int options,
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
{
int rc;
struct parse_packet_ctx_s parsectx;
PACKET *pkt;
kbnode_t root = NULL;
+ kbnode_t lastnode = NULL;
int in_cert, in_v3key, skip_sigs;
+ u32 keyid[2];
+ int got_keyid = 0;
+ unsigned int dropped_nonselfsigs = 0;
*r_v3keys = 0;
if (*pending_pkt)
{
- root = new_kbnode( *pending_pkt );
+ root = lastnode = new_kbnode( *pending_pkt );
*pending_pkt = NULL;
+ log_assert (root->pkt->pkttype == PKT_PUBLIC_KEY
+ || root->pkt->pkttype == PKT_SECRET_KEY);
in_cert = 1;
+ keyid_from_pk (root->pkt->pkt.public_key, keyid);
+ got_keyid = 1;
}
else
in_cert = 0;
@@ -858,7 +888,7 @@ read_block( IOBUF a, int with_meta,
pkt = xmalloc (sizeof *pkt);
init_packet (pkt);
init_parse_packet (&parsectx, a);
- if (!with_meta)
+ if (!(options & IMPORT_RESTORE))
parsectx.skip_meta = 1;
in_v3key = 0;
skip_sigs = 0;
@@ -965,24 +995,59 @@ read_block( IOBUF a, int with_meta,
init_packet(pkt);
break;
+ case PKT_SIGNATURE:
+ if (!in_cert)
+ goto x_default;
+ if (!(options & IMPORT_SELF_SIGS_ONLY))
+ goto x_default;
+ log_assert (got_keyid);
+ if (pkt->pkt.signature->keyid[0] == keyid[0]
+ && pkt->pkt.signature->keyid[1] == keyid[1])
+ { /* This is likely a self-signature. We import this one.
+ * Eventually we should use the ISSUER_FPR to compare
+ * self-signatures, but that will work only for v5 keys
+ * which are currently not even deployed.
+ * Note that we do not do any crypto verify here because
+ * that would defeat this very mitigation of DoS by
+ * importing a key with a huge amount of faked
+ * key-signatures. A verification will be done later in
+ * the processing anyway. Here we want a cheap an early
+ * way to drop non-self-signatures. */
+ goto x_default;
+ }
+ /* Skip this signature. */
+ dropped_nonselfsigs++;
+ free_packet (pkt, &parsectx);
+ init_packet(pkt);
+ break;
+
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
- if (in_cert ) /* Store this packet. */
+ if (!got_keyid)
+ {
+ keyid_from_pk (pkt->pkt.public_key, keyid);
+ got_keyid = 1;
+ }
+ if (in_cert) /* Store this packet. */
{
*pending_pkt = pkt;
pkt = NULL;
goto ready;
}
in_cert = 1;
- /* fall through */
+ goto x_default;
+
default:
x_default:
if (in_cert && valid_keyblock_packet (pkt->pkttype))
{
if (!root )
- root = new_kbnode (pkt);
+ root = lastnode = new_kbnode (pkt);
else
- add_kbnode (root, new_kbnode (pkt));
+ {
+ lastnode->next = new_kbnode (pkt);
+ lastnode = lastnode->next;
+ }
pkt = xmalloc (sizeof *pkt);
}
else
@@ -1003,6 +1068,10 @@ read_block( IOBUF a, int with_meta,
free_packet (pkt, &parsectx);
deinit_parse_packet (&parsectx);
xfree( pkt );
+ if (!rc && dropped_nonselfsigs && opt.verbose)
+ log_info ("key %s: number of dropped non-self-signatures: %u\n",
+ keystr (keyid), dropped_nonselfsigs);
+
return rc;
}
@@ -1729,12 +1798,12 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url)
* has valid parts.
*/
static gpg_error_t
-import_one (ctrl_t ctrl,
- kbnode_t keyblock, struct import_stats_s *stats,
- 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 *r_valid)
+import_one_real (ctrl_t ctrl,
+ kbnode_t keyblock, struct import_stats_s *stats,
+ 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 *r_valid)
{
gpg_error_t err = 0;
PKT_public_key *pk;
@@ -1817,6 +1886,13 @@ import_one (ctrl_t ctrl,
return 0;
}
+ /* Remove all non-self-sigs if requested. Noe that this is a NOP if
+ * that option has been globally set but we may also be called
+ * latter with the already parsed keyblock and a locally changed
+ * option. This is why we need to remove them here as well. */
+ if ((options & IMPORT_SELF_SIGS_ONLY))
+ remove_all_non_self_sigs (&keyblock, keyid);
+
/* Remove or collapse the user ids. */
if ((options & IMPORT_DROP_UIDS))
remove_all_uids (&keyblock);
@@ -2026,22 +2102,25 @@ import_one (ctrl_t ctrl,
hd = NULL;
/* We are ready. */
- if (!opt.quiet && !silent)
+ if (!err && !opt.quiet && !silent)
{
- char *p = get_user_id_byfpr_native (ctrl, fpr2);
+ char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
log_info (_("key %s: public key \"%s\" imported\n"),
keystr(keyid), p);
xfree(p);
}
- if (is_status_enabled())
+ if (!err && is_status_enabled())
{
char *us = get_long_user_id_string (ctrl, keyid);
write_status_text( STATUS_IMPORTED, us );
xfree(us);
print_import_ok (pk, 1);
}
- stats->imported++;
- new_key = 1;
+ if (!err)
+ {
+ stats->imported++;
+ new_key = 1;
+ }
}
else /* Key already exists - merge. */
{
@@ -2111,10 +2190,12 @@ import_one (ctrl_t ctrl,
keydb_release (hd);
hd = NULL;
- /* We are ready. */
- if (!opt.quiet && !silent)
+ /* We are ready. Print and update stats if we got no error.
+ * An error here comes from writing the keyblock and thus
+ * very likely means that no update happened. */
+ if (!err && !opt.quiet && !silent)
{
- char *p = get_user_id_byfpr_native (ctrl, fpr2);
+ char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
if (n_uids == 1 )
log_info( _("key %s: \"%s\" 1 new user ID\n"),
keystr(keyid),p);
@@ -2148,14 +2229,17 @@ import_one (ctrl_t ctrl,
xfree(p);
}
- stats->n_uids +=n_uids;
- stats->n_sigs +=n_sigs;
- stats->n_subk +=n_subk;
- stats->n_sigs_cleaned +=n_sigs_cleaned;
- stats->n_uids_cleaned +=n_uids_cleaned;
-
- if (is_status_enabled () && !silent)
- print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
+ if (!err)
+ {
+ stats->n_uids +=n_uids;
+ stats->n_sigs +=n_sigs;
+ stats->n_subk +=n_subk;
+ stats->n_sigs_cleaned +=n_sigs_cleaned;
+ stats->n_uids_cleaned +=n_uids_cleaned;
+
+ if (is_status_enabled () && !silent)
+ print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
+ }
}
else
{
@@ -2175,7 +2259,7 @@ import_one (ctrl_t ctrl,
if (!opt.quiet && !silent)
{
- char *p = get_user_id_byfpr_native (ctrl, fpr2);
+ char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
xfree(p);
}
@@ -2203,14 +2287,19 @@ import_one (ctrl_t ctrl,
fingerprint of the key in all cases. */
if (fpr)
{
- xfree (*fpr);
/* Note that we need to compare against 0 here because
COUNT gets only incremented after returning from this
function. */
if (!stats->count)
- *fpr = fingerprint_from_pk (pk, NULL, fpr_len);
- else
- *fpr = NULL;
+ {
+ xfree (*fpr);
+ *fpr = fingerprint_from_pk (pk, NULL, fpr_len);
+ }
+ else if (origin != KEYORG_WKD)
+ {
+ xfree (*fpr);
+ *fpr = NULL;
+ }
}
}
@@ -2237,6 +2326,41 @@ import_one (ctrl_t ctrl,
}
+/* Wrapper around import_one_real to retry the import in some cases. */
+static gpg_error_t
+import_one (ctrl_t ctrl,
+ kbnode_t keyblock, struct import_stats_s *stats,
+ 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 *r_valid)
+{
+ gpg_error_t err;
+
+ err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
+ from_sk, silent, screener, screener_arg,
+ origin, url, r_valid);
+ if (gpg_err_code (err) == GPG_ERR_TOO_LARGE
+ && gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX
+ && ((options & (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN))
+ != (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN)))
+ {
+ /* We hit the maximum image length. Ask the wrapper to do
+ * everything again but this time with some extra options. */
+ u32 keyid[2];
+
+ keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
+ log_info ("key %s: keyblock too large, retrying with self-sigs-only\n",
+ keystr (keyid));
+ options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN;
+ err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
+ from_sk, silent, screener, screener_arg,
+ origin, url, r_valid);
+ }
+ return err;
+}
+
+
/* 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
@@ -2544,6 +2668,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
kbnode_t pub_keyblock = NULL;
kbnode_t ctx = NULL;
kbnode_t secnode, pubnode;
+ kbnode_t lastnode = NULL;
unsigned int tag = 0;
/* Set a tag to all nodes. */
@@ -2583,9 +2708,12 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
pubnode->tag = secnode->tag;
if (!pub_keyblock)
- pub_keyblock = pubnode;
+ pub_keyblock = lastnode = pubnode;
else
- add_kbnode (pub_keyblock, pubnode);
+ {
+ lastnode->next = pubnode;
+ lastnode = pubnode;
+ }
}
return pub_keyblock;
@@ -2915,7 +3043,7 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
/* 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. */
+ * surprising and clutters our private-keys-v1.d. */
err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic);
if (err)
goto leave;
@@ -3764,6 +3892,38 @@ remove_all_uids (kbnode_t *keyblock)
}
+/* Delete all non-self-sigs from KEYBLOCK.
+ * Returns: True if the keyblock has changed. */
+static void
+remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid)
+{
+ kbnode_t node;
+ unsigned int dropped = 0;
+
+ for (node = *keyblock; node; node = node->next)
+ {
+ if (is_deleted_kbnode (node))
+ continue;
+
+ if (node->pkt->pkttype != PKT_SIGNATURE)
+ continue;
+
+ if (node->pkt->pkt.signature->keyid[0] == keyid[0]
+ && node->pkt->pkt.signature->keyid[1] == keyid[1])
+ continue;
+ delete_kbnode (node);
+ dropped++;
+ }
+
+ if (dropped)
+ commit_kbnode (keyblock);
+
+ if (dropped && opt.verbose)
+ log_info ("key %s: number of dropped non-self-signatures: %u\n",
+ keystr (keyid), dropped);
+}
+
+
/*
* It may happen that the imported keyblock has duplicated user IDs.
* We check this here and collapse those user IDs together with their
diff --git a/g10/keydb.c b/g10/keydb.c
index 8c067e1df..a7691bbe2 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -1,6 +1,6 @@
/* keydb.c - key database dispatcher
* Copyright (C) 2001-2013 Free Software Foundation, Inc.
- * Coyrright (C) 2001-2015 Werner Koch
+ * Copyright (C) 2001-2015 Werner Koch
*
* This file is part of GnuPG.
*
@@ -1076,7 +1076,7 @@ lock_all (KEYDB_HANDLE hd)
rc = keyring_lock (hd->active[i].u.kr, 1);
break;
case KEYDB_RESOURCE_TYPE_KEYBOX:
- rc = keybox_lock (hd->active[i].u.kb, 1);
+ rc = keybox_lock (hd->active[i].u.kb, 1, -1);
break;
}
}
@@ -1094,7 +1094,7 @@ lock_all (KEYDB_HANDLE hd)
keyring_lock (hd->active[i].u.kr, 0);
break;
case KEYDB_RESOURCE_TYPE_KEYBOX:
- keybox_lock (hd->active[i].u.kb, 0);
+ keybox_lock (hd->active[i].u.kb, 0, 0);
break;
}
}
@@ -1127,7 +1127,7 @@ unlock_all (KEYDB_HANDLE hd)
keyring_lock (hd->active[i].u.kr, 0);
break;
case KEYDB_RESOURCE_TYPE_KEYBOX:
- keybox_lock (hd->active[i].u.kb, 0);
+ keybox_lock (hd->active[i].u.kb, 0, 0);
break;
}
}
@@ -1242,8 +1242,15 @@ parse_keyblock_image (iobuf_t iobuf, int pk_no, int uid_no,
}
if (err)
{
+ es_fflush (es_stdout);
log_error ("parse_keyblock_image: read error: %s\n",
gpg_strerror (err));
+ if (gpg_err_code (err) == GPG_ERR_INV_PACKET)
+ {
+ free_packet (pkt, &parsectx);
+ init_packet (pkt);
+ continue;
+ }
err = gpg_error (GPG_ERR_INV_KEYRING);
break;
}
diff --git a/g10/keydb.h b/g10/keydb.h
index 7cdfe9bbf..6ad8dce4c 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -345,16 +345,25 @@ typedef struct pubkey_s *pubkey_t;
/* Free a list of public keys. */
void pubkeys_free (pubkey_t keys);
+
+/* Mode flags for get_pubkey_byname. */
+enum get_pubkey_modes
+ {
+ GET_PUBKEY_NORMAL = 0,
+ GET_PUBKEY_NO_AKL = 1,
+ GET_PUBKEY_NO_LOCAL = 2
+ };
+
/* Find a public key identified by NAME. */
-int get_pubkey_byname (ctrl_t ctrl,
+int get_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name,
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
- int include_unusable, int no_akl );
+ int include_unusable);
/* Likewise, but only return the best match if NAME resembles a mail
* address. */
-gpg_error_t get_best_pubkey_byname (ctrl_t ctrl,
+gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
GETKEY_CTX *retctx, PKT_public_key *pk,
const char *name, KBNODE *ret_keyblock,
int include_unusable);
@@ -436,8 +445,7 @@ char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);
char *get_user_id_native (ctrl_t ctrl, u32 *keyid);
-char *get_user_id_byfpr (ctrl_t ctrl, const byte *fpr, size_t *rn);
-char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr);
+char *get_user_id_byfpr_native (ctrl_t ctrl, const byte *fpr, size_t fprlen);
void release_akl(void);
int parse_auto_key_locate(const char *options);
diff --git a/g10/keyedit.c b/g10/keyedit.c
index c28a565b1..1bf5de9b2 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1012,7 +1012,8 @@ sign_uids (ctrl_t ctrl, estream_t fp,
node->pkt->pkt.user_id,
NULL,
pk,
- 0x13, 0, 0, 0,
+ 0x13,
+ 0, 0,
keygen_add_std_prefs, primary_pk,
NULL);
else
@@ -1020,7 +1021,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
node->pkt->pkt.user_id,
NULL,
pk,
- class, 0,
+ class,
timestamp, duration,
sign_mk_attrib, &attrib,
NULL);
@@ -1437,7 +1438,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
#endif
/* Get the public key */
- err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1);
+ err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, NULL, username, &keyblock, &kdbhd, 1);
if (err)
{
log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err));
@@ -2570,7 +2572,8 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr,
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
- err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1);
+ err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, NULL, fpr, &keyblock, &kdbhd, 1);
if (err)
{
log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err));
@@ -3991,7 +3994,7 @@ menu_adduid (ctrl_t ctrl, kbnode_t pub_keyblock,
return 0;
}
- err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0, 0,
+ err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x13, 0, 0,
keygen_add_std_prefs, pk, NULL);
if (err)
{
@@ -4289,7 +4292,8 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
primary keys only, but some casual testing shows that PGP and
GnuPG both can handle a designated revocation from a subkey. */
revoker_pk->req_usage = PUBKEY_USAGE_CERT;
- rc = get_pubkey_byname (ctrl, NULL, revoker_pk, answer, NULL, NULL, 1, 1);
+ rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, revoker_pk, answer, NULL, NULL, 1);
if (rc)
{
log_error (_("key \"%s\" not found: %s\n"), answer,
@@ -4355,7 +4359,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
continue;
}
- print_pubkey_info (ctrl, NULL, revoker_pk);
+ print_key_info (ctrl, NULL, 0, revoker_pk, 0);
print_fingerprint (ctrl, NULL, revoker_pk, 2);
tty_printf ("\n");
@@ -4374,7 +4378,7 @@ menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive)
break;
}
- rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0,
+ rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk, 0x1F, 0, 0,
keygen_add_revkey, &revkey, NULL);
if (rc)
{
@@ -5898,7 +5902,7 @@ reloop: /* (must use this, because we are modifying the list) */
}
rc = make_keysig_packet (ctrl, &sig, primary_pk,
unode->pkt->pkt.user_id,
- NULL, signerkey, 0x30, 0, 0, 0,
+ NULL, signerkey, 0x30, 0, 0,
sign_mk_attrib, &attrib, NULL);
free_public_key (signerkey);
if (rc)
@@ -5977,11 +5981,11 @@ core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
memset (&attrib, 0, sizeof attrib);
/* should not need to cast away const here; but
revocation_reason_build_cb needs to take a non-const
- void* in order to meet the function signtuare for the
+ void* in order to meet the function signutare for the
mksubpkt argument to make_keysig_packet */
attrib.reason = (struct revocation_reason_info *)reason;
- rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30, 0,
+ rc = make_keysig_packet (ctrl, &sig, pk, uid, NULL, pk, 0x30,
timestamp, 0,
sign_mk_attrib, &attrib, NULL);
if (rc)
@@ -6111,7 +6115,7 @@ menu_revkey (ctrl_t ctrl, kbnode_t pub_keyblock)
return 0;
rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk,
- 0x20, 0, 0, 0,
+ 0x20, 0, 0,
revocation_reason_build_cb, reason, NULL);
if (rc)
{
@@ -6173,7 +6177,7 @@ menu_revsubkey (ctrl_t ctrl, kbnode_t pub_keyblock)
node->flag &= ~NODFLG_SELKEY;
rc = make_keysig_packet (ctrl, &sig, mainpk, NULL, subpk, mainpk,
- 0x28, 0, 0, 0, sign_mk_attrib, &attrib,
+ 0x28, 0, 0, sign_mk_attrib, &attrib,
NULL);
if (rc)
{
diff --git a/g10/keygen.c b/g10/keygen.c
index 64fefd231..d9037d29d 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -227,18 +227,22 @@ print_status_key_not_created (const char *handle)
-static void
-write_uid( KBNODE root, const char *s )
+static gpg_error_t
+write_uid (kbnode_t root, const char *s)
{
- PACKET *pkt = xmalloc_clear(sizeof *pkt );
- size_t n = strlen(s);
-
- pkt->pkttype = PKT_USER_ID;
- pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
- pkt->pkt.user_id->len = n;
- pkt->pkt.user_id->ref = 1;
- strcpy(pkt->pkt.user_id->name, s);
- add_kbnode( root, new_kbnode( pkt ) );
+ PACKET *pkt = xmalloc_clear (sizeof *pkt);
+ size_t n = strlen (s);
+
+ if (n > MAX_UID_PACKET_LENGTH - 10)
+ return gpg_error (GPG_ERR_INV_USER_ID);
+
+ pkt->pkttype = PKT_USER_ID;
+ pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
+ pkt->pkt.user_id->len = n;
+ pkt->pkt.user_id->ref = 1;
+ strcpy (pkt->pkt.user_id->name, s);
+ add_kbnode (root, new_kbnode (pkt));
+ return 0;
}
static void
@@ -1022,7 +1026,7 @@ make_backsig (ctrl_t ctrl, PKT_signature *sig, PKT_public_key *pk,
cache_public_key (sub_pk);
err = make_keysig_packet (ctrl, &backsig, pk, NULL, sub_pk, sub_psk, 0x19,
- 0, timestamp, 0, NULL, NULL, cache_nonce);
+ timestamp, 0, NULL, NULL, cache_nonce);
if (err)
log_error ("make_keysig_packet failed for backsig: %s\n",
gpg_strerror (err));
@@ -1130,7 +1134,7 @@ write_direct_sig (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk,
/* Make the signature. */
err = make_keysig_packet (ctrl, &sig, pk, NULL,NULL, psk, 0x1F,
- 0, timestamp, 0,
+ timestamp, 0,
keygen_add_revkey, revkey, cache_nonce);
if (err)
{
@@ -1185,7 +1189,7 @@ write_selfsigs (ctrl_t ctrl, kbnode_t root, PKT_public_key *psk,
/* Make the signature. */
err = make_keysig_packet (ctrl, &sig, pk, uid, NULL, psk, 0x13,
- 0, timestamp, 0,
+ timestamp, 0,
keygen_add_std_prefs, pk, cache_nonce);
if (err)
{
@@ -1245,7 +1249,7 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
oduap.usage = use;
oduap.pk = sub_pk;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
- 0, timestamp, 0,
+ timestamp, 0,
keygen_add_key_flags_and_expire, &oduap,
cache_nonce);
if (err)
@@ -1881,24 +1885,26 @@ print_key_flags(int flags)
/* Ask for the key flags and return them. CURRENT gives the current
- * usage which should normally be given as 0. */
+ * usage which should normally be given as 0. MASK gives the allowed
+ * flags. */
unsigned int
-ask_key_flags (int algo, int subkey, unsigned int current)
+ask_key_flags_with_mask (int algo, int subkey, unsigned int current,
+ unsigned int mask)
{
/* TRANSLATORS: Please use only plain ASCII characters for the
- translation. If this is not possible use single digits. The
- string needs to 8 bytes long. Here is a description of the
- functions:
-
- s = Toggle signing capability
- e = Toggle encryption capability
- a = Toggle authentication capability
- q = Finish
- */
+ * translation. If this is not possible use single digits. The
+ * string needs to 8 bytes long. Here is a description of the
+ * functions:
+ *
+ * s = Toggle signing capability
+ * e = Toggle encryption capability
+ * a = Toggle authentication capability
+ * q = Finish
+ */
const char *togglers = _("SsEeAaQq");
char *answer = NULL;
const char *s;
- unsigned int possible = openpgp_pk_algo_usage(algo);
+ unsigned int possible;
if ( strlen(togglers) != 8 )
{
@@ -1907,22 +1913,26 @@ ask_key_flags (int algo, int subkey, unsigned int current)
togglers = "11223300";
}
- /* Only primary keys may certify. */
- if(subkey)
- possible&=~PUBKEY_USAGE_CERT;
+ /* Mask the possible usage flags. This is for example used for a
+ * card based key. */
+ possible = (openpgp_pk_algo_usage (algo) & mask);
- /* Preload the current set with the possible set, minus
- authentication if CURRENT has been given as 0. If CURRENT has
- been has non-zero we mask with all possible usages. */
+ /* However, only primary keys may certify. */
+ if (subkey)
+ possible &= ~PUBKEY_USAGE_CERT;
+
+ /* Preload the current set with the possible set, without
+ * authentication if CURRENT is 0. If CURRENT is non-zero we mask
+ * with all possible usages. */
if (current)
current &= possible;
else
current = (possible&~PUBKEY_USAGE_AUTH);
- for(;;)
+ for (;;)
{
tty_printf("\n");
- tty_printf(_("Possible actions for a %s key: "),
+ tty_printf(_("Possible actions for this %s key: "),
(algo == PUBKEY_ALGO_ECDSA
|| algo == PUBKEY_ALGO_EDDSA)
? "ECDSA/EdDSA" : openpgp_pk_algo_name (algo));
@@ -2009,6 +2019,13 @@ ask_key_flags (int algo, int subkey, unsigned int current)
}
+unsigned int
+ask_key_flags (int algo, int subkey, unsigned int current)
+{
+ return ask_key_flags_with_mask (algo, subkey, current, ~0);
+}
+
+
/* Check whether we have a key for the key with HEXGRIP. Returns 0 if
there is no such key or the OpenPGP algo number for the key. */
static int
@@ -2047,10 +2064,12 @@ static int
ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
char **r_keygrip)
{
+ gpg_error_t err;
char *keygrip = NULL;
char *answer = NULL;
int algo;
int dummy_algo;
+ char *p;
if (!r_subkey_algo)
r_subkey_algo = &dummy_algo;
@@ -2101,6 +2120,8 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
if (opt.expert && r_keygrip)
tty_printf (_(" (%d) Existing key\n"), 13 );
+ if (r_keygrip)
+ tty_printf (_(" (%d) Existing key from card\n"), 14 );
for (;;)
{
@@ -2221,9 +2242,130 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
*r_usage = ask_key_flags (algo, addmode, 0);
break;
}
+ else if ((algo == 14 || !strcmp (answer, "cardkey")) && r_keygrip)
+ {
+ char *serialno;
+ strlist_t keypairlist, sl;
+ int count, selection;
+
+ err = agent_scd_serialno (&serialno, NULL);
+ if (err)
+ {
+ tty_printf (_("error reading the card: %s\n"),
+ gpg_strerror (err));
+ goto ask_again;
+ }
+ tty_printf (_("Serial number of the card: %s\n"), serialno);
+ xfree (serialno);
+
+ err = agent_scd_keypairinfo (ctrl, NULL, &keypairlist);
+ if (err)
+ {
+ tty_printf (_("error reading the card: %s\n"),
+ gpg_strerror (err));
+ goto ask_again;
+ }
+
+ do
+ {
+ tty_printf (_("Available keys:\n"));
+ for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
+ {
+ gcry_sexp_t s_pkey;
+ char *algostr = NULL;
+ enum gcry_pk_algos algoid = 0;
+ const char *keyref;
+ int any = 0;
+
+ keyref = strchr (sl->d, ' ');
+ if (keyref)
+ {
+ keyref++;
+ if (!agent_scd_readkey (keyref, &s_pkey))
+ {
+ algostr = pubkey_algo_string (s_pkey, &algoid);
+ gcry_sexp_release (s_pkey);
+ }
+ }
+ /* We use the flags also encode the algo for use
+ * below. We need to tweak the algo in case
+ * GCRY_PK_ECC is returned becuase pubkey_algo_string
+ * is not aware of the OpenPGP algo mapping.
+ * FIXME: This is an ugly hack. */
+ sl->flags &= 0xff;
+ if (algoid == GCRY_PK_ECC
+ && algostr && !strncmp (algostr, "nistp", 5)
+ && !(sl->flags & GCRY_PK_USAGE_ENCR))
+ sl->flags |= (PUBKEY_ALGO_ECDSA << 8);
+ else
+ sl->flags |= (map_pk_gcry_to_openpgp (algoid) << 8);
+
+ tty_printf (" (%d) %s %s", count, sl->d, algostr);
+ if ((sl->flags & GCRY_PK_USAGE_CERT))
+ {
+ tty_printf ("%scert", any?",":" (");
+ any = 1;
+ }
+ if ((sl->flags & GCRY_PK_USAGE_SIGN))
+ {
+ tty_printf ("%ssign", any?",":" (");
+ any = 1;
+ }
+ if ((sl->flags & GCRY_PK_USAGE_AUTH))
+ {
+ tty_printf ("%sauth", any?",":" (");
+ any = 1;
+ }
+ if ((sl->flags & GCRY_PK_USAGE_ENCR))
+ {
+ tty_printf ("%sencr", any?",":" (");
+ any = 1;
+ }
+ tty_printf ("%s\n", any?")":"");
+ xfree (algostr);
+ }
+
+ xfree (answer);
+ answer = cpr_get ("keygen.cardkey", _("Your selection? "));
+ cpr_kill_prompt ();
+ trim_spaces (answer);
+ selection = atoi (answer);
+ }
+ while (!(selection > 0 && selection < count));
+
+ for (count=1,sl=keypairlist; sl; sl = sl->next, count++)
+ if (count == selection)
+ break;
+ if (!sl)
+ {
+ /* Just in case COUNT is zero (no keys). */
+ free_strlist (keypairlist);
+ goto ask_again;
+ }
+
+ xfree (keygrip);
+ keygrip = xstrdup (sl->d);
+ if ((p = strchr (keygrip, ' ')))
+ *p = 0;
+ algo = (sl->flags >>8);
+ if (opt.expert)
+ *r_usage = ask_key_flags_with_mask (algo, addmode,
+ (sl->flags & 0xff),
+ (sl->flags & 0xff));
+ else
+ {
+ *r_usage = (sl->flags & 0xff);
+ if (addmode)
+ *r_usage &= ~GCRY_PK_USAGE_CERT;
+ }
+ free_strlist (keypairlist);
+ break;
+ }
else
tty_printf (_("Invalid selection.\n"));
+ ask_again:
+ ;
}
xfree(answer);
@@ -2507,14 +2649,25 @@ ask_curve (int *algo, int *subkey_algo, const char *current)
else
{
/* If the user selected a signing algorithm and Curve25519
- we need to set the algo to EdDSA and update the curve name. */
- if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
- && curves[idx].eddsa_curve)
+ we need to set the algo to EdDSA and update the curve name.
+ If switching away from EdDSA, we need to set the algo back
+ to ECDSA. */
+ if (*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA)
{
- if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
- *subkey_algo = PUBKEY_ALGO_EDDSA;
- *algo = PUBKEY_ALGO_EDDSA;
- result = curves[idx].eddsa_curve;
+ if (curves[idx].eddsa_curve)
+ {
+ if (subkey_algo && *subkey_algo == PUBKEY_ALGO_ECDSA)
+ *subkey_algo = PUBKEY_ALGO_EDDSA;
+ *algo = PUBKEY_ALGO_EDDSA;
+ result = curves[idx].eddsa_curve;
+ }
+ else
+ {
+ if (subkey_algo && *subkey_algo == PUBKEY_ALGO_EDDSA)
+ *subkey_algo = PUBKEY_ALGO_ECDSA;
+ *algo = PUBKEY_ALGO_ECDSA;
+ result = curves[idx].name;
+ }
}
else
result = curves[idx].name;
@@ -4943,10 +5096,11 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
if (!err && (s = get_parameter_value (para, pUSERID)))
{
- write_uid (pub_root, s );
- err = write_selfsigs (ctrl, pub_root, pri_psk,
- get_parameter_uint (para, pKEYUSAGE), timestamp,
- cache_nonce);
+ err = write_uid (pub_root, s );
+ if (!err)
+ err = write_selfsigs (ctrl, pub_root, pri_psk,
+ get_parameter_uint (para, pKEYUSAGE), timestamp,
+ cache_nonce);
}
/* Write the auth key to the card before the encryption key. This
diff --git a/g10/keyid.c b/g10/keyid.c
index aa77b47e2..7605cb386 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -68,7 +68,7 @@ pubkey_letter( int algo )
}
/* Return a string describing the public key algorithm and the
- keysize. For elliptic curves the functions prints the name of the
+ keysize. For elliptic curves the function prints the name of the
curve because the keysize is a property of the curve. The string
is copied to the supplied buffer up a length of BUFSIZE-1.
Examples for the output are:
@@ -253,20 +253,6 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
}
-static gcry_md_hd_t
-do_fingerprint_md( PKT_public_key *pk )
-{
- gcry_md_hd_t md;
-
- if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
- BUG ();
- hash_public_key (md,pk);
- gcry_md_final (md);
-
- return md;
-}
-
-
/* fixme: Check whether we can replace this function or if not
describe why we need it. */
u32
@@ -520,6 +506,37 @@ keystr_from_desc(KEYDB_SEARCH_DESC *desc)
}
+/* Compute the fingerprint and keyid and store it in PK. */
+static void
+compute_fingerprint (PKT_public_key *pk)
+{
+ const byte *dp;
+ gcry_md_hd_t md;
+ size_t len;
+
+ if (gcry_md_open (&md, pk->version == 5 ? GCRY_MD_SHA256 : GCRY_MD_SHA1, 0))
+ BUG ();
+ hash_public_key (md, pk);
+ gcry_md_final (md);
+ dp = gcry_md_read (md, 0);
+ len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
+ log_assert (len <= MAX_FINGERPRINT_LEN);
+ memcpy (pk->fpr, dp, len);
+ pk->fprlen = len;
+ if (pk->version == 5)
+ {
+ pk->keyid[0] = buf32_to_u32 (dp);
+ pk->keyid[1] = buf32_to_u32 (dp+4);
+ }
+ else
+ {
+ pk->keyid[0] = buf32_to_u32 (dp+12);
+ pk->keyid[1] = buf32_to_u32 (dp+16);
+ }
+ gcry_md_close( md);
+}
+
+
/*
* Get the keyid from the public key PK and store it at KEYID unless
* this is NULL. Returns the 32 bit short keyid.
@@ -532,37 +549,11 @@ keyid_from_pk (PKT_public_key *pk, u32 *keyid)
if (!keyid)
keyid = dummy_keyid;
- if( pk->keyid[0] || pk->keyid[1] )
- {
- keyid[0] = pk->keyid[0];
- keyid[1] = pk->keyid[1];
- }
- else
- {
- const byte *dp;
- gcry_md_hd_t md;
-
- md = do_fingerprint_md(pk);
- if(md)
- {
- dp = gcry_md_read ( md, 0 );
- if (pk->version == 5)
- {
- keyid[0] = buf32_to_u32 (dp);
- keyid[1] = buf32_to_u32 (dp+4);
- }
- else
- {
- keyid[0] = buf32_to_u32 (dp+12);
- keyid[1] = buf32_to_u32 (dp+16);
- }
- gcry_md_close (md);
- pk->keyid[0] = keyid[0];
- pk->keyid[1] = keyid[1];
- }
- else
- pk->keyid[0] = pk->keyid[1] = keyid[0]= keyid[1] = 0xFFFFFFFF;
- }
+ if (!pk->fprlen)
+ compute_fingerprint (pk);
+
+ keyid[0] = pk->keyid[0];
+ keyid[1] = pk->keyid[1];
return keyid[1]; /*FIXME:shortkeyid ist different for v5*/
}
@@ -805,6 +796,7 @@ colon_expirestr_from_sig (PKT_signature *sig)
}
+
/*
* Return a byte array with the fingerprint for the given PK/SK
* The length of the array is returned in ret_len. Caller must free
@@ -813,31 +805,15 @@ colon_expirestr_from_sig (PKT_signature *sig)
byte *
fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
{
- const byte *dp;
- size_t len;
- gcry_md_hd_t md;
+ if (!pk->fprlen)
+ compute_fingerprint (pk);
- md = do_fingerprint_md (pk);
- dp = gcry_md_read (md, 0);
- len = gcry_md_get_algo_dlen (gcry_md_get_algo (md));
- log_assert (len <= MAX_FINGERPRINT_LEN);
if (!array)
- array = xmalloc ( len );
- memcpy (array, dp, len );
- if (pk->version == 5)
- {
- pk->keyid[0] = buf32_to_u32 (dp);
- pk->keyid[1] = buf32_to_u32 (dp+4);
- }
- else
- {
- pk->keyid[0] = buf32_to_u32 (dp+12);
- pk->keyid[1] = buf32_to_u32 (dp+16);
- }
- gcry_md_close( md);
+ array = xmalloc (pk->fprlen);
+ memcpy (array, pk->fpr, pk->fprlen);
if (ret_len)
- *ret_len = len;
+ *ret_len = pk->fprlen;
return array;
}
@@ -852,19 +828,19 @@ fingerprint_from_pk (PKT_public_key *pk, byte *array, size_t *ret_len)
char *
hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen)
{
- unsigned char fpr[MAX_FINGERPRINT_LEN];
- size_t len;
+ if (!pk->fprlen)
+ compute_fingerprint (pk);
- fingerprint_from_pk (pk, fpr, &len);
if (!buffer)
{
- buffer = xtrymalloc (2 * len + 1);
+ buffer = xtrymalloc (2 * pk->fprlen + 1);
if (!buffer)
return NULL;
}
- else if (buflen < 2*len+1)
+ else if (buflen < 2 * pk->fprlen + 1)
log_fatal ("%s: buffer too short (%zu)\n", __func__, buflen);
- bin2hex (fpr, len, buffer);
+
+ bin2hex (pk->fpr, pk->fprlen, buffer);
return buffer;
}
diff --git a/g10/keylist.c b/g10/keylist.c
index 8d5b2e0b9..1274775d2 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -51,7 +51,7 @@
static void list_all (ctrl_t, int, int);
static void list_one (ctrl_t ctrl,
strlist_t names, int secret, int mark_secret);
-static void locate_one (ctrl_t ctrl, strlist_t names);
+static void locate_one (ctrl_t ctrl, strlist_t names, int no_local);
static void print_card_serialno (const char *serialno);
struct keylist_context
@@ -83,10 +83,11 @@ keylist_context_release (struct keylist_context *listctx)
/* List the keys. If list is NULL, all available keys are listed.
- With LOCATE_MODE set the locate algorithm is used to find a
- key. */
+ * With LOCATE_MODE set the locate algorithm is used to find a key; if
+ * in addition NO_LOCAL is set the locate does not look into the local
+ * keyring. */
void
-public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
+public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode, int no_local)
{
#ifndef NO_TRUST_MODELS
if (opt.with_colons)
@@ -140,7 +141,7 @@ public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode)
#endif
if (locate_mode)
- locate_one (ctrl, list);
+ locate_one (ctrl, list, no_local);
else if (!list)
list_all (ctrl, 0, opt.with_secret);
else
@@ -165,60 +166,78 @@ secret_key_list (ctrl_t ctrl, strlist_t list)
list_one (ctrl, list, 1, 0);
}
-char *
-format_seckey_info (ctrl_t ctrl, PKT_public_key *pk)
+
+/* Helper for print_key_info and print_key_info_log. */
+static char *
+format_key_info (ctrl_t ctrl, PKT_public_key *pk, int secret)
{
u32 keyid[2];
char *p;
char pkstrbuf[PUBKEY_STRING_SIZE];
- char *info;
+ char *result;
keyid_from_pk (pk, keyid);
- p = get_user_id_native (ctrl, keyid);
- info = xtryasprintf ("sec %s/%s %s %s",
- pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
- keystr (keyid), datestr_from_pk (pk), p);
+ /* If the pk was chosen by a particular user ID, that is the one to
+ print. */
+ if (pk->user_id)
+ p = utf8_to_native (pk->user_id->name, pk->user_id->len, 0);
+ else
+ p = get_user_id_native (ctrl, keyid);
+ result = xtryasprintf ("%s %s/%s %s %s",
+ secret? (pk->flags.primary? "sec":"ssb")
+ /* */ : (pk->flags.primary? "pub":"sub"),
+ pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
+ keystr (keyid), datestr_from_pk (pk), p);
xfree (p);
-
- return info;
+ return result;
}
+
+/* Print basic information about a public or secret key. With FP
+ * passed as NULL, the tty output interface is used, otherwise output
+ * is directed to the given stream. INDENT gives the requested
+ * indentation; if that is a negative value indentation is suppressed
+ * for the first line. SECRET tells that the PK has a secret part.
+ * FIXME: This is similar in use to print_key_line and thus both
+ * functions should eventually be united.
+ */
void
-print_seckey_info (ctrl_t ctrl, PKT_public_key *pk)
+print_key_info (ctrl_t ctrl, estream_t fp,
+ int indent, PKT_public_key *pk, int secret)
{
- char *p = format_seckey_info (ctrl, pk);
- tty_printf ("\n%s\n", p);
- xfree (p);
+ int indentabs = indent >= 0? indent : -indent;
+ char *info;
+
+ /* Note: Negative values for INDENT are not yet needed. */
+
+ info = format_key_info (ctrl, pk, secret);
+
+ if (!fp && indent >= 0)
+ tty_printf ("\n"); /* (Backward compatibility to old code) */
+ tty_fprintf (fp, "%*s%s\n", indentabs, "",
+ info? info : "[Ooops - out of core]");
+
+ xfree (info);
}
-/* Print information about the public key. With FP passed as NULL,
- the tty output interface is used, otherwise output is directed to
- the given stream. */
+
+/* Same as print_key_info put print using the log functions at
+ * LOGLEVEL. */
void
-print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk)
+print_key_info_log (ctrl_t ctrl, int loglevel,
+ int indent, PKT_public_key *pk, int secret)
{
- u32 keyid[2];
- char *p;
- char pkstrbuf[PUBKEY_STRING_SIZE];
+ int indentabs = indent >= 0? indent : -indent;
+ char *info;
- keyid_from_pk (pk, keyid);
+ info = format_key_info (ctrl, pk, secret);
- /* If the pk was chosen by a particular user ID, that is the one to
- print. */
- if (pk->user_id)
- p = utf8_to_native (pk->user_id->name, pk->user_id->len, 0);
- else
- p = get_user_id_native (ctrl, keyid);
+ log_log (loglevel, "%*s%s\n", indentabs, "",
+ info? info : "[Ooops - out of core]");
- if (!fp)
- tty_printf ("\n");
- tty_fprintf (fp, "%s %s/%s %s %s\n",
- pk->flags.primary? "pub":"sub",
- pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
- keystr (keyid), datestr_from_pk (pk), p);
- xfree (p);
+ xfree (info);
}
@@ -640,7 +659,7 @@ list_one (ctrl_t ctrl, strlist_t names, int secret, int mark_secret)
static void
-locate_one (ctrl_t ctrl, strlist_t names)
+locate_one (ctrl_t ctrl, strlist_t names, int no_local)
{
int rc = 0;
strlist_t sl;
@@ -654,7 +673,10 @@ locate_one (ctrl_t ctrl, strlist_t names)
for (sl = names; sl; sl = sl->next)
{
- rc = get_best_pubkey_byname (ctrl, &ctx, NULL, sl->d, &keyblock, 1);
+ rc = get_best_pubkey_byname (ctrl,
+ no_local? GET_PUBKEY_NO_LOCAL
+ /* */: GET_PUBKEY_NORMAL,
+ &ctx, NULL, sl->d, &keyblock, 1);
if (rc)
{
if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY)
diff --git a/g10/keyring.c b/g10/keyring.c
index 21791a6ac..5fa499759 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -473,11 +473,14 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
}
in_cert = 1;
- node = lastnode = new_kbnode (pkt);
+ node = new_kbnode (pkt);
if (!keyblock)
- keyblock = node;
+ keyblock = lastnode = node;
else
- add_kbnode (keyblock, node);
+ {
+ lastnode->next = node;
+ lastnode = node;
+ }
switch (pkt->pkttype)
{
case PKT_PUBLIC_KEY:
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 66900f7a9..b07afb128 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -333,7 +333,7 @@ parse_keyserver_uri (const char *string,int require_scheme)
{
/* Three slashes means network path with a default host name.
This is a hack because it does not crok all possible
- combiantions. We should better repalce all code bythe parser
+ combinations. We should better replace all code by the parser
from http.c. */
keyserver->path = xstrdup (uri+2);
}
@@ -1519,9 +1519,7 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
log_info (_("key not found on keyserver\n"));
}
- if (gpg_err_code (err) == GPG_ERR_NO_KEYSERVER)
- log_error (_("no keyserver known (use option --keyserver)\n"));
- else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+ if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = gpg_error (GPG_ERR_NOT_FOUND);
else if (err)
log_error ("error searching keyserver: %s\n", gpg_strerror (err));
@@ -2051,8 +2049,9 @@ keyserver_import_wkd (ctrl_t ctrl, const char *name, int quick,
int armor_status = opt.no_armor;
import_filter_t save_filt;
- /* Keys returned via WKD are in binary format. */
- opt.no_armor = 1;
+ /* Keys returned via WKD are in binary format. However, we
+ * relax that requirement and allow also for armored data. */
+ opt.no_armor = 0;
save_filt = save_and_clear_import_filter ();
if (!save_filt)
err = gpg_error_from_syserror ();
diff --git a/g10/main.h b/g10/main.h
index 34a932b16..f45b03909 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -414,6 +414,8 @@ void export_print_stats (export_stats_t stats);
int parse_export_options(char *str,unsigned int *options,int noisy);
gpg_error_t parse_and_set_export_filter (const char *string);
+int exact_subkey_match_p (KEYDB_SEARCH_DESC *desc, kbnode_t node);
+
int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
export_stats_t stats);
int export_seckeys (ctrl_t ctrl, strlist_t users, unsigned int options,
@@ -456,7 +458,8 @@ struct revocation_reason_info * get_default_uid_revocation_reason(void);
void release_revocation_reason_info( struct revocation_reason_info *reason );
/*-- keylist.c --*/
-void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode );
+void public_key_list (ctrl_t ctrl, strlist_t list,
+ int locate_mode, int no_local);
void secret_key_list (ctrl_t ctrl, strlist_t list );
void print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock);
@@ -470,9 +473,10 @@ void show_keyserver_url(PKT_signature *sig,int indent,int mode);
void show_notation(PKT_signature *sig,int indent,int mode,int which);
void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk);
void set_attrib_fd(int fd);
-char *format_seckey_info (ctrl_t ctrl, PKT_public_key *pk);
-void print_seckey_info (ctrl_t ctrl, PKT_public_key *pk);
-void print_pubkey_info (ctrl_t ctrl, estream_t fp, PKT_public_key *pk);
+void print_key_info (ctrl_t ctrl, estream_t fp, int indent,
+ PKT_public_key *pk, int secret);
+void print_key_info_log (ctrl_t ctrl, int loglevel, int indent,
+ PKT_public_key *pk, int secret);
void print_card_key_info (estream_t fp, KBNODE keyblock);
void print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret);
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 7acf67b1e..8a9005c21 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -506,19 +506,18 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list)
for (; list; list = list->next)
{
PKT_public_key *pk;
- const char *algstr;
+ char pkstrbuf[PUBKEY_STRING_SIZE];
+ char *p;
- algstr = openpgp_pk_algo_name (list->pubkey_algo);
pk = xmalloc_clear (sizeof *pk);
- if (!algstr)
- algstr = "[?]";
pk->pubkey_algo = list->pubkey_algo;
if (!get_pubkey (ctrl, pk, list->keyid))
{
- char *p;
- log_info (_("encrypted with %u-bit %s key, ID %s, created %s\n"),
- nbits_from_pk (pk), algstr, keystr_from_pk(pk),
+ pubkey_string (pk, pkstrbuf, sizeof pkstrbuf);
+
+ log_info (_("encrypted with %s key, ID %s, created %s\n"),
+ pkstrbuf, keystr_from_pk (pk),
strtimestamp (pk->timestamp));
p = get_user_id_native (ctrl, list->keyid);
log_printf (_(" \"%s\"\n"), p);
@@ -526,7 +525,8 @@ print_pkenc_list (ctrl_t ctrl, struct pubkey_enc_list *list)
}
else
log_info (_("encrypted with %s key, ID %s\n"),
- algstr, keystr(list->keyid));
+ openpgp_pk_algo_name (list->pubkey_algo),
+ keystr(list->keyid));
free_public_key (pk);
}
@@ -574,7 +574,7 @@ proc_encrypted (CTX c, PACKET *pkt)
write_status_error ("pkdecrypt_failed", result);
}
}
- else
+ else if (c->pkenc_list)
{
c->dek = xmalloc_secure_clear (sizeof *c->dek);
result = get_session_key (c->ctrl, c->pkenc_list, c->dek);
@@ -583,7 +583,7 @@ proc_encrypted (CTX c, PACKET *pkt)
struct pubkey_enc_list *list;
for (list = c->pkenc_list; list; list = list->next)
- if (list->result == GPG_ERR_NO_SECKEY)
+ if (list->result != -1)
{
char buf[20];
snprintf (buf, sizeof buf, "%08lX%08lX",
@@ -668,7 +668,13 @@ proc_encrypted (CTX c, PACKET *pkt)
}
}
else if (!c->dek)
- result = GPG_ERR_NO_SECKEY;
+ {
+ if (c->symkeys && !c->pkenc_list)
+ result = gpg_error (GPG_ERR_BAD_KEY);
+
+ if (!result)
+ result = gpg_error (GPG_ERR_NO_SECKEY);
+ }
/* Compute compliance with CO_DE_VS. */
if (!result && is_status_enabled ()
@@ -780,7 +786,7 @@ proc_encrypted (CTX c, PACKET *pkt)
if ((gpg_err_code (result) == GPG_ERR_BAD_KEY
|| gpg_err_code (result) == GPG_ERR_CHECKSUM
|| gpg_err_code (result) == GPG_ERR_CIPHER_ALGO)
- && *c->dek->s2k_cacheid != '\0')
+ && c->dek && *c->dek->s2k_cacheid != '\0')
{
if (opt.debug)
log_debug ("cleared passphrase cached with ID: %s\n",
@@ -1840,7 +1846,6 @@ check_sig_and_print (CTX c, kbnode_t node)
int is_revkey = 0;
char *issuer_fpr = NULL;
PKT_public_key *pk = NULL; /* The public key for the signature or NULL. */
- int tried_ks_by_fpr;
const void *extrahash = NULL;
size_t extrahashlen = 0;
@@ -1999,12 +2004,17 @@ check_sig_and_print (CTX c, kbnode_t node)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
- /* If the key isn't found, check for a preferred keyserver. */
- if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && sig->flags.pref_ks)
+ /* If the key isn't found, check for a preferred keyserver. Note
+ * that this is only done if honor-keyserver-url has been set. We
+ * test for this in the loop so that we can show info about the
+ * preferred keyservers. */
+ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
+ && sig->flags.pref_ks)
{
const byte *p;
int seq = 0;
size_t n;
+ int any_pref_ks = 0;
while ((p=enum_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS,&n,&seq,NULL)))
{
@@ -2015,9 +2025,10 @@ check_sig_and_print (CTX c, kbnode_t node)
log_info(_("Key available at: ") );
print_utf8_buffer (log_get_stream(), p, n);
log_printf ("\n");
+ any_pref_ks = 1;
- if (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE
- && opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL)
+ if ((opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
+ && (opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL))
{
struct keyserver_spec *spec;
@@ -2026,6 +2037,10 @@ check_sig_and_print (CTX c, kbnode_t node)
{
int res;
+ if (DBG_LOOKUP)
+ log_debug ("trying auto-key-retrieve method %s\n",
+ "Pref-KS");
+
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
@@ -2034,6 +2049,9 @@ check_sig_and_print (CTX c, kbnode_t node)
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
+ else if (DBG_LOOKUP)
+ log_debug ("lookup via %s failed: %s\n", "Pref-KS",
+ gpg_strerror (res));
free_keyserver_spec (spec);
if (!rc)
@@ -2041,10 +2059,44 @@ check_sig_and_print (CTX c, kbnode_t node)
}
}
}
+
+ if (any_pref_ks
+ && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
+ && !(opt.keyserver_options.options&KEYSERVER_HONOR_KEYSERVER_URL))
+ log_info (_("Note: Use '%s' to make use of this info\n"),
+ "--keyserver-option honor-keyserver-url");
+ }
+
+ /* If the above methods didn't work, our next try is to retrieve the
+ * key from the WKD. This requires that WKD is in the AKL and the
+ * Signer's UID is in the signature. */
+ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
+ && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
+ && !opt.flags.disable_signer_uid
+ && akl_has_wkd_method ()
+ && sig->signers_uid)
+ {
+ int res;
+
+ if (DBG_LOOKUP)
+ log_debug ("trying auto-key-retrieve method %s\n", "WKD");
+ free_public_key (pk);
+ pk = NULL;
+ glo_ctrl.in_auto_key_retrieve++;
+ res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL);
+ glo_ctrl.in_auto_key_retrieve--;
+ /* Fixme: If the fingerprint is embedded in the signature,
+ * compare it to the fingerprint of the returned key. */
+ if (!res)
+ rc = do_check_sig (c, node, extrahash, extrahashlen,
+ NULL, &is_expkey, &is_revkey, &pk);
+ else if (DBG_LOOKUP)
+ log_debug ("lookup via %s failed: %s\n", "WKD", gpg_strerror (res));
}
/* If the avove methods didn't work, our next try is to use the URI
- * from a DNS PKA record. */
+ * from a DNS PKA record. This is a legacy method which will
+ * eventually be removed. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
&& (opt.keyserver_options.options & KEYSERVER_HONOR_PKA_RECORD))
@@ -2061,6 +2113,9 @@ check_sig_and_print (CTX c, kbnode_t node)
spec = parse_keyserver_uri (uri, 1);
if (spec)
{
+ if (DBG_LOOKUP)
+ log_debug ("trying auto-key-retrieve method %s\n", "PKA");
+
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
@@ -2070,16 +2125,16 @@ check_sig_and_print (CTX c, kbnode_t node)
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
+ else if (DBG_LOOKUP)
+ log_debug ("lookup via %s failed: %s\n", "PKA",
+ gpg_strerror (res));
}
}
}
/* If the above methods didn't work, our next try is to locate
* the key via its fingerprint from a keyserver. This requires
- * that the signers fingerprint is encoded in the signature. We
- * favor this over the WKD method (to be tried next), because an
- * arbitrary keyserver is less subject to web bug like monitoring. */
- tried_ks_by_fpr = 0;
+ * that the signers fingerprint is encoded in the signature. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
&& (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
&& keyserver_any_configured (c->ctrl))
@@ -2091,60 +2146,23 @@ check_sig_and_print (CTX c, kbnode_t node)
p = issuer_fpr_raw (sig, &n);
if (p)
{
+ if (DBG_LOOKUP)
+ log_debug ("trying auto-key-retrieve method %s\n", "KS");
+
/* v4 or v5 packet with a SHA-1/256 fingerprint. */
free_public_key (pk);
pk = NULL;
glo_ctrl.in_auto_key_retrieve++;
res = keyserver_import_fprint (c->ctrl, p, n, opt.keyserver, 1);
- tried_ks_by_fpr = 1;
glo_ctrl.in_auto_key_retrieve--;
if (!res)
rc = do_check_sig (c, node, extrahash, extrahashlen,
NULL, &is_expkey, &is_revkey, &pk);
+ else if (DBG_LOOKUP)
+ log_debug ("lookup via %s failed: %s\n", "KS", gpg_strerror (res));
}
}
- /* If the above methods didn't work, our next try is to retrieve the
- * key from the WKD. */
- if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
- && (opt.keyserver_options.options & KEYSERVER_AUTO_KEY_RETRIEVE)
- && !opt.flags.disable_signer_uid
- && akl_has_wkd_method ()
- && sig->signers_uid)
- {
- int res;
-
- free_public_key (pk);
- pk = NULL;
- glo_ctrl.in_auto_key_retrieve++;
- res = keyserver_import_wkd (c->ctrl, sig->signers_uid, 1, NULL, NULL);
- glo_ctrl.in_auto_key_retrieve--;
- /* Fixme: If the fingerprint is embedded in the signature,
- * compare it to the fingerprint of the returned key. */
- if (!res)
- rc = do_check_sig (c, node, extrahash, extrahashlen,
- NULL, &is_expkey, &is_revkey, &pk);
- }
-
- /* If the above methods did't work, our next try is to use a
- * keyserver. */
- if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
- && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
- && !tried_ks_by_fpr
- && keyserver_any_configured (c->ctrl))
- {
- int res;
-
- free_public_key (pk);
- pk = NULL;
- glo_ctrl.in_auto_key_retrieve++;
- res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver, 1);
- glo_ctrl.in_auto_key_retrieve--;
- if (!res)
- rc = do_check_sig (c, node, extrahash, extrahashlen,
- NULL, &is_expkey, &is_revkey, &pk);
- }
-
if (!rc || gpg_err_code (rc) == GPG_ERR_BAD_SIGNATURE)
{
kbnode_t un, keyblock;
diff --git a/g10/objcache.c b/g10/objcache.c
new file mode 100644
index 000000000..adb0717d7
--- /dev/null
+++ b/g10/objcache.c
@@ -0,0 +1,689 @@
+/* objcache.c - Caching functions for keys and user ids.
+ * Copyright (C) 2019 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gpg.h"
+#include "../common/util.h"
+#include "packet.h"
+#include "keydb.h"
+#include "options.h"
+#include "objcache.h"
+
+/* Note that max value for uid_items is actually a the threshold when
+ * we start to look for ietms which can be removed. */
+#define NO_OF_UID_ITEM_BUCKETS 107
+#define MAX_UID_ITEMS_PER_BUCKET 20
+
+#define NO_OF_KEY_ITEM_BUCKETS 383
+#define MAX_KEY_ITEMS_PER_BUCKET 20
+
+
+/* An object to store a user id. This describes an item in the linked
+ * lists of a bucket in hash table. The reference count will
+ * eventually be used to remove items from the table. */
+typedef struct uid_item_s
+{
+ struct uid_item_s *next;
+ unsigned int refcount; /* The reference count for this item. */
+ unsigned int namelen; /* The length of the UID sans the nul. */
+ char name[1];
+} *uid_item_t;
+
+static uid_item_t *uid_table; /* Hash table for with user ids. */
+static size_t uid_table_size; /* Number of allocated buckets. */
+static unsigned int uid_table_max; /* Max. # of items in a bucket. */
+static unsigned int uid_table_added; /* # of items added. */
+static unsigned int uid_table_dropped;/* # of items dropped. */
+
+
+/* An object to store properties of a key. Note that this can be used
+ * for a primary or a subkey. The key is linked to a user if that
+ * exists. */
+typedef struct key_item_s
+{
+ struct key_item_s *next;
+ unsigned int usecount;
+ byte fprlen;
+ char fpr[MAX_FINGERPRINT_LEN];
+ u32 keyid[2];
+ uid_item_t ui; /* NULL of a ref'ed user id item. */
+} *key_item_t;
+
+static key_item_t *key_table; /* Hash table with the keys. */
+static size_t key_table_size; /* Number of allocated buckents. */
+static unsigned int key_table_max; /* Max. # of items in a bucket. */
+static unsigned int key_table_added; /* # of items added. */
+static unsigned int key_table_dropped;/* # of items dropped. */
+static key_item_t key_item_attic; /* List of freed items. */
+
+
+
+/* Dump stats. */
+void
+objcache_dump_stats (void)
+{
+ unsigned int idx;
+ int len, minlen, maxlen;
+ unsigned int count, attic, empty;
+ key_item_t ki;
+ uid_item_t ui;
+
+ count = empty = 0;
+ minlen = -1;
+ maxlen = 0;
+ for (idx = 0; idx < key_table_size; idx++)
+ {
+ len = 0;
+ for (ki = key_table[idx]; ki; ki = ki->next)
+ {
+ count++;
+ len++;
+ /* log_debug ("key bucket %u: kid=%08lX used=%u ui=%p\n", */
+ /* idx, (ulong)ki->keyid[0], ki->usecount, ki->ui); */
+ }
+ if (len > maxlen)
+ maxlen = len;
+
+ if (!len)
+ empty++;
+ else if (minlen == -1 || len < minlen)
+ minlen = len;
+ }
+ for (attic=0, ki = key_item_attic; ki; ki = ki->next)
+ attic++;
+ log_info ("objcache: keys=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u"
+ " attic=%u\n",
+ count, key_table_added, key_table_dropped,
+ empty, minlen > 0? minlen : 0, maxlen,
+ key_table_size, key_table_max, attic);
+
+ count = empty = 0;
+ minlen = -1;
+ maxlen = 0;
+ for (idx = 0; idx < uid_table_size; idx++)
+ {
+ len = 0;
+ for (ui = uid_table[idx]; ui; ui = ui->next)
+ {
+ count++;
+ len++;
+ /* log_debug ("uid bucket %u: %p ref=%u l=%u (%.20s)\n", */
+ /* idx, ui, ui->refcount, ui->namelen, ui->name); */
+ }
+ if (len > maxlen)
+ maxlen = len;
+
+ if (!len)
+ empty++;
+ else if (minlen == -1 || len < minlen)
+ minlen = len;
+ }
+ log_info ("objcache: uids=%u/%u/%u chains=%u,%d..%d buckets=%zu/%u\n",
+ count, uid_table_added, uid_table_dropped,
+ empty, minlen > 0? minlen : 0, maxlen,
+ uid_table_size, uid_table_max);
+}
+
+
+
+/* The hash function we use for the uid_table. Must not call a system
+ * function. */
+static inline unsigned int
+uid_table_hasher (const char *name, unsigned namelen)
+{
+ const unsigned char *s = (const unsigned char*)name;
+ unsigned int hashval = 0;
+ unsigned int carry;
+
+ for (; namelen; namelen--, s++)
+ {
+ hashval = (hashval << 4) + *s;
+ if ((carry = (hashval & 0xf0000000)))
+ {
+ hashval ^= (carry >> 24);
+ hashval ^= carry;
+ }
+ }
+
+ return hashval % uid_table_size;
+}
+
+
+/* Run time allocation of the uid table. This allows us to eventually
+ * add an option to gpg to control the size. */
+static void
+uid_table_init (void)
+{
+ if (uid_table)
+ return;
+ uid_table_size = NO_OF_UID_ITEM_BUCKETS;
+ uid_table_max = MAX_UID_ITEMS_PER_BUCKET;
+ uid_table = xcalloc (uid_table_size, sizeof *uid_table);
+}
+
+
+static uid_item_t
+uid_item_ref (uid_item_t ui)
+{
+ if (ui)
+ ui->refcount++;
+ return ui;
+}
+
+static void
+uid_item_unref (uid_item_t uid)
+{
+ if (!uid)
+ return;
+ if (!uid->refcount)
+ log_fatal ("too many unrefs for uid_item\n");
+
+ uid->refcount--;
+ /* We do not release the item here because that would require that
+ * we locate the head of the list which has this item. This will
+ * take too long and thus the item is removed when we need to purge
+ * some items for the list during uid_item_put. */
+}
+
+
+/* Put (NAME,NAMELEN) into the UID_TABLE and return the item. The
+ * reference count for that item is incremented. NULL is return on an
+ * allocation error. The caller should release the returned item
+ * using uid_item_unref. */
+static uid_item_t
+uid_table_put (const char *name, unsigned int namelen)
+{
+ unsigned int hash;
+ uid_item_t ui;
+ unsigned int count;
+
+ if (!uid_table)
+ uid_table_init ();
+
+ hash = uid_table_hasher (name, namelen);
+ for (ui = uid_table[hash], count = 0; ui; ui = ui->next, count++)
+ if (ui->namelen == namelen && !memcmp (ui->name, name, namelen))
+ return uid_item_ref (ui); /* Found. */
+
+ /* If the bucket is full remove all unrefed items. */
+ if (count >= uid_table_max)
+ {
+ uid_item_t ui_next, ui_prev, list_head, drop_head;
+
+ /* No syscalls from here .. */
+ list_head = uid_table[hash];
+ drop_head = NULL;
+ while (list_head && !list_head->refcount)
+ {
+ ui = list_head;
+ list_head = ui->next;
+ ui->next = drop_head;
+ drop_head = ui;
+ }
+ if ((ui_prev = list_head))
+ for (ui = ui_prev->next; ui; ui = ui_next)
+ {
+ ui_next = ui->next;
+ if (!ui->refcount)
+ {
+ ui->next = drop_head;
+ drop_head = ui;
+ ui_prev->next = ui_next;
+ }
+ else
+ ui_prev = ui;
+ }
+ uid_table[hash] = list_head;
+ /* ... to here */
+
+ for (ui = drop_head; ui; ui = ui_next)
+ {
+ ui_next = ui->next;
+ xfree (ui);
+ uid_table_dropped++;
+ }
+ }
+
+ count = uid_table_added + uid_table_dropped;
+ ui = xtrycalloc (1, sizeof *ui + namelen);
+ if (!ui)
+ return NULL; /* Out of core. */
+ if (count != uid_table_added + uid_table_dropped)
+ {
+ /* During the malloc another thread added an item. Thus we need
+ * to check again. */
+ uid_item_t ui_new = ui;
+ for (ui = uid_table[hash]; ui; ui = ui->next)
+ if (ui->namelen == namelen && !memcmp (ui->name, name, namelen))
+ {
+ /* Found. */
+ xfree (ui_new);
+ return uid_item_ref (ui);
+ }
+ ui = ui_new;
+ }
+
+ memcpy (ui->name, name, namelen);
+ ui->name[namelen] = 0; /* Extra Nul so we can use it as a string. */
+ ui->namelen = namelen;
+ ui->refcount = 1;
+ ui->next = uid_table[hash];
+ uid_table[hash] = ui;
+ uid_table_added++;
+ return ui;
+}
+
+
+
+/* The hash function we use for the key_table. Must not call a system
+ * function. */
+static inline unsigned int
+key_table_hasher (u32 *keyid)
+{
+ /* A fingerprint could be used directly as a hash value. However,
+ * we use the keyid here because it is used in encrypted packets and
+ * older signatures to identify a key. Since v4 keys the keyid is
+ * anyway a part of the fingerprint so it quickly extracted from a
+ * fingerprint. Note that v3 keys are not supported by gpg. */
+ return keyid[0] % key_table_size;
+}
+
+
+/* Run time allocation of the key table. This allows us to eventually
+ * add an option to gpg to control the size. */
+static void
+key_table_init (void)
+{
+ if (key_table)
+ return;
+ key_table_size = NO_OF_KEY_ITEM_BUCKETS;
+ key_table_max = MAX_KEY_ITEMS_PER_BUCKET;
+ key_table = xcalloc (key_table_size, sizeof *key_table);
+}
+
+
+static void
+key_item_free (key_item_t ki)
+{
+ if (!ki)
+ return;
+ uid_item_unref (ki->ui);
+ ki->ui = NULL;
+ ki->next = key_item_attic;
+ key_item_attic = ki;
+}
+
+
+/* Get a key item from PK or if that is NULL from KEYID. The
+ * reference count for that item is incremented. NULL is return if it
+ * was not found. */
+static key_item_t
+key_table_get (PKT_public_key *pk, u32 *keyid)
+{
+ unsigned int hash;
+ key_item_t ki, ki2;
+
+ if (!key_table)
+ key_table_init ();
+
+ if (pk)
+ {
+ byte fpr[MAX_FINGERPRINT_LEN];
+ size_t fprlen;
+ u32 tmpkeyid[2];
+
+ fingerprint_from_pk (pk, fpr, &fprlen);
+ keyid_from_pk (pk, tmpkeyid);
+ hash = key_table_hasher (tmpkeyid);
+ for (ki = key_table[hash]; ki; ki = ki->next)
+ if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
+ return ki; /* Found */
+ }
+ else if (keyid)
+ {
+ hash = key_table_hasher (keyid);
+ for (ki = key_table[hash]; ki; ki = ki->next)
+ if (ki->keyid[0] == keyid[0] && ki->keyid[1] == keyid[1])
+ {
+ /* Found. We need to check for dups. */
+ for (ki2 = ki->next; ki2; ki2 = ki2->next)
+ if (ki2->keyid[0] == keyid[0] && ki2->keyid[1] == keyid[1])
+ return NULL; /* Duplicated keyid - retrun NULL. */
+
+ /* This is the only one - return it. */
+ return ki;
+ }
+ }
+ return NULL;
+}
+
+
+/* Helper for the qsort in key_table_put. */
+static int
+compare_key_items (const void *arg_a, const void *arg_b)
+{
+ const key_item_t a = *(const key_item_t *)arg_a;
+ const key_item_t b = *(const key_item_t *)arg_b;
+
+ /* Reverse sort on the usecount. */
+ if (a->usecount > b->usecount)
+ return -1;
+ else if (a->usecount == b->usecount)
+ return 0;
+ else
+ return 1;
+}
+
+
+/* Put PK into the KEY_TABLE and return a key item. The reference
+ * count for that item is incremented. If UI is given it is put into
+ * the entry. NULL is return on an allocation error. */
+static key_item_t
+key_table_put (PKT_public_key *pk, uid_item_t ui)
+{
+ unsigned int hash;
+ key_item_t ki;
+ u32 keyid[2];
+ byte fpr[MAX_FINGERPRINT_LEN];
+ size_t fprlen;
+ unsigned int count, n;
+
+ if (!key_table)
+ key_table_init ();
+
+ fingerprint_from_pk (pk, fpr, &fprlen);
+ keyid_from_pk (pk, keyid);
+ hash = key_table_hasher (keyid);
+ for (ki = key_table[hash], count=0; ki; ki = ki->next, count++)
+ if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
+ return ki; /* Found */
+
+ /* If the bucket is full remove a couple of items. */
+ if (count >= key_table_max)
+ {
+ key_item_t list_head, *list_tailp, ki_next;
+ key_item_t *array;
+ int narray, idx;
+
+ /* Unlink from the global list so that other threads don't
+ * disturb us. If another thread adds or removes something only
+ * one will be the winner. Bad luck for the drooped cache items
+ * but after all it is just a cache. */
+ list_head = key_table[hash];
+ key_table[hash] = NULL;
+
+ /* Put all items into an array for sorting. */
+ array = xtrycalloc (count, sizeof *array);
+ if (!array)
+ {
+ /* That's bad; give up all items of the bucket. */
+ log_info ("Note: malloc failed while purging from the key_tabe: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ goto leave_drop;
+ }
+ narray = 0;
+ for (ki = list_head; ki; ki = ki_next)
+ {
+ ki_next = ki->next;
+ array[narray++] = ki;
+ ki->next = NULL;
+ }
+ log_assert (narray == count);
+
+ /* Sort the array and put half of it onto a new list. */
+ qsort (array, narray, sizeof *array, compare_key_items);
+ list_head = NULL;
+ list_tailp = &list_head;
+ for (idx=0; idx < narray/2; idx++)
+ {
+ *list_tailp = array[idx];
+ list_tailp = &array[idx]->next;
+ }
+
+ /* Put the new list into the bucket. */
+ ki = key_table[hash];
+ key_table[hash] = list_head;
+ list_head = ki;
+
+ /* Free the remaining items and the array. */
+ for (; idx < narray; idx++)
+ {
+ key_item_free (array[idx]);
+ key_table_dropped++;
+ }
+ xfree (array);
+
+ leave_drop:
+ /* Free any items added in the meantime by other threads. This
+ * is also used in case of a malloc problem (which won't update
+ * the counters, though). */
+ for ( ; list_head; list_head = ki_next)
+ {
+ ki_next = list_head->next;
+ key_item_free (list_head);
+ }
+ }
+
+ /* Add an item to the bucket. We allocate a whole block of items
+ * for cache performace reasons. */
+ if (!key_item_attic)
+ {
+ key_item_t kiblock;
+ int kiblocksize = 256;
+
+ kiblock = xtrymalloc (kiblocksize * sizeof *kiblock);
+ if (!kiblock)
+ return NULL; /* Out of core. */
+ for (n = 0; n < kiblocksize; n++)
+ {
+ ki = kiblock + n;
+ ki->next = key_item_attic;
+ key_item_attic = ki;
+ }
+
+ /* During the malloc another thread may have changed the bucket.
+ * Thus we need to check again. */
+ for (ki = key_table[hash]; ki; ki = ki->next)
+ if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
+ return ki; /* Found */
+ }
+
+ /* We now know that there is an item in the attic. */
+ ki = key_item_attic;
+ key_item_attic = ki->next;
+ ki->next = NULL;
+
+ memcpy (ki->fpr, fpr, fprlen);
+ ki->fprlen = fprlen;
+ ki->keyid[0] = keyid[0];
+ ki->keyid[1] = keyid[1];
+ ki->ui = uid_item_ref (ui);
+ ki->usecount = 0;
+ ki->next = key_table[hash];
+ key_table[hash] = ki;
+ key_table_added++;
+ return ki;
+}
+
+
+
+/* Return the user ID from the given keyblock. We use the primary uid
+ * flag which should have already been set. The returned value is
+ * only valid as long as the given keyblock is not changed. */
+static const char *
+primary_uid_from_keyblock (kbnode_t keyblock, size_t *uidlen)
+{
+ kbnode_t k;
+
+ for (k = keyblock; k; k = k->next)
+ {
+ if (k->pkt->pkttype == PKT_USER_ID
+ && !k->pkt->pkt.user_id->attrib_data
+ && k->pkt->pkt.user_id->flags.primary)
+ {
+ *uidlen = k->pkt->pkt.user_id->len;
+ return k->pkt->pkt.user_id->name;
+ }
+ }
+ return NULL;
+}
+
+
+/* Store the associations of keyid/fingerprint and userid. Only
+ * public keys should be fed to this function. */
+void
+cache_put_keyblock (kbnode_t keyblock)
+{
+ uid_item_t ui = NULL;
+ kbnode_t k;
+
+ restart:
+ for (k = keyblock; k; k = k->next)
+ {
+ if (k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ if (!ui)
+ {
+ /* Initially we just test for an entry to avoid the need
+ * to create a user id item for a put. Only if we miss
+ * key in the cache we create a user id and restart. */
+ if (!key_table_get (k->pkt->pkt.public_key, NULL))
+ {
+ const char *uid;
+ size_t uidlen;
+
+ uid = primary_uid_from_keyblock (keyblock, &uidlen);
+ if (uid)
+ {
+ ui = uid_table_put (uid, uidlen);
+ if (!ui)
+ {
+ log_info ("Note: failed to cache a user id: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ goto leave;
+ }
+ goto restart;
+ }
+ }
+ }
+ else /* With a UID we use the update cache mode. */
+ {
+ if (!key_table_put (k->pkt->pkt.public_key, ui))
+ {
+ log_info ("Note: failed to cache a key: %s\n",
+ gpg_strerror (gpg_error_from_syserror ()));
+ goto leave;
+ }
+ }
+ }
+ }
+
+ leave:
+ uid_item_unref (ui);
+}
+
+
+/* Return the user id string for KEYID. If a user id is not found (or
+ * on malloc error) NULL is returned. If R_LENGTH is not NULL the
+ * length of the user id is stored there; this does not included the
+ * always appended nul. Note that a user id may include an internal
+ * nul which can be detected by the caller by comparing to the
+ * returned length. */
+char *
+cache_get_uid_bykid (u32 *keyid, unsigned int *r_length)
+{
+ key_item_t ki;
+ char *p;
+
+ if (r_length)
+ *r_length = 0;
+
+ ki = key_table_get (NULL, keyid);
+ if (!ki)
+ return NULL; /* Not found or duplicate keyid. */
+
+ if (!ki->ui)
+ p = NULL; /* No user id known for key. */
+ else
+ {
+ p = xtrymalloc (ki->ui->namelen + 1);
+ if (p)
+ {
+ memcpy (p, ki->ui->name, ki->ui->namelen + 1);
+ if (r_length)
+ *r_length = ki->ui->namelen;
+ ki->usecount++;
+ }
+ }
+
+ return p;
+}
+
+
+/* Return the user id string for FPR with FPRLEN. If a user id is not
+ * found (or on malloc error) NULL is returned. If R_LENGTH is not
+ * NULL the length of the user id is stored there; this does not
+ * included the always appended nul. Note that a user id may include
+ * an internal nul which can be detected by the caller by comparing to
+ * the returned length. */
+char *
+cache_get_uid_byfpr (const byte *fpr, size_t fprlen, size_t *r_length)
+{
+ char *p;
+ unsigned int hash;
+ u32 keyid[2];
+ key_item_t ki;
+
+ if (r_length)
+ *r_length = 0;
+
+ if (!key_table)
+ return NULL;
+
+ keyid_from_fingerprint (NULL, fpr, fprlen, keyid);
+ hash = key_table_hasher (keyid);
+ for (ki = key_table[hash]; ki; ki = ki->next)
+ if (ki->fprlen == fprlen && !memcmp (ki->fpr, fpr, fprlen))
+ break; /* Found */
+
+ if (!ki)
+ return NULL; /* Not found. */
+
+ if (!ki->ui)
+ p = NULL; /* No user id known for key. */
+ else
+ {
+ p = xtrymalloc (ki->ui->namelen + 1);
+ if (p)
+ {
+ memcpy (p, ki->ui->name, ki->ui->namelen + 1);
+ if (r_length)
+ *r_length = ki->ui->namelen;
+ ki->usecount++;
+ }
+ }
+
+ return p;
+}
diff --git a/g10/objcache.h b/g10/objcache.h
new file mode 100644
index 000000000..edf129525
--- /dev/null
+++ b/g10/objcache.h
@@ -0,0 +1,29 @@
+/* objcache.h - Caching functions for keys and user ids.
+ * Copyright (C) 2019 g10 Code GmbH
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef GNUPG_G10_OBJCACHE_H
+#define GNUPG_G10_OBJCACHE_H
+
+void objcache_dump_stats (void);
+void cache_put_keyblock (kbnode_t keyblock);
+char *cache_get_uid_bykid (u32 *keyid, unsigned int *r_length);
+char *cache_get_uid_byfpr (const byte *fpr, size_t fprlen, size_t *r_length);
+
+#endif /*GNUPG_G10_OBJCACHE_H*/
diff --git a/g10/options.h b/g10/options.h
index 8adf09f08..234929b15 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -249,6 +249,8 @@ struct
unsigned int disable_signer_uid:1;
/* Flag to enable experimental features from RFC4880bis. */
unsigned int rfc4880bis:1;
+ /* Hack: --output is not given but OUTFILE was temporary set to "-". */
+ unsigned int dummy_outfile:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
@@ -361,6 +363,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define IMPORT_REPAIR_KEYS (1<<11)
#define IMPORT_DRY_RUN (1<<12)
#define IMPORT_DROP_UIDS (1<<13)
+#define IMPORT_SELF_SIGS_ONLY (1<<14)
#define EXPORT_LOCAL_SIGS (1<<0)
#define EXPORT_ATTRIBUTES (1<<1)
diff --git a/g10/packet.h b/g10/packet.h
index 41dd1a95a..479f25044 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -33,6 +33,11 @@
#define DEBUG_PARSE_PACKET 1
+/* Maximum length of packets to avoid excessive memory allocation. */
+#define MAX_KEY_PACKET_LENGTH (256 * 1024)
+#define MAX_UID_PACKET_LENGTH ( 2 * 1024)
+#define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024)
+#define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024)
/* Constants to allocate static MPI arrays. */
#define PUBKEY_MAX_NPKEY OPENPGP_MAX_NPKEY
@@ -394,6 +399,7 @@ typedef struct
byte pubkey_algo;
byte pubkey_usage; /* for now only used to pass it to getkey() */
byte req_usage; /* hack to pass a request to getkey() */
+ byte fprlen; /* 0 or length of FPR. */
u32 has_expired; /* set to the expiration date if expired */
/* keyid of the primary key. Never access this value directly.
Instead, use pk_main_keyid(). */
@@ -401,6 +407,8 @@ typedef struct
/* keyid of this key. Never access this value directly! Instead,
use pk_keyid(). */
u32 keyid[2];
+ /* Fingerprint of the key. Only valid if FPRLEN is not 0. */
+ byte fpr[MAX_FINGERPRINT_LEN];
prefitem_t *prefs; /* list of preferences (may be NULL) */
struct
{
@@ -928,7 +936,7 @@ int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2,
int make_keysig_packet (ctrl_t ctrl,
PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
- PKT_public_key *pksk, int sigclass, int digest_algo,
+ PKT_public_key *pksk, int sigclass,
u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque,
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 5b4b1c900..ab82d475a 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -35,14 +35,9 @@
#include "main.h"
#include "../common/i18n.h"
#include "../common/host2net.h"
+#include "../common/mbox-util.h"
-/* Maximum length of packets to avoid excessive memory allocation. */
-#define MAX_KEY_PACKET_LENGTH (256 * 1024)
-#define MAX_UID_PACKET_LENGTH ( 2 * 1024)
-#define MAX_COMMENT_PACKET_LENGTH ( 64 * 1024)
-#define MAX_ATTR_PACKET_LENGTH ( 16 * 1024*1024)
-
static int mpi_print_mode;
static int list_mode;
static estream_t listfp;
@@ -2118,12 +2113,20 @@ parse_signature (IOBUF inp, int pkttype, unsigned long pktlen,
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIGNERS_UID, &len);
if (p && len)
{
+ char *mbox;
+
sig->signers_uid = try_make_printable_string (p, len, 0);
if (!sig->signers_uid)
{
rc = gpg_error_from_syserror ();
goto leave;
}
+ mbox = mailbox_from_userid (sig->signers_uid, 0);
+ if (mbox)
+ {
+ xfree (sig->signers_uid);
+ sig->signers_uid = mbox;
+ }
}
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_NOTATION, NULL);
diff --git a/g10/photoid.c b/g10/photoid.c
index bcea64fbf..f9720d329 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -262,7 +262,8 @@ char *image_type_to_string(byte type,int style)
}
#if !defined(FIXED_PHOTO_VIEWER) && !defined(DISABLE_PHOTO_VIEWER)
-static const char *get_default_photo_command(void)
+static const char *
+get_default_photo_command(void)
{
#if defined(_WIN32)
OSVERSIONINFO osvi;
@@ -274,14 +275,21 @@ static const char *get_default_photo_command(void)
if(osvi.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS)
return "start /w %i";
else
- return "cmd /c start /w %i";
+ return "!ShellExecute 400 %i";
#elif defined(__APPLE__)
/* OS X. This really needs more than just __APPLE__. */
return "open %I";
#elif defined(__riscos__)
return "Filer_Run %I";
#else
- return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
+ if (!path_access ("xloadimage", X_OK))
+ return "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin";
+ else if (!path_access ("display",X_OK))
+ return "display -title 'KeyID 0x%k' %i";
+ else if (getuid () && !path_access ("xdg-open", X_OK))
+ return "xdg-open %i";
+ else
+ return "/bin/true";
#endif
}
#endif
@@ -312,6 +320,8 @@ show_photos (ctrl_t ctrl, const struct user_attribute *attrs, int count,
if (pk)
keyid_from_pk (pk, kid);
+ es_fflush (es_stdout);
+
for(i=0;i<count;i++)
if(attrs[i].type==ATTRIB_IMAGE &&
parse_image_header(&attrs[i],&args.imagetype,&len))
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 46258bf85..1fd23a3e4 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -475,7 +475,7 @@ do_we_trust_pre (ctrl_t ctrl, PKT_public_key *pk, unsigned int trustlevel )
if( !opt.batch && !rc )
{
- print_pubkey_info (ctrl, NULL,pk);
+ print_key_info (ctrl, NULL, 0, pk, 0);
print_fingerprint (ctrl, NULL, pk, 2);
tty_printf("\n");
@@ -834,7 +834,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name);
else
- rc = get_best_pubkey_byname (ctrl, NULL, pk, name, &keyblock, 0);
+ rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
+ NULL, pk, name, &keyblock, 0);
if (rc)
{
int code;
@@ -975,8 +976,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
r->pk = xmalloc_clear (sizeof *r->pk);
r->pk->req_usage = PUBKEY_USAGE_ENC;
- rc = get_pubkey_byname (ctrl, NULL, r->pk, default_key,
- NULL, NULL, 0, 1);
+ rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, r->pk, default_key, NULL, NULL, 0);
if (rc)
{
xfree (r->pk);
@@ -1041,8 +1042,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
/* We explicitly allow encrypt-to to an disabled key; thus
we pass 1 for the second last argument and 1 as the last
argument to disable AKL. */
- if ( (rc = get_pubkey_byname (ctrl,
- NULL, pk, rov->d, NULL, NULL, 1, 1)) )
+ if ((rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, pk, rov->d, NULL, NULL, 1)))
{
free_public_key ( pk ); pk = NULL;
log_error (_("%s: skipped: %s\n"), rov->d, gpg_strerror (rc) );
@@ -1179,7 +1180,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
free_public_key (pk);
pk = xmalloc_clear( sizeof *pk );
pk->req_usage = PUBKEY_USAGE_ENC;
- rc = get_pubkey_byname (ctrl, NULL, pk, answer, NULL, NULL, 0, 0 );
+ rc = get_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
+ NULL, pk, answer, NULL, NULL, 0);
if (rc)
tty_printf(_("No such user ID.\n"));
else if ( !(rc=openpgp_pk_test_algo2 (pk->pubkey_algo,
@@ -1257,7 +1259,8 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
/* The default recipient is allowed to be disabled; thus pass 1
as second last argument. We also don't want an AKL. */
- rc = get_pubkey_byname (ctrl, NULL, pk, def_rec, NULL, NULL, 1, 1);
+ rc = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, pk, def_rec, NULL, NULL, 1);
if (rc)
log_error(_("unknown default recipient \"%s\"\n"), def_rec );
else if ( !(rc=openpgp_pk_test_algo2(pk->pubkey_algo,
diff --git a/g10/plaintext.c b/g10/plaintext.c
index c5d1ddb7f..f9e0a4296 100644
--- a/g10/plaintext.c
+++ b/g10/plaintext.c
@@ -70,7 +70,8 @@ get_output_file (const byte *embedded_name, int embedded_namelen,
goto leave;
}
}
- else if (opt.outfile)
+ else if (opt.outfile
+ && !(opt.flags.use_embedded_filename && opt.flags.dummy_outfile))
{
fname = xtrystrdup (opt.outfile);
if (!fname)
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 055c39b8f..fb1b17143 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -75,25 +75,21 @@ gpg_error_t
get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
{
PKT_public_key *sk = NULL;
- int rc;
+ gpg_error_t err;
void *enum_context = NULL;
u32 keyid[2];
int search_for_secret_keys = 1;
+ struct pubkey_enc_list *k;
if (DBG_CLOCK)
log_clock ("get_session_key enter");
while (search_for_secret_keys)
{
- struct pubkey_enc_list *k;
-
sk = xmalloc_clear (sizeof *sk);
- rc = enum_secret_keys (ctrl, &enum_context, sk);
- if (rc)
- {
- rc = GPG_ERR_NO_SECKEY;
- break;
- }
+ err = enum_secret_keys (ctrl, &enum_context, sk);
+ if (err)
+ break;
if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
continue;
@@ -132,8 +128,6 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
if (openpgp_pk_test_algo2 (k->pubkey_algo, PUBKEY_USAGE_ENC))
continue;
- k->result = GPG_ERR_NO_SECKEY;
-
if (sk->pubkey_algo != k->pubkey_algo)
continue;
@@ -154,16 +148,16 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
else
continue;
- rc = get_it (ctrl, k, dek, sk, keyid);
- if (!rc)
+ err = get_it (ctrl, k, dek, sk, keyid);
+ k->result = err;
+ if (!err)
{
- k->result = 0;
if (!opt.quiet && !k->keyid[0] && !k->keyid[1])
log_info (_("okay, we are the anonymous recipient.\n"));
search_for_secret_keys = 0;
break;
}
- else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
+ else if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
{
search_for_secret_keys = 0;
break; /* Don't try any more secret keys. */
@@ -172,9 +166,19 @@ get_session_key (ctrl_t ctrl, struct pubkey_enc_list *list, DEK *dek)
}
enum_secret_keys (ctrl, &enum_context, NULL); /* free context */
+ if (gpg_err_code (err) == GPG_ERR_EOF)
+ {
+ err = gpg_error (GPG_ERR_NO_SECKEY);
+
+ /* Return the last specific error, if any. */
+ for (k = list; k; k = k->next)
+ if (k->result != -1)
+ err = k->result;
+ }
+
if (DBG_CLOCK)
log_clock ("get_session_key leave");
- return rc;
+ return err;
}
@@ -319,6 +323,16 @@ get_it (ctrl_t ctrl,
err = gpg_error (GPG_ERR_WRONG_SECKEY);
goto leave;
}
+
+ /* FIXME: Actually the leading zero is required but due to
+ * the way we encode the output in libgcrypt as an MPI we
+ * are not able to encode that leading zero. However, when
+ * using a Smartcard we are doing it the right way and
+ * therefore we have to skip the zero. This should be fixed
+ * in gpg-agent of course. */
+ if (!frame[n])
+ n++;
+
if (frame[n] == 1 && frame[nframe - 1] == 2)
{
log_info (_("old encoding of the DEK is not supported\n"));
diff --git a/g10/revoke.c b/g10/revoke.c
index e8ce3544c..0a93c31f9 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -305,11 +305,11 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
any = 1;
- print_pubkey_info (ctrl, NULL, pk);
+ print_key_info (ctrl, NULL, 0, pk, 0);
tty_printf ("\n");
tty_printf (_("To be revoked by:\n"));
- print_seckey_info (ctrl, pk2);
+ print_key_info (ctrl, NULL, 0, pk2, 1);
if(pk->revkey[i].class&0x40)
tty_printf(_("(This is a sensitive revocation key)\n"));
@@ -343,7 +343,7 @@ gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr)
push_armor_filter (afx, out);
/* create it */
- rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20, 0,
+ rc = make_keysig_packet (ctrl, &sig, pk, NULL, NULL, pk2, 0x20,
0, 0,
revocation_reason_build_cb, reason,
NULL);
@@ -474,7 +474,7 @@ create_revocation (ctrl_t ctrl,
afx->hdrlines = "Comment: This is a revocation certificate\n";
push_armor_filter (afx, out);
- rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20, 0,
+ rc = make_keysig_packet (ctrl, &sig, psk, NULL, NULL, psk, 0x20,
0, 0,
revocation_reason_build_cb, reason, cache_nonce);
if (rc)
@@ -669,30 +669,26 @@ gen_revoke (ctrl_t ctrl, const char *uname)
rc = keydb_search (kdbhd, &desc, 1, NULL);
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
- /* Not ambiguous. */
{
+ /* Not ambiguous. */
}
else if (rc == 0)
- /* Ambiguous. */
{
- char *info;
-
+ /* Ambiguous. */
/* TRANSLATORS: The %s prints a key specification which
for example has been given at the command line. Several lines
lines with secret key infos are printed after this message. */
log_error (_("'%s' matches multiple secret keys:\n"), uname);
- info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
- log_error (" %s\n", info);
- xfree (info);
+ print_key_info_log (ctrl, GPGRT_LOGLVL_ERROR, 2,
+ keyblock->pkt->pkt.public_key, 1);
release_kbnode (keyblock);
rc = keydb_get_keyblock (kdbhd, &keyblock);
while (! rc)
{
- info = format_seckey_info (ctrl, keyblock->pkt->pkt.public_key);
- log_info (" %s\n", info);
- xfree (info);
+ print_key_info_log (ctrl, GPGRT_LOGLVL_INFO, 2,
+ keyblock->pkt->pkt.public_key, 1);
release_kbnode (keyblock);
keyblock = NULL;
@@ -726,7 +722,7 @@ gen_revoke (ctrl_t ctrl, const char *uname)
}
keyid_from_pk (psk, keyid );
- print_seckey_info (ctrl, psk);
+ print_key_info (ctrl, NULL, 0, psk, 1);
tty_printf("\n");
if (!cpr_get_answer_is_yes ("gen_revoke.okay",
diff --git a/g10/sig-check.c b/g10/sig-check.c
index e7f97de65..4c172d692 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -1076,7 +1076,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
* signature packet's data structure.
*
* TODO: add r_revoked here as well. It has the same problems as
- * r_expiredate and r_expired and the cache. */
+ * r_expiredate and r_expired and the cache [nw]. Which problems [wk]? */
int
check_key_signature2 (ctrl_t ctrl,
kbnode_t root, kbnode_t node, PKT_public_key *check_pk,
diff --git a/g10/sign.c b/g10/sign.c
index 176940bff..d71580639 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1593,7 +1593,7 @@ make_keysig_packet (ctrl_t ctrl,
PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_public_key *pksk,
- int sigclass, int digest_algo,
+ int sigclass,
u32 timestamp, u32 duration,
int (*mksubpkt)(PKT_signature *, void *), void *opaque,
const char *cache_nonce)
@@ -1601,6 +1601,7 @@ make_keysig_packet (ctrl_t ctrl,
PKT_signature *sig;
int rc = 0;
int sigversion;
+ int digest_algo;
gcry_md_hd_t md;
log_assert ((sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F
@@ -1612,31 +1613,22 @@ make_keysig_packet (ctrl_t ctrl,
else
sigversion = 4;
- if (!digest_algo)
+ /* Select the digest algo to use. */
+ if (opt.cert_digest_algo) /* Forceful override by the user. */
+ digest_algo = opt.cert_digest_algo;
+ else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA) /* Meet DSA requirements. */
+ digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
+ else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA /* Meet ECDSA requirements. */
+ || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
{
- /* Basically, this means use SHA1 always unless the user
- * specified something (use whatever they said), or it's DSA
- * (use the best match). They still can't pick an inappropriate
- * hash for DSA or the signature will fail. Note that this
- * still allows the caller of make_keysig_packet to override the
- * user setting if it must. */
-
- if (opt.cert_digest_algo)
- digest_algo = opt.cert_digest_algo;
- else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA)
- digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
- else if (pksk->pubkey_algo == PUBKEY_ALGO_ECDSA
- || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
- {
- if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
- digest_algo = DIGEST_ALGO_SHA256;
- else
- digest_algo = match_dsa_hash
- (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
- }
+ if (openpgp_oid_is_ed25519 (pksk->pkey[0]))
+ digest_algo = DIGEST_ALGO_SHA256;
else
- digest_algo = DEFAULT_DIGEST_ALGO;
+ digest_algo = match_dsa_hash
+ (ecdsa_qbits_from_Q (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
}
+ else /* Use the default. */
+ digest_algo = DEFAULT_DIGEST_ALGO;
if (gcry_md_open (&md, digest_algo, 0))
BUG ();
@@ -1722,8 +1714,19 @@ update_keysig_packet (ctrl_t ctrl,
|| (orig_sig->sig_class == 0x18 && !subpk))
return GPG_ERR_GENERAL;
+ /* Either use the override digest algo or in the normal case the
+ * original digest algorithm. However, iff the original digest
+ * algorithms is SHA-1 and we are in gnupg or de-vs compliance mode
+ * we switch to SHA-256 (done by the macro). */
if (opt.cert_digest_algo)
digest_algo = opt.cert_digest_algo;
+ else if (pksk->pubkey_algo == PUBKEY_ALGO_DSA
+ || pksk->pubkey_algo == PUBKEY_ALGO_ECDSA
+ || pksk->pubkey_algo == PUBKEY_ALGO_EDDSA)
+ digest_algo = orig_sig->digest_algo;
+ else if (orig_sig->digest_algo == DIGEST_ALGO_SHA1
+ || orig_sig->digest_algo == DIGEST_ALGO_RMD160)
+ digest_algo = DEFAULT_DIGEST_ALGO;
else
digest_algo = orig_sig->digest_algo;
diff --git a/g10/skclist.c b/g10/skclist.c
index c9c41d0d9..c13566e2b 100644
--- a/g10/skclist.c
+++ b/g10/skclist.c
@@ -340,6 +340,10 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
SK_LIST results;
} *c = *context;
+#if MAX_FINGERPRINT_LEN < KEYGRIP_LEN
+# error buffer too short for this configuration
+#endif
+
if (!c)
{
/* Make a new context. */
@@ -423,23 +427,58 @@ enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
if (opt.verbose)
log_info (_("error getting serial number of card: %s\n"),
gpg_strerror (err));
+ c->sl = c->sl->next;
continue;
}
xfree (serialno);
c->info.fpr2len = 0;
err = agent_scd_getattr ("KEY-FPR", &c->info);
+ if (!err)
+ {
+ if (c->info.fpr2len)
+ {
+ c->fpr2[0] = '0';
+ c->fpr2[1] = 'x';
+ bin2hex (c->info.fpr2, sizeof c->info.fpr2,
+ c->fpr2 + 2);
+ name = c->fpr2;
+ }
+ }
+ else if (gpg_err_code (err) == GPG_ERR_INV_NAME)
+ {
+ /* KEY-FPR not supported by the card - get
+ * the key using the keygrip. */
+ char *keyref;
+ strlist_t kplist;
+ const char *s;
+ int i;
+
+ err = agent_scd_getattr_one ("$ENCRKEYID", &keyref);
+ if (!err)
+ {
+ err = agent_scd_keypairinfo (ctrl, keyref,
+ &kplist);
+ if (!err)
+ {
+ c->fpr2[0] = '&';
+ for (i=1, s=kplist->d;
+ (*s && *s != ' '
+ && i < sizeof c->fpr2 - 3);
+ s++, i++)
+ c->fpr2[i] = *s;
+ c->fpr2[i] = 0;
+ name = c->fpr2;
+ free_strlist (kplist);
+ }
+ xfree (keyref);
+ }
+ }
+
if (err)
- log_error ("error retrieving key fingerprint from card: %s\n",
+ log_error ("error retrieving key from card: %s\n",
gpg_strerror (err));
- if (c->info.fpr2len)
- {
- c->fpr2[0] = '0';
- c->fpr2[1] = 'x';
- bin2hex (c->info.fpr2, sizeof c->info.fpr2,c->fpr2+2);
- name = c->fpr2;
- }
c->sl = c->sl->next;
}
else
diff --git a/g10/tofu.c b/g10/tofu.c
index 44f354512..e78da15c1 100644
--- a/g10/tofu.c
+++ b/g10/tofu.c
@@ -534,7 +534,7 @@ check_utks (sqlite3 *db)
NULL, NULL, &err);
if (rc)
{
- log_error (_("error creating 'ultimately_trusted_keys' TOFU table: %s\n"),
+ log_error ("error creating 'ultimately_trusted_keys' TOFU table: %s\n",
err);
sqlite3_free (err);
goto out;
@@ -840,7 +840,7 @@ initdb (sqlite3 *db)
NULL, NULL, &err);
if (rc)
{
- log_error (_("error creating 'encryptions' TOFU table: %s\n"),
+ log_error ("error creating 'encryptions' TOFU table: %s\n",
err);
sqlite3_free (err);
}
@@ -870,7 +870,7 @@ initdb (sqlite3 *db)
* safely ignore. */
rc = 0;
else
- log_error (_("adding column effective_policy to bindings DB: %s\n"),
+ log_error ("adding column effective_policy to bindings DB: %s\n",
err);
sqlite3_free (err);
}
@@ -2146,8 +2146,7 @@ build_conflict_set (ctrl_t ctrl, tofu_dbs_t dbs,
rc = keydb_search_reset (hd);
if (rc)
{
- log_error (_("resetting keydb: %s\n"),
- gpg_strerror (rc));
+ log_error ("resetting keydb failed: %s\n", gpg_strerror (rc));
continue;
}
@@ -2614,8 +2613,8 @@ get_policy (ctrl_t ctrl, tofu_dbs_t dbs, PKT_public_key *pk,
if (record_binding (dbs, fingerprint, email, user_id,
policy == TOFU_POLICY_NONE ? TOFU_POLICY_AUTO : policy,
effective_policy, conflict, 1, 0, now) != 0)
- log_error (_("error setting TOFU binding's policy"
- " to %s\n"), tofu_policy_str (policy));
+ log_error ("error setting TOFU binding's policy"
+ " to %s\n", tofu_policy_str (policy));
}
/* If the caller wants the set of conflicts, return it. */
@@ -3152,14 +3151,10 @@ show_statistics (tofu_dbs_t dbs,
es_fprintf (fp, _("%s: Verified 0 signatures."), email);
else
{
- /* TRANSLATORS: The final %s is replaced by a string like
- "7~months". */
+ /* Note: Translation not possible with that wording. */
char *ago_str = time_ago_str (now - signature_first_seen);
es_fprintf
- (fp,
- ngettext("%s: Verified %ld~signature in the past %s.",
- "%s: Verified %ld~signatures in the past %s.",
- signature_count),
+ (fp, "%s: Verified %ld~signatures in the past %s.",
email, signature_count, ago_str);
xfree (ago_str);
}
@@ -3172,12 +3167,9 @@ show_statistics (tofu_dbs_t dbs,
{
char *ago_str = time_ago_str (now - encryption_first_done);
- /* TRANSLATORS: The final %s is replaced by a string like
- "7~months". */
- es_fprintf (fp,
- ngettext("Encrypted %ld~message in the past %s.",
- "Encrypted %ld~messages in the past %s.",
- encryption_count),
+ /* Note: Translation not possible with this kind of
+ * composition. */
+ es_fprintf (fp, "Encrypted %ld~messages in the past %s.",
encryption_count, ago_str);
xfree (ago_str);
}
@@ -3944,7 +3936,7 @@ tofu_set_policy (ctrl_t ctrl, kbnode_t kb, enum tofu_policy policy)
policy, TOFU_POLICY_NONE, NULL, 0, 1, now);
if (err)
{
- log_error (_("error setting policy for key %s, user id \"%s\": %s"),
+ log_error ("error setting policy for key %s, user id \"%s\": %s",
fingerprint, email, gpg_strerror (err));
xfree (email);
break;