aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--agent/agent.h4
-rw-r--r--agent/cache.c38
-rw-r--r--agent/command-ssh.c2
-rw-r--r--agent/command.c46
-rw-r--r--agent/cvt-openpgp.c2
-rw-r--r--agent/findkey.c8
-rw-r--r--agent/genkey.c6
-rw-r--r--agent/protect-tool.c3
-rw-r--r--common/agent-opt.c35
-rw-r--r--common/shareddefs.h13
-rw-r--r--configure.ac3
-rw-r--r--doc/Makefile.am2
-rw-r--r--doc/gpg-agent.texi21
-rw-r--r--doc/gpg.texi17
-rw-r--r--doc/gpgsm.texi9
-rw-r--r--g10/call-agent.c19
-rw-r--r--g10/call-agent.h1
-rw-r--r--g10/card-util.c132
-rw-r--r--g10/gpg.c8
-rw-r--r--g10/gpg.h4
-rw-r--r--g10/keyedit.c4
-rw-r--r--g10/misc.c1
-rw-r--r--g10/options.h1
-rw-r--r--g10/parse-packet.c17
-rw-r--r--g10/tdbdump.c2
-rw-r--r--g10/tdbio.c110
-rw-r--r--g10/tdbio.h6
-rw-r--r--g10/trustdb.c2
-rw-r--r--scd/apdu.c56
-rw-r--r--scd/app-openpgp.c5
-rw-r--r--scd/ccid-driver.c3
-rw-r--r--scd/scdaemon.c36
-rw-r--r--sm/call-agent.c14
-rw-r--r--sm/gpgsm.c8
-rw-r--r--sm/gpgsm.h1
-rw-r--r--sm/server.c12
36 files changed, 516 insertions, 135 deletions
diff --git a/agent/agent.h b/agent/agent.h
index 0d5cf4f1c..9fdbc76d3 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -453,9 +453,9 @@ void initialize_module_cache (void);
void deinitialize_module_cache (void);
void agent_cache_housekeeping (void);
void agent_flush_cache (void);
-int agent_put_cache (const char *key, cache_mode_t cache_mode,
+int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
const char *data, int ttl);
-char *agent_get_cache (const char *key, cache_mode_t cache_mode);
+char *agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode);
void agent_store_cache_hit (const char *key);
diff --git a/agent/cache.c b/agent/cache.c
index ed5c97cd2..238b6e214 100644
--- a/agent/cache.c
+++ b/agent/cache.c
@@ -58,6 +58,7 @@ struct cache_item_s {
int ttl; /* max. lifetime given in seconds, -1 one means infinite */
struct secret_data_s *pw;
cache_mode_t cache_mode;
+ int restricted; /* The value of ctrl->restricted is part of the key. */
char key[1];
};
@@ -202,8 +203,8 @@ housekeeping (void)
if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
{
if (DBG_CACHE)
- log_debug (" expired '%s' (%ds after last access)\n",
- r->key, r->ttl);
+ log_debug (" expired '%s'.%d (%ds after last access)\n",
+ r->key, r->restricted, r->ttl);
release_data (r->pw);
r->pw = NULL;
r->accessed = current;
@@ -224,8 +225,8 @@ housekeeping (void)
if (r->pw && r->created + maxttl < current)
{
if (DBG_CACHE)
- log_debug (" expired '%s' (%lus after creation)\n",
- r->key, opt.max_cache_ttl);
+ log_debug (" expired '%s'.%d (%lus after creation)\n",
+ r->key, r->restricted, opt.max_cache_ttl);
release_data (r->pw);
r->pw = NULL;
r->accessed = current;
@@ -233,15 +234,15 @@ housekeeping (void)
}
/* Third, make sure that we don't have too many items in the list.
- Expire old and unused entries after 30 minutes */
+ * Expire old and unused entries after 30 minutes. */
for (rprev=NULL, r=thecache; r; )
{
if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
{
ITEM r2 = r->next;
if (DBG_CACHE)
- log_debug (" removed '%s' (mode %d) (slot not used for 30m)\n",
- r->key, r->cache_mode);
+ log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
+ r->key, r->restricted, r->cache_mode);
xfree (r);
if (!rprev)
thecache = r2;
@@ -296,7 +297,7 @@ agent_flush_cache (void)
if (r->pw)
{
if (DBG_CACHE)
- log_debug (" flushing '%s'\n", r->key);
+ log_debug (" flushing '%s'.%d\n", r->key, r->restricted);
release_data (r->pw);
r->pw = NULL;
r->accessed = 0;
@@ -326,20 +327,21 @@ cache_mode_equal (cache_mode_t a, cache_mode_t b)
set infinite timeout. CACHE_MODE is stored with the cache entry
and used to select different timeouts. */
int
-agent_put_cache (const char *key, cache_mode_t cache_mode,
+agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
const char *data, int ttl)
{
gpg_error_t err = 0;
ITEM r;
int res;
+ int restricted = ctrl? ctrl->restricted : -1;
res = npth_mutex_lock (&cache_lock);
if (res)
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
if (DBG_CACHE)
- log_debug ("agent_put_cache '%s' (mode %d) requested ttl=%d\n",
- key, cache_mode, ttl);
+ log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n",
+ key, restricted, cache_mode, ttl);
housekeeping ();
if (!ttl)
@@ -358,6 +360,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
if (((cache_mode != CACHE_MODE_USER
&& cache_mode != CACHE_MODE_NONCE)
|| cache_mode_equal (r->cache_mode, cache_mode))
+ && r->restricted == restricted
&& !strcmp (r->key, key))
break;
}
@@ -386,6 +389,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
else
{
strcpy (r->key, key);
+ r->restricted = restricted;
r->created = r->accessed = gnupg_get_time ();
r->ttl = ttl;
r->cache_mode = cache_mode;
@@ -415,13 +419,14 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
make use of CACHE_MODE except for CACHE_MODE_NONCE and
CACHE_MODE_USER. */
char *
-agent_get_cache (const char *key, cache_mode_t cache_mode)
+agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
{
gpg_error_t err;
ITEM r;
char *value = NULL;
int res;
int last_stored = 0;
+ int restricted = ctrl? ctrl->restricted : -1;
if (cache_mode == CACHE_MODE_IGNORE)
return NULL;
@@ -439,8 +444,8 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
}
if (DBG_CACHE)
- log_debug ("agent_get_cache '%s' (mode %d)%s ...\n",
- key, cache_mode,
+ log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n",
+ key, ctrl->restricted, cache_mode,
last_stored? " (stored cache key)":"");
housekeeping ();
@@ -450,6 +455,7 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
&& ((cache_mode != CACHE_MODE_USER
&& cache_mode != CACHE_MODE_NONCE)
|| cache_mode_equal (r->cache_mode, cache_mode))
+ && r->restricted == restricted
&& !strcmp (r->key, key))
{
/* Note: To avoid races KEY may not be accessed anymore below. */
@@ -472,8 +478,8 @@ agent_get_cache (const char *key, cache_mode_t cache_mode)
{
xfree (value);
value = NULL;
- log_error ("retrieving cache entry '%s' failed: %s\n",
- key, gpg_strerror (err));
+ log_error ("retrieving cache entry '%s'.%d failed: %s\n",
+ key, restricted, gpg_strerror (err));
}
break;
}
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 715544635..38934f450 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -3145,7 +3145,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
goto out;
/* Cache this passphrase. */
- err = agent_put_cache (key_grip, CACHE_MODE_SSH, pi->pin, ttl);
+ err = agent_put_cache (ctrl, key_grip, CACHE_MODE_SSH, pi->pin, ttl);
if (err)
goto out;
diff --git a/agent/command.c b/agent/command.c
index e2486a556..a5baf4d9a 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -199,14 +199,14 @@ clear_nonce_cache (ctrl_t ctrl)
{
if (ctrl->server_local->last_cache_nonce)
{
- agent_put_cache (ctrl->server_local->last_cache_nonce,
+ agent_put_cache (ctrl, ctrl->server_local->last_cache_nonce,
CACHE_MODE_NONCE, NULL, 0);
xfree (ctrl->server_local->last_cache_nonce);
ctrl->server_local->last_cache_nonce = NULL;
}
if (ctrl->server_local->last_passwd_nonce)
{
- agent_put_cache (ctrl->server_local->last_passwd_nonce,
+ agent_put_cache (ctrl, ctrl->server_local->last_passwd_nonce,
CACHE_MODE_NONCE, NULL, 0);
xfree (ctrl->server_local->last_passwd_nonce);
ctrl->server_local->last_passwd_nonce = NULL;
@@ -930,7 +930,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
}
else if (passwd_nonce)
- newpasswd = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
+ newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
rc = agent_genkey (ctrl, cache_nonce, (char*)value, valuelen, no_protection,
newpasswd, opt_preset, &outbuf);
@@ -1179,7 +1179,7 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
/* Here we have a little race by doing the cache check separately
from the retrieval function. Given that the cache flag is only a
hint, it should not really matter. */
- pw = agent_get_cache (hexgrip, CACHE_MODE_NORMAL);
+ pw = agent_get_cache (ctrl, hexgrip, CACHE_MODE_NORMAL);
cached = pw ? "1" : "-";
xfree (pw);
@@ -1484,7 +1484,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
if (!strcmp (desc, "X"))
desc = NULL;
- pw = cacheid ? agent_get_cache (cacheid, CACHE_MODE_USER) : NULL;
+ pw = cacheid ? agent_get_cache (ctrl, cacheid, CACHE_MODE_USER) : NULL;
if (pw)
{
rc = send_back_passphrase (ctx, opt_data, pw);
@@ -1551,7 +1551,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
if (!rc)
{
if (cacheid)
- agent_put_cache (cacheid, CACHE_MODE_USER, response, 0);
+ agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0);
rc = send_back_passphrase (ctx, opt_data, response);
}
xfree (response);
@@ -1593,7 +1593,8 @@ cmd_clear_passphrase (assuan_context_t ctx, char *line)
if (!*cacheid || strlen (cacheid) > 50)
return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
- agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
+ agent_put_cache (ctrl, cacheid,
+ opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
NULL, 0);
agent_clear_passphrase (ctrl, cacheid,
@@ -1770,7 +1771,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
passwd_nonce = bin2hex (buf, 12, NULL);
}
if (passwd_nonce
- && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
+ && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE))
{
assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
@@ -1785,7 +1786,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
char *newpass = NULL;
if (passwd_nonce)
- newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
+ newpass = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
err = agent_protect_and_store (ctrl, s_skey, &newpass);
if (!err && passphrase)
{
@@ -1800,7 +1801,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
cache_nonce = bin2hex (buf, 12, NULL);
}
if (cache_nonce
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+ && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE))
{
assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
@@ -1820,7 +1821,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
passwd_nonce = bin2hex (buf, 12, NULL);
}
if (passwd_nonce
- && !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
+ && !agent_put_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE,
newpass, CACHE_TTL_NONCE))
{
assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
@@ -1834,7 +1835,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
{
char hexgrip[40+1];
bin2hex(grip, 20, hexgrip);
- err = agent_put_cache (hexgrip, CACHE_MODE_ANY, newpass,
+ err = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, newpass,
ctrl->cache_ttl_opt_preset);
}
xfree (newpass);
@@ -1939,7 +1940,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
if (!rc)
{
- rc = agent_put_cache (grip_clear, CACHE_MODE_ANY, passphrase, ttl);
+ rc = agent_put_cache (ctrl, grip_clear, CACHE_MODE_ANY, passphrase, ttl);
if (opt_inquire)
xfree (passphrase);
}
@@ -2174,7 +2175,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
cache_nonce = bin2hex (buf, 12, NULL);
}
if (cache_nonce
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+ && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE))
assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
}
@@ -2336,7 +2337,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
cache_nonce = bin2hex (buf, 12, NULL);
}
if (cache_nonce
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+ && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, CACHE_TTL_NONCE))
{
assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
@@ -3101,6 +3102,21 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->s2k_count = 0;
}
}
+ else if (!strcmp (key, "pretend-request-origin"))
+ {
+ log_assert (!ctrl->restricted);
+ switch (parse_request_origin (value))
+ {
+ case REQUEST_ORIGIN_LOCAL: ctrl->restricted = 0; break;
+ case REQUEST_ORIGIN_REMOTE: ctrl->restricted = 1; break;
+ case REQUEST_ORIGIN_BROWSER: ctrl->restricted = 2; break;
+ default:
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ /* Better pretend to be remote in case of a bad value. */
+ ctrl->restricted = 1;
+ break;
+ }
+ }
else
err = gpg_error (GPG_ERR_UNKNOWN_OPTION);
diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c
index c4d0334c6..06cd1c840 100644
--- a/agent/cvt-openpgp.c
+++ b/agent/cvt-openpgp.c
@@ -951,7 +951,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
{
char *cache_value;
- cache_value = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
+ cache_value = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE);
if (cache_value)
{
if (strlen (cache_value) < pi->max_length)
diff --git a/agent/findkey.c b/agent/findkey.c
index e3e9a123f..78c3b1a47 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -511,7 +511,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
{
char *pw;
- pw = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
+ pw = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE);
if (pw)
{
rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
@@ -536,7 +536,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
char *pw;
retry:
- pw = agent_get_cache (hexgrip, cache_mode);
+ pw = agent_get_cache (ctrl, hexgrip, cache_mode);
if (pw)
{
rc = agent_unprotect (ctrl, *keybuf, pw, NULL, &result, &resultlen);
@@ -574,7 +574,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
We can often avoid the passphrase entry in the second
step. We do this only in normal mode, so not to
interfere with unrelated cache entries. */
- pw = agent_get_cache (NULL, cache_mode);
+ pw = agent_get_cache (ctrl, NULL, cache_mode);
if (pw)
{
rc = agent_unprotect (ctrl, *keybuf, pw, NULL,
@@ -670,7 +670,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
else
{
/* Passphrase is fine. */
- agent_put_cache (hexgrip, cache_mode, pi->pin,
+ agent_put_cache (ctrl, hexgrip, cache_mode, pi->pin,
lookup_ttl? lookup_ttl (hexgrip) : 0);
agent_store_cache_hit (hexgrip);
if (r_passphrase && *pi->pin)
diff --git a/agent/genkey.c b/agent/genkey.c
index a3e37ee3a..d5c80d0aa 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -468,7 +468,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
passphrase = NULL;
else
{
- passphrase_buffer = agent_get_cache (cache_nonce, CACHE_MODE_NONCE);
+ passphrase_buffer = agent_get_cache (ctrl, cache_nonce, CACHE_MODE_NONCE);
passphrase = passphrase_buffer;
}
@@ -528,7 +528,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
}
if (cache_nonce
&& !no_protection
- && !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
+ && !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, ctrl->cache_ttl_opt_preset))
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
if (preset && !no_protection)
@@ -538,7 +538,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
if (gcry_pk_get_keygrip (s_private, grip))
{
bin2hex(grip, 20, hexgrip);
- rc = agent_put_cache (hexgrip, CACHE_MODE_ANY, passphrase,
+ rc = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, passphrase,
ctrl->cache_ttl_opt_preset);
}
}
diff --git a/agent/protect-tool.c b/agent/protect-tool.c
index a193e4969..ec7b47695 100644
--- a/agent/protect-tool.c
+++ b/agent/protect-tool.c
@@ -749,8 +749,9 @@ agent_key_available (const unsigned char *grip)
}
char *
-agent_get_cache (const char *key, cache_mode_t cache_mode)
+agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
{
+ (void)ctrl;
(void)key;
(void)cache_mode;
return NULL;
diff --git a/common/agent-opt.c b/common/agent-opt.c
index b32448242..6d9f9e77e 100644
--- a/common/agent-opt.c
+++ b/common/agent-opt.c
@@ -69,3 +69,38 @@ str_pinentry_mode (pinentry_mode_t mode)
}
return "?";
}
+
+
+/* Parse VALUE and return an integer representing a request_origin_t.
+ * (-1) is returned for an invalid VALUE. */
+int
+parse_request_origin (const char *value)
+{
+ int result;
+
+ if (!strcmp (value, "none") || !strcmp (value, "local"))
+ result = REQUEST_ORIGIN_LOCAL;
+ else if (!strcmp (value, "remote"))
+ result = REQUEST_ORIGIN_REMOTE;
+ else if (!strcmp (value, "browser"))
+ result = REQUEST_ORIGIN_BROWSER;
+ else
+ result = -1;
+
+ return result;
+}
+
+
+/* Return the string representation for the request origin. Returns
+ * "?" for an invalid mode. */
+const char *
+str_request_origin (request_origin_t mode)
+{
+ switch (mode)
+ {
+ case REQUEST_ORIGIN_LOCAL: return "local";
+ case REQUEST_ORIGIN_REMOTE: return "remote";
+ case REQUEST_ORIGIN_BROWSER: return "browser";
+ }
+ return "?";
+}
diff --git a/common/shareddefs.h b/common/shareddefs.h
index 1594f6650..4b1442133 100644
--- a/common/shareddefs.h
+++ b/common/shareddefs.h
@@ -39,10 +39,23 @@ typedef enum
pinentry_mode_t;
+/* Values for the request origin. */
+typedef enum
+ {
+ REQUEST_ORIGIN_LOCAL = 0,
+ REQUEST_ORIGIN_REMOTE,
+ REQUEST_ORIGIN_BROWSER
+ }
+request_origin_t;
+
+
/*-- agent-opt.c --*/
int parse_pinentry_mode (const char *value);
const char *str_pinentry_mode (pinentry_mode_t mode);
+int parse_request_origin (const char *value);
+const char *str_request_origin (request_origin_t mode);
+
#endif /*GNUPG_COMMON_SHAREDDEFS_H*/
diff --git a/configure.ac b/configure.ac
index 7522b6922..3096aeecb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -650,7 +650,7 @@ have_android_system=no
use_simple_gettext=no
use_ldapwrapper=yes
mmap_needed=yes
-require_pipe_to_unblock_pselect=no
+require_pipe_to_unblock_pselect=yes
case "${host}" in
*-mingw32*)
# special stuff for Windoze NT
@@ -665,6 +665,7 @@ case "${host}" in
have_w32_system=yes
require_iconv=no
use_ldapwrapper=no # Fixme: Do this only for CE.
+ require_pipe_to_unblock_pselect=no
case "${host}" in
*-mingw32ce*)
have_w32ce_system=yes
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 21e3e4578..aa16b7796 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -85,7 +85,7 @@ DVIPS = TEXINPUTS="$(srcdir)$(PATH_SEPARATOR)$$TEXINPUTS" dvips
AM_MAKEINFOFLAGS = -I $(srcdir) --css-ref=/share/site.css
YAT2M_OPTIONS = -I $(srcdir) \
- --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.1"
+ --release "GnuPG @PACKAGE_VERSION@" --source "GNU Privacy Guard 2.2"
myman_sources = gnupg7.texi gpg.texi gpgsm.texi gpg-agent.texi \
dirmngr.texi scdaemon.texi tools.texi wks.texi
diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi
index 4781bbdca..bcce03329 100644
--- a/doc/gpg-agent.texi
+++ b/doc/gpg-agent.texi
@@ -1581,6 +1581,27 @@ option is valid for the entire session or until reset to 0. This
option is useful if the key is later used on boxes which are either
much slower or faster than the actual box.
+@item pretend-request-origin
+This option switches the connection into a restricted mode which
+handles all further commands in the same way as they would be handled
+when originating from the extra or browser socket. Note that this
+option is not available in the restricted mode. Valid values for this
+option are:
+
+ @table @code
+ @item none
+ @itemx local
+ This is a NOP and leaves the connection in the standard way.
+
+ @item remote
+ Pretend to come from a remote origin in the same way as connections
+ from the @option{--extra-socket}.
+
+ @item browser
+ Pretend to come from a local web browser in the same way as connections
+ from the @option{--browser-socket}.
+ @end table
+
@end table
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 8fea489f0..e32974b46 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -1126,7 +1126,9 @@ all affected self-signatures is set one second ahead.
@opindex passwd
Change the passphrase of the secret key belonging to the certificate
specified as @var{user-id}. This is a shortcut for the sub-command
-@code{passwd} of the edit key menu.
+@code{passwd} of the edit key menu. When using together with the
+option @option{--dry-run} this will not actually change the passphrase
+but check that the current passphrase is correct.
@end table
@@ -2213,8 +2215,8 @@ handy in case where an encrypted message contains a bogus key ID.
@opindex skip-hidden-recipients
@opindex no-skip-hidden-recipients
During decryption skip all anonymous recipients. This option helps in
-the case that people use the hidden recipients feature to hide there
-own encrypt-to key from others. If oneself has many secret keys this
+the case that people use the hidden recipients feature to hide their
+own encrypt-to key from others. If one has many secret keys this
may lead to a major annoyance because all keys are tried in turn to
decrypt something which was not really intended for it. The drawback
of this option is that it is currently not possible to decrypt a
@@ -3177,6 +3179,15 @@ are:
Pinentry the user is not prompted again if he enters a bad password.
@end table
+@item --request-origin @var{origin}
+@opindex request-origin
+Tell gpg to assume that the operation ultimately originated at
+@var{origin}. Depending on the origin certain restrictions are applied
+and the Pinentry may include an extra note on the origin. Supported
+values for @var{origin} are: @code{local} which is the default,
+@code{remote} to indicate a remote origin or @code{browser} for an
+operation requested by a web browser.
+
@item --command-fd @var{n}
@opindex command-fd
This is a replacement for the deprecated shared-memory IPC mode.
diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi
index 93ae56efe..1736ff111 100644
--- a/doc/gpgsm.texi
+++ b/doc/gpgsm.texi
@@ -765,6 +765,15 @@ are:
Pinentry the user is not prompted again if he enters a bad password.
@end table
+@item --request-origin @var{origin}
+@opindex request-origin
+Tell gpgsm to assume that the operation ultimately originated at
+@var{origin}. Depending on the origin certain restrictions are applied
+and the Pinentry may include an extra note on the origin. Supported
+values for @var{origin} are: @code{local} which is the default,
+@code{remote} to indicate a remote origin or @code{browser} for an
+operation requested by a web browser.
+
@item --no-common-certs-import
@opindex no-common-certs-import
Suppress the import of common certificates on keybox creation.
diff --git a/g10/call-agent.c b/g10/call-agent.c
index b1f589bbc..1445f4e44 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -289,6 +289,23 @@ start_agent (ctrl_t ctrl, int flag_for_card)
}
}
+ /* Pass on the request origin. */
+ if (opt.request_origin)
+ {
+ char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
+ str_request_origin (opt.request_origin));
+ rc = assuan_transact (agent_ctx, tmp,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ xfree (tmp);
+ if (rc)
+ {
+ log_error ("setting request origin '%s' failed: %s\n",
+ str_request_origin (opt.request_origin),
+ gpg_strerror (rc));
+ write_status_error ("set_request_origin", rc);
+ }
+ }
+
/* In DE_VS mode under Windows we require that the JENT RNG
* is active. */
#ifdef HAVE_W32_SYSTEM
@@ -591,6 +608,8 @@ learn_status_cb (void *opaque, const char *line)
parm->extcap.ki = abool;
else if (!strcmp (p, "aac"))
parm->extcap.aac = abool;
+ else if (!strcmp (p, "kdf"))
+ parm->extcap.kdf = abool;
else if (!strcmp (p, "si"))
parm->status_indicator = strtoul (p2, NULL, 10);
}
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 53775c5c8..8de0d13fd 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -67,6 +67,7 @@ struct agent_card_info_s
struct {
unsigned int ki:1; /* Key import available. */
unsigned int aac:1; /* Algorithm attributes are changeable. */
+ unsigned int kdf:1; /* KDF object to support PIN hashing available. */
} extcap;
unsigned int status_indicator;
};
diff --git a/g10/card-util.c b/g10/card-util.c
index f8a1bb831..9b99751ee 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -659,7 +659,7 @@ current_card_status (ctrl_t ctrl, estream_t fp,
/* Print all available information for specific card with SERIALNO.
Print all available information for current card when SERIALNO is NULL.
- Or print llfor all cards when SERIALNO is "all". */
+ Or print for all cards when SERIALNO is "all". */
void
card_status (ctrl_t ctrl, estream_t fp, const char *serialno)
{
@@ -1797,6 +1797,7 @@ factory_reset (void)
scd apdu 00 20 00 83 08 40 40 40 40 40 40 40 40
scd apdu 00 e6 00 00
scd apdu 00 44 00 00
+ scd reset
/echo Card has been reset to factory defaults
but tries to find out something about the card first.
@@ -1809,7 +1810,7 @@ factory_reset (void)
else if (err)
{
log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err));
- return;
+ goto leave;
}
if (!termstate)
@@ -1859,10 +1860,16 @@ factory_reset (void)
command because there is no machinery in scdaemon to catch
the verify command and ask for the PIN when the "APDU"
command is used. */
+ /* Here, the length of dummy wrong PIN is 32-byte, also
+ supporting authentication with KDF DO. */
for (i=0; i < 4; i++)
- send_apdu ("00200081084040404040404040", "VERIFY", 0xffff);
+ send_apdu ("0020008120"
+ "40404040404040404040404040404040"
+ "40404040404040404040404040404040", "VERIFY", 0xffff);
for (i=0; i < 4; i++)
- send_apdu ("00200083084040404040404040", "VERIFY", 0xffff);
+ send_apdu ("0020008320"
+ "40404040404040404040404040404040"
+ "40404040404040404040404040404040", "VERIFY", 0xffff);
/* Send terminate datafile command. */
err = send_apdu ("00e60000", "TERMINATE DF", 0x6985);
@@ -1878,8 +1885,16 @@ factory_reset (void)
/* Finally we reset the card reader once more. */
err = send_apdu (NULL, "RESET", 0);
- if (err)
- goto leave;
+
+ /* Then, connect the card again. */
+ if (!err)
+ {
+ char *serialno0;
+
+ err = agent_scd_serialno (&serialno0, NULL);
+ if (!err)
+ xfree (serialno0);
+ }
leave:
xfree (answer);
@@ -1887,6 +1902,104 @@ factory_reset (void)
}
+#define USER_PIN_DEFAULT "123456"
+#define ADMIN_PIN_DEFAULT "12345678"
+#define KDF_DATA_LENGTH 110
+
+/* Generate KDF data. */
+static gpg_error_t
+gen_kdf_data (unsigned char *data)
+{
+ const unsigned char h0[] = { 0x81, 0x01, 0x03,
+ 0x82, 0x01, 0x08,
+ 0x83, 0x04 };
+ const unsigned char h1[] = { 0x84, 0x08 };
+ const unsigned char h2[] = { 0x85, 0x08 };
+ const unsigned char h3[] = { 0x86, 0x08 };
+ const unsigned char h4[] = { 0x87, 0x20 };
+ const unsigned char h5[] = { 0x88, 0x20 };
+ unsigned char *p, *salt_user, *salt_admin;
+ unsigned char s2k_char;
+ unsigned int iterations;
+ unsigned char count_4byte[4];
+ gpg_error_t err = 0;
+
+ p = data;
+
+ s2k_char = encode_s2k_iterations (0);
+ iterations = S2K_DECODE_COUNT (s2k_char);
+ count_4byte[0] = (iterations >> 24) & 0xff;
+ count_4byte[1] = (iterations >> 16) & 0xff;
+ count_4byte[2] = (iterations >> 8) & 0xff;
+ count_4byte[3] = (iterations & 0xff);
+
+ memcpy (p, h0, sizeof h0);
+ p += sizeof h0;
+ memcpy (p, count_4byte, sizeof count_4byte);
+ p += sizeof count_4byte;
+ memcpy (p, h1, sizeof h1);
+ salt_user = (p += sizeof h1);
+ gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+ p += 8;
+ memcpy (p, h2, sizeof h2);
+ p += sizeof h2;
+ gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+ p += 8;
+ memcpy (p, h3, sizeof h3);
+ salt_admin = (p += sizeof h3);
+ gcry_randomize (p, 8, GCRY_STRONG_RANDOM);
+ p += 8;
+ memcpy (p, h4, sizeof h4);
+ p += sizeof h4;
+ err = gcry_kdf_derive (USER_PIN_DEFAULT, strlen (USER_PIN_DEFAULT),
+ GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
+ salt_user, 8, iterations, 32, p);
+ p += 32;
+ if (!err)
+ {
+ memcpy (p, h5, sizeof h5);
+ p += sizeof h5;
+ err = gcry_kdf_derive (ADMIN_PIN_DEFAULT, strlen (ADMIN_PIN_DEFAULT),
+ GCRY_KDF_ITERSALTED_S2K, DIGEST_ALGO_SHA256,
+ salt_admin, 8, iterations, 32, p);
+ }
+
+ return err;
+}
+
+/* Setup KDF data object which is used for PIN authentication. */
+static void
+kdf_setup (void)
+{
+ struct agent_card_info_s info;
+ gpg_error_t err;
+ unsigned char kdf_data[KDF_DATA_LENGTH];
+
+ memset (&info, 0, sizeof info);
+
+ err = agent_scd_getattr ("EXTCAP", &info);
+ if (err)
+ {
+ log_error (_("error getting card info: %s\n"), gpg_strerror (err));
+ return;
+ }
+
+ if (!info.extcap.kdf)
+ {
+ log_error (_("This command is not supported by this card\n"));
+ goto leave;
+ }
+
+ if (!(err = gen_kdf_data (kdf_data))
+ && !(err = agent_scd_setattr ("KDF", kdf_data, KDF_DATA_LENGTH, NULL)))
+ err = agent_scd_getattr ("KDF", &info);
+
+ if (err)
+ log_error (_("error for setup KDF: %s\n"), gpg_strerror (err));
+
+ leave:
+ agent_release_card_info (&info);
+}
/* Data used by the command parser. This needs to be outside of the
function scope to allow readline based command completion. */
@@ -1896,7 +2009,7 @@ enum cmdids
cmdQUIT, cmdADMIN, cmdHELP, cmdLIST, cmdDEBUG, cmdVERIFY,
cmdNAME, cmdURL, cmdFETCH, cmdLOGIN, cmdLANG, cmdSEX, cmdCAFPR,
cmdFORCESIG, cmdGENERATE, cmdPASSWD, cmdPRIVATEDO, cmdWRITECERT,
- cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET,
+ cmdREADCERT, cmdUNBLOCK, cmdFACTORYRESET, cmdKDFSETUP,
cmdINVCMD
};
@@ -1930,6 +2043,7 @@ static struct
{ "verify" , cmdVERIFY, 0, N_("verify the PIN and list all data")},
{ "unblock" , cmdUNBLOCK,0, N_("unblock the PIN using a Reset Code") },
{ "factory-reset", cmdFACTORYRESET, 1, N_("destroy all keys and data")},
+ { "kdf-setup", cmdKDFSETUP, 1, N_("setup KDF for PIN authentication")},
/* Note, that we do not announce these command yet. */
{ "privatedo", cmdPRIVATEDO, 0, NULL },
{ "readcert", cmdREADCERT, 0, NULL },
@@ -2213,6 +2327,10 @@ card_edit (ctrl_t ctrl, strlist_t commands)
factory_reset ();
break;
+ case cmdKDFSETUP:
+ kdf_setup ();
+ break;
+
case cmdQUIT:
goto leave;
diff --git a/g10/gpg.c b/g10/gpg.c
index cbac967d8..277b5dbbb 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -428,6 +428,7 @@ enum cmd_and_opt_values
oDisableSignerUID,
oSender,
oKeyOrigin,
+ oRequestOrigin,
oNoop
};
@@ -719,6 +720,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"),
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
+ ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"),
ARGPARSE_s_i (oCommandFD, "command-fd", "@"),
ARGPARSE_s_s (oCommandFile, "command-file", "@"),
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@@ -3158,6 +3160,12 @@ main (int argc, char **argv)
log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
break;
+ case oRequestOrigin:
+ opt.request_origin = parse_request_origin (pargs.r.ret_str);
+ if (opt.request_origin == -1)
+ log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
+ break;
+
case oCommandFD:
opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0);
if (! gnupg_fd_valid (opt.command_fd))
diff --git a/g10/gpg.h b/g10/gpg.h
index 03fe384aa..28a77b6df 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -24,6 +24,10 @@
correct value and may be of advantage if we ever have to do
special things. */
+#ifdef HAVE_W32_SYSTEM
+# define WIN32_LEAN_AND_MEAN 1
+#endif
+
#ifdef GPG_ERR_SOURCE_DEFAULT
#error GPG_ERR_SOURCE_DEFAULT already defined
#endif
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 2c33a29dd..2cb9bb2ff 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1134,8 +1134,10 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
if (err)
goto leave;
+ /* Note that when using --dry-run we don't change the
+ * passphrase but merely verify the current passphrase. */
desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_NORMAL, 1);
- err = agent_passwd (ctrl, hexgrip, desc, 0,
+ err = agent_passwd (ctrl, hexgrip, desc, !!opt.dry_run,
&cache_nonce, &passwd_nonce);
xfree (desc);
diff --git a/g10/misc.c b/g10/misc.c
index 8c54793ed..1e6df5f67 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -42,6 +42,7 @@
#include <time.h>
#include <process.h>
#ifdef HAVE_WINSOCK2_H
+# define WIN32_LEAN_AND_MEAN 1
# include <winsock2.h>
#endif
#include <windows.h>
diff --git a/g10/options.h b/g10/options.h
index 471aee7f4..f186225c6 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -278,6 +278,7 @@ struct
int passphrase_repeat;
int pinentry_mode;
+ int request_origin;
int unwrap_encryption;
int only_sign_text_ids;
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index e3ff4321e..e933abfa0 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -971,10 +971,10 @@ skip_packet (IOBUF inp, int pkttype, unsigned long pktlen, int partial)
}
-/* Read PKTLEN bytes form INP and return them in a newly allocated
- buffer. In case of an error (including reading fewer than PKTLEN
- bytes from INP before EOF is returned), NULL is returned and an
- error message is logged. */
+/* Read PKTLEN bytes from INP and return them in a newly allocated
+ * buffer. In case of an error (including reading fewer than PKTLEN
+ * bytes from INP before EOF is returned), NULL is returned and an
+ * error message is logged. */
static void *
read_rest (IOBUF inp, size_t pktlen)
{
@@ -1741,6 +1741,8 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
}
if (buflen < n)
goto too_short;
+ if (!buflen)
+ goto no_type_byte;
type = *buffer;
if (type & 0x80)
{
@@ -1815,6 +1817,13 @@ enum_sig_subpkt (const subpktarea_t * pktbuf, sigsubpkttype_t reqtype,
if (start)
*start = -1;
return NULL;
+
+ no_type_byte:
+ if (opt.verbose)
+ log_info ("type octet missing in subpacket\n");
+ if (start)
+ *start = -1;
+ return NULL;
}
diff --git a/g10/tdbdump.c b/g10/tdbdump.c
index 37bf78b80..73a6c2c57 100644
--- a/g10/tdbdump.c
+++ b/g10/tdbdump.c
@@ -191,7 +191,7 @@ import_ownertrust (ctrl_t ctrl, const char *fname )
while (fprlen < MAX_FINGERPRINT_LEN)
fpr[fprlen++] = 0;
- rc = tdbio_search_trust_byfpr (fpr, &rec);
+ rc = tdbio_search_trust_byfpr (ctrl, fpr, &rec);
if( !rc ) { /* found: update */
if (rec.r.trust.ownertrust != otrust)
{
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 7572b9aeb..fed0cf5ab 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -105,16 +105,17 @@ struct cmp_xdir_struct
/* The name of the trustdb file. */
static char *db_name;
-/* The handle for locking the trustdb file and a flag to record
- whether a lock has been taken. */
+/* The handle for locking the trustdb file and a counter to record how
+ * often this lock has been taken. That counter is required becuase
+ * dotlock does not implemen recursive locks. */
static dotlock_t lockhandle;
-static int is_locked;
+static unsigned int is_locked;
/* The file descriptor of the trustdb. */
static int db_fd = -1;
/* A flag indicating that a transaction is active. */
-static int in_transaction;
+/* static int in_transaction; Not yet used. */
@@ -125,7 +126,7 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type);
/*
* Take a lock on the trustdb file name. I a lock file can't be
- * created the function terminates the process. Excvept for a
+ * created the function terminates the process. Except for a
* different return code the function does nothing if the lock has
* already been taken.
*
@@ -135,6 +136,8 @@ static void create_hashtable (ctrl_t ctrl, TRUSTREC *vr, int type);
static int
take_write_lock (void)
{
+ int rc;
+
if (!lockhandle)
lockhandle = dotlock_create (db_name, 0);
if (!lockhandle)
@@ -144,12 +147,16 @@ take_write_lock (void)
{
if (dotlock_take (lockhandle, -1) )
log_fatal ( _("can't lock '%s'\n"), db_name );
- else
- is_locked = 1;
- return 0;
+ rc = 0;
}
else
- return 1;
+ rc = 1;
+
+ if (opt.lock_once)
+ is_locked = 1;
+ else
+ is_locked++;
+ return rc;
}
@@ -160,10 +167,22 @@ take_write_lock (void)
static void
release_write_lock (void)
{
- if (!opt.lock_once)
- if (!dotlock_release (lockhandle))
- is_locked = 0;
+ if (opt.lock_once)
+ return; /* Don't care; here IS_LOCKED is fixed to 1. */
+
+ if (!is_locked)
+ {
+ log_error ("Ooops, tdbio:release_write_lock with no lock held\n");
+ return;
+ }
+ if (--is_locked)
+ return;
+
+ if (dotlock_release (lockhandle))
+ log_error ("Oops, tdbio:release_write_locked failed\n");
}
+
+
/*************************************
************* record cache **********
@@ -329,6 +348,7 @@ put_record_into_cache (ulong recno, const char *data)
}
/* No clean entries: We have to flush some dirty entries. */
+#if 0 /* Transactions are not yet used. */
if (in_transaction)
{
/* But we can't do this while in a transaction. Thus we
@@ -352,6 +372,7 @@ put_record_into_cache (ulong recno, const char *data)
log_info (_("trustdb transaction too large\n"));
return GPG_ERR_RESOURCE_LIMIT;
}
+#endif
if (dirty_count)
{
@@ -418,8 +439,10 @@ tdbio_sync()
if( db_fd == -1 )
open_db();
+#if 0 /* Transactions are not yet used. */
if( in_transaction )
log_bug("tdbio: syncing while in transaction\n");
+#endif
if( !cache_is_dirty )
return 0;
@@ -560,7 +583,7 @@ tdbio_update_version_record (ctrl_t ctrl)
/*
* Create and write the trustdb version record.
- *
+ * This is called with the writelock activ.
* Returns: 0 on success or an error code.
*/
static int
@@ -951,10 +974,12 @@ tdbio_write_nextcheck (ctrl_t ctrl, ulong stamp)
* Return: record number
*/
static ulong
-get_trusthashrec(void)
+get_trusthashrec (ctrl_t ctrl)
{
static ulong trusthashtbl; /* Record number of the trust hashtable. */
+ (void)ctrl;
+
if (!trusthashtbl)
{
TRUSTREC vr;
@@ -965,6 +990,20 @@ get_trusthashrec(void)
log_fatal (_("%s: error reading version record: %s\n"),
db_name, gpg_strerror (rc) );
+ if (!vr.r.ver.trusthashtbl)
+ {
+ /* Oops: the trustdb is corrupt because the hashtable is
+ * always created along with the version record. However,
+ * if something went initially wrong it may happen that
+ * there is just the version record. We try to fix it here.
+ * If we can't do that we return 0 - this is the version
+ * record and thus the actual read will detect the mismatch
+ * and bail out. Note that create_hashtable updates VR. */
+ take_write_lock ();
+ if (lseek (db_fd, 0, SEEK_END) == TRUST_RECORD_LEN)
+ create_hashtable (ctrl, &vr, 0);
+ release_write_lock ();
+ }
trusthashtbl = vr.r.ver.trusthashtbl;
}
@@ -1269,6 +1308,13 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen,
int msb;
int level = 0;
+ if (!table)
+ {
+ rc = gpg_error (GPG_ERR_INV_RECORD);
+ log_error("lookup_hashtable failed: %s\n", "request for record 0");
+ return rc;
+ }
+
hashrec = table;
next_level:
msb = key[level];
@@ -1358,7 +1404,7 @@ lookup_hashtable (ulong table, const byte *key, size_t keylen,
static int
update_trusthashtbl (ctrl_t ctrl, TRUSTREC *tr)
{
- return upd_hashtable (ctrl, get_trusthashrec (),
+ return upd_hashtable (ctrl, get_trusthashrec (ctrl),
tr->r.trust.fingerprint, 20, tr->recnum);
}
@@ -1441,7 +1487,7 @@ tdbio_dump_record (TRUSTREC *rec, estream_t fp)
* EXPECTED is not 0 reading any other record type will return an
* error.
*
- * Return: 0 on success, -1 on EOF, or an error code.
+ * Return: 0 on success or an error code.
*/
int
tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected)
@@ -1466,7 +1512,7 @@ tdbio_read_record (ulong recnum, TRUSTREC *rec, int expected)
n = read (db_fd, readbuf, TRUST_RECORD_LEN);
if (!n)
{
- return -1; /* eof */
+ return gpg_error (GPG_ERR_EOF);
}
else if (n != TRUST_RECORD_LEN)
{
@@ -1700,7 +1746,7 @@ tdbio_delete_record (ctrl_t ctrl, ulong recnum)
;
else if (rec.rectype == RECTYPE_TRUST)
{
- rc = drop_from_hashtable (ctrl, get_trusthashrec(),
+ rc = drop_from_hashtable (ctrl, get_trusthashrec (ctrl),
rec.r.trust.fingerprint, 20, rec.recnum);
}
@@ -1746,20 +1792,14 @@ tdbio_new_recnum (ctrl_t ctrl)
recnum = vr.r.ver.firstfree;
rc = tdbio_read_record (recnum, &rec, RECTYPE_FREE);
if (rc)
- {
- log_error (_("%s: error reading free record: %s\n"),
- db_name, gpg_strerror (rc));
- return rc;
- }
+ log_fatal (_("%s: error reading free record: %s\n"),
+ db_name, gpg_strerror (rc));
/* Update dir record. */
vr.r.ver.firstfree = rec.r.free.next;
rc = tdbio_write_record (ctrl, &vr);
if (rc)
- {
- log_error (_("%s: error writing dir record: %s\n"),
- db_name, gpg_strerror (rc));
- return rc;
- }
+ log_fatal (_("%s: error writing dir record: %s\n"),
+ db_name, gpg_strerror (rc));
/* Zero out the new record. */
memset (&rec, 0, sizeof rec);
rec.rectype = 0; /* Mark as unused record (actually already done
@@ -1776,7 +1816,7 @@ tdbio_new_recnum (ctrl_t ctrl)
if (offset == (off_t)(-1))
log_fatal ("trustdb: lseek to end failed: %s\n", strerror (errno));
recnum = offset / TRUST_RECORD_LEN;
- log_assert (recnum); /* this is will never be the first record */
+ log_assert (recnum); /* This will never be the first record */
/* We must write a record, so that the next call to this
* function returns another recnum. */
memset (&rec, 0, sizeof rec);
@@ -1798,13 +1838,13 @@ tdbio_new_recnum (ctrl_t ctrl)
{
rc = gpg_error_from_syserror ();
log_error (_("trustdb rec %lu: write failed (n=%d): %s\n"),
- recnum, n, strerror (errno));
+ recnum, n, gpg_strerror (rc));
}
}
if (rc)
log_fatal (_("%s: failed to append a record: %s\n"),
- db_name, gpg_strerror (rc));
+ db_name, gpg_strerror (rc));
}
return recnum ;
@@ -1828,12 +1868,12 @@ cmp_trec_fpr ( const void *fpr, const TRUSTREC *rec )
* Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code.
*/
gpg_error_t
-tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec)
+tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint, TRUSTREC *rec)
{
int rc;
/* Locate the trust record using the hash table */
- rc = lookup_hashtable (get_trusthashrec(), fingerprint, 20,
+ rc = lookup_hashtable (get_trusthashrec (ctrl), fingerprint, 20,
cmp_trec_fpr, fingerprint, rec );
return rc;
}
@@ -1846,7 +1886,7 @@ tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec)
* Return: 0 if found, GPG_ERR_NOT_FOUND, or another error code.
*/
gpg_error_t
-tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec)
+tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec)
{
byte fingerprint[MAX_FINGERPRINT_LEN];
size_t fingerlen;
@@ -1854,7 +1894,7 @@ tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec)
fingerprint_from_pk( pk, fingerprint, &fingerlen );
for (; fingerlen < 20; fingerlen++)
fingerprint[fingerlen] = 0;
- return tdbio_search_trust_byfpr (fingerprint, rec);
+ return tdbio_search_trust_byfpr (ctrl, fingerprint, rec);
}
diff --git a/g10/tdbio.h b/g10/tdbio.h
index beaa30876..267a37970 100644
--- a/g10/tdbio.h
+++ b/g10/tdbio.h
@@ -110,8 +110,10 @@ int tdbio_end_transaction(void);
int tdbio_cancel_transaction(void);
int tdbio_delete_record (ctrl_t ctrl, ulong recnum);
ulong tdbio_new_recnum (ctrl_t ctrl);
-gpg_error_t tdbio_search_trust_byfpr (const byte *fingerprint, TRUSTREC *rec);
-gpg_error_t tdbio_search_trust_bypk (PKT_public_key *pk, TRUSTREC *rec);
+gpg_error_t tdbio_search_trust_byfpr (ctrl_t ctrl, const byte *fingerprint,
+ TRUSTREC *rec);
+gpg_error_t tdbio_search_trust_bypk (ctrl_t ctrl, PKT_public_key *pk,
+ TRUSTREC *rec);
void tdbio_how_to_fix (void);
void tdbio_invalid(void);
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 0a98c129f..2c2d2394a 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -649,7 +649,7 @@ read_trust_record (ctrl_t ctrl, PKT_public_key *pk, TRUSTREC *rec)
int rc;
init_trustdb (ctrl, 0);
- rc = tdbio_search_trust_bypk (pk, rec);
+ rc = tdbio_search_trust_bypk (ctrl, pk, rec);
if (rc)
{
if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
diff --git a/scd/apdu.c b/scd/apdu.c
index 60270ede0..66a16f820 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -119,6 +119,7 @@ struct reader_table_s {
pcsc_dword_t modify_ioctl;
int pinmin;
int pinmax;
+ pcsc_dword_t current_state;
} pcsc;
#ifdef USE_G10CODE_RAPDU
struct {
@@ -228,6 +229,7 @@ static npth_mutex_t reader_table_lock;
#define PCSC_E_READER_UNAVAILABLE 0x80100017
#define PCSC_E_NO_SERVICE 0x8010001D
#define PCSC_E_SERVICE_STOPPED 0x8010001E
+#define PCSC_W_RESET_CARD 0x80100068
#define PCSC_W_REMOVED_CARD 0x80100069
/* Fix pcsc-lite ABI incompatibility. */
@@ -453,6 +455,7 @@ new_reader_slot (void)
reader_table[reader].pcsc.modify_ioctl = 0;
reader_table[reader].pcsc.pinmin = -1;
reader_table[reader].pcsc.pinmax = -1;
+ reader_table[reader].pcsc.current_state = PCSC_STATE_UNAWARE;
return reader;
}
@@ -653,12 +656,12 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
(void)on_wire;
memset (rdrstates, 0, sizeof *rdrstates);
rdrstates[0].reader = reader_table[slot].rdrname;
- rdrstates[0].current_state = PCSC_STATE_UNAWARE;
+ rdrstates[0].current_state = reader_table[slot].pcsc.current_state;
err = pcsc_get_status_change (reader_table[slot].pcsc.context,
0,
rdrstates, 1);
if (err == PCSC_E_TIMEOUT)
- err = 0; /* Timeout is no error error here. */
+ err = 0; /* Timeout is no error here. */
if (err)
{
log_error ("pcsc_get_status_change failed: %s (0x%lx)\n",
@@ -666,24 +669,29 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
return pcsc_error_to_sw (err);
}
- /* log_debug */
- /* ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n", */
- /* (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_INUSE)? " unuse":"", */
- /* (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" ); */
+ if ((rdrstates[0].event_state & PCSC_STATE_CHANGED))
+ reader_table[slot].pcsc.current_state =
+ (rdrstates[0].event_state & ~PCSC_STATE_CHANGED);
+
+ if (DBG_CARD_IO)
+ log_debug
+ ("pcsc_get_status_change: %s%s%s%s%s%s%s%s%s%s\n",
+ (rdrstates[0].event_state & PCSC_STATE_IGNORE)? " ignore":"",
+ (rdrstates[0].event_state & PCSC_STATE_CHANGED)? " changed":"",
+ (rdrstates[0].event_state & PCSC_STATE_UNKNOWN)? " unknown":"",
+ (rdrstates[0].event_state & PCSC_STATE_UNAVAILABLE)?" unavail":"",
+ (rdrstates[0].event_state & PCSC_STATE_EMPTY)? " empty":"",
+ (rdrstates[0].event_state & PCSC_STATE_PRESENT)? " present":"",
+ (rdrstates[0].event_state & PCSC_STATE_ATRMATCH)? " atr":"",
+ (rdrstates[0].event_state & PCSC_STATE_EXCLUSIVE)? " excl":"",
+ (rdrstates[0].event_state & PCSC_STATE_INUSE)? " inuse":"",
+ (rdrstates[0].event_state & PCSC_STATE_MUTE)? " mute":"" );
*status = 0;
- if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
+ if ( (reader_table[slot].pcsc.current_state & PCSC_STATE_PRESENT) )
{
*status |= APDU_CARD_PRESENT;
- if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
+ if ( !(reader_table[slot].pcsc.current_state & PCSC_STATE_MUTE) )
*status |= APDU_CARD_ACTIVE;
}
#ifndef HAVE_W32_SYSTEM
@@ -692,7 +700,7 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
mode. */
if ( (*status & (APDU_CARD_PRESENT|APDU_CARD_ACTIVE))
== (APDU_CARD_PRESENT|APDU_CARD_ACTIVE)
- && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
+ && !(reader_table[slot].pcsc.current_state & PCSC_STATE_INUSE) )
*status |= APDU_CARD_USABLE;
#else
/* Some winscard drivers may set EXCLUSIVE and INUSE at the same
@@ -702,7 +710,11 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
*status |= APDU_CARD_USABLE;
#endif
- return 0;
+ if (!on_wire && (rdrstates[0].event_state & PCSC_STATE_CHANGED))
+ /* Event like sleep/resume occurs, which requires RESET. */
+ return SW_HOST_NO_READER;
+ else
+ return 0;
}
@@ -741,6 +753,14 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
log_error ("pcsc_transmit failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
+ /* Handle fatal errors which require shutdown of reader. */
+ if (err == PCSC_E_NOT_TRANSACTED || err == PCSC_W_RESET_CARD
+ || err == PCSC_W_REMOVED_CARD)
+ {
+ reader_table[slot].pcsc.current_state = PCSC_STATE_UNAWARE;
+ scd_kick_the_loop ();
+ }
+
return pcsc_error_to_sw (err);
}
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 54f04c612..dc775f77e 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1018,7 +1018,7 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
snprintf (tmp, sizeof tmp,
"gc=%d ki=%d fc=%d pd=%d mcl3=%u aac=%d "
- "sm=%d si=%u dec=%d bt=%d",
+ "sm=%d si=%u dec=%d bt=%d kdf=%d",
app->app_local->extcap.get_challenge,
app->app_local->extcap.key_import,
app->app_local->extcap.change_force_chv,
@@ -1032,7 +1032,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
: 0),
app->app_local->status_indicator,
app->app_local->extcap.has_decrypt,
- app->app_local->extcap.has_button);
+ app->app_local->extcap.has_button,
+ app->app_local->extcap.kdf_do);
send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
return 0;
}
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index 5046da555..f33a36c83 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -1467,7 +1467,8 @@ intr_cb (struct libusb_transfer *transfer)
DEBUGOUT_1 ("CCID: interrupt callback %d\n", transfer->status);
- if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT)
+ if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT
+ || transfer->status == LIBUSB_TRANSFER_NO_DEVICE)
{
int err;
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index cebeea9d3..8f8a02619 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -393,7 +393,21 @@ cleanup (void)
}
}
-
+static void
+setup_signal_mask (void)
+{
+#ifndef HAVE_W32_SYSTEM
+ npth_sigev_init ();
+ npth_sigev_add (SIGHUP);
+ npth_sigev_add (SIGUSR1);
+ npth_sigev_add (SIGUSR2);
+ npth_sigev_add (SIGINT);
+ npth_sigev_add (SIGCONT);
+ npth_sigev_add (SIGTERM);
+ npth_sigev_fini ();
+ main_thread_pid = getpid ();
+#endif
+}
int
main (int argc, char **argv )
@@ -744,6 +758,7 @@ main (int argc, char **argv )
#endif
npth_init ();
+ setup_signal_mask ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* If --debug-allow-core-dump has been given we also need to
@@ -884,6 +899,7 @@ main (int argc, char **argv )
/* This is the child. */
npth_init ();
+ setup_signal_mask ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* Detach from tty and put process into a new session. */
@@ -1206,18 +1222,16 @@ start_connection_thread (void *arg)
void
scd_kick_the_loop (void)
{
- int ret;
-
/* Kick the select loop. */
#ifdef HAVE_W32_SYSTEM
- ret = SetEvent (the_event);
+ int ret = SetEvent (the_event);
if (ret == 0)
log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
w32_strerror (-1));
#elif defined(HAVE_PSELECT_NO_EINTR)
write (notify_fd, "", 1);
#else
- ret = kill (main_thread_pid, SIGCONT);
+ int ret = kill (main_thread_pid, SIGCONT);
if (ret < 0)
log_error ("SetEvent for scd_kick_the_loop failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
@@ -1292,16 +1306,6 @@ handle_connections (int listen_fd)
events[0] = the_event = h2;
}
}
-#else
- npth_sigev_init ();
- npth_sigev_add (SIGHUP);
- npth_sigev_add (SIGUSR1);
- npth_sigev_add (SIGUSR2);
- npth_sigev_add (SIGINT);
- npth_sigev_add (SIGCONT);
- npth_sigev_add (SIGTERM);
- npth_sigev_fini ();
- main_thread_pid = getpid ();
#endif
FD_ZERO (&fdset);
@@ -1348,6 +1352,8 @@ handle_connections (int listen_fd)
FD_SET (pipe_fd[0], &read_fdset);
if (max_fd < pipe_fd[0])
max_fd = pipe_fd[0];
+#else
+ (void)max_fd;
#endif
#ifndef HAVE_W32_SYSTEM
diff --git a/sm/call-agent.c b/sm/call-agent.c
index 772c9c312..20d879fa4 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -179,6 +179,20 @@ start_agent (ctrl_t ctrl)
gpg_strerror (rc));
}
+ /* Pass on the request origin. */
+ if (opt.request_origin)
+ {
+ char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
+ str_request_origin (opt.request_origin));
+ rc = assuan_transact (agent_ctx, tmp,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ xfree (tmp);
+ if (rc)
+ log_error ("setting request origin '%s' failed: %s\n",
+ str_request_origin (opt.request_origin),
+ gpg_strerror (rc));
+ }
+
/* In DE_VS mode under Windows we require that the JENT RNG
* is active. */
#ifdef HAVE_W32_SYSTEM
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index 982be58ba..beabb3854 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -125,6 +125,7 @@ enum cmd_and_opt_values {
oPassphraseFD,
oPinentryMode,
+ oRequestOrigin,
oAssumeArmor,
oAssumeBase64,
@@ -255,6 +256,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"),
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
+ ARGPARSE_s_s (oRequestOrigin, "request-origin", "@"),
ARGPARSE_s_n (oAssumeArmor, "assume-armor",
N_("assume input is in PEM format")),
@@ -1162,6 +1164,12 @@ main ( int argc, char **argv)
log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str);
break;
+ case oRequestOrigin:
+ opt.request_origin = parse_request_origin (pargs.r.ret_str);
+ if (opt.request_origin == -1)
+ log_error (_("invalid request origin '%s'\n"), pargs.r.ret_str);
+ break;
+
/* Input encoding selection. */
case oAssumeArmor:
ctrl.autodetect_encoding = 0;
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 3e2f95fb3..d3fbde515 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -88,6 +88,7 @@ struct
int with_key_screening; /* Option --with-key-screening active. */
int pinentry_mode;
+ int request_origin;
int armor; /* force base64 armoring (see also ctrl.with_base64) */
int no_armor; /* don't try to figure out whether data is base64 armored*/
diff --git a/sm/server.c b/sm/server.c
index 721f3faf0..98505e26d 100644
--- a/sm/server.c
+++ b/sm/server.c
@@ -32,6 +32,7 @@
#include "../common/sysutils.h"
#include "../common/server-help.h"
#include "../common/asshelp.h"
+#include "../common/shareddefs.h"
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
@@ -289,6 +290,17 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->offline = i;
}
}
+ else if (!strcmp (key, "request-origin"))
+ {
+ if (!opt.request_origin)
+ {
+ int i = parse_request_origin (value);
+ if (i == -1)
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ else
+ opt.request_origin = i;
+ }
+ }
else
err = gpg_error (GPG_ERR_UNKNOWN_OPTION);