mirror of
git://git.gnupg.org/gnupg.git
synced 2024-10-29 19:48:43 +01:00
gpgsm: Implement a cache for the KEYINFO queries.
* sm/gpgsm.h (struct keyinfo_cache_item_s): New.
(struct server_control_s): Add keyinfo_cache and keyinfo_cache_valid.
* sm/call-agent.c (keyinfo_cache_disabled): New flag.
(release_a_keyinfo_cache): New.
(gpgsm_flush_keyinfo_cache): New.
(struct keyinfo_status_parm_s): New.
(keyinfo_status_cb): Implement a fill mode.
(gpgsm_agent_keyinfo): Implement a cache.
* sm/server.c (reset_notify): Flush the cache.
* sm/gpgsm.c (gpgsm_deinit_default_ctrl): Ditto.
--
In almost all cases we have just a few private keys in the agent and
thus it is better to fetch them early. This does not work in a
restricted connection but we take care and disable the cache in this
case.
This cache gives a a minor speed up.
GnuPG-bug-id: 7308
(cherry picked from commit 241971fac0
)
This commit is contained in:
parent
09d4b8f496
commit
9087c1d363
158
sm/call-agent.c
158
sm/call-agent.c
@ -98,6 +98,9 @@ static istrusted_cache_t istrusted_cache;
|
|||||||
static int istrusted_cache_valid;
|
static int istrusted_cache_valid;
|
||||||
static int istrusted_cache_disabled;
|
static int istrusted_cache_disabled;
|
||||||
|
|
||||||
|
/* Flag indicating that we can't use the keyinfo cache at all. The
|
||||||
|
* actual cache is stored in CTRL. */
|
||||||
|
static int keyinfo_cache_disabled;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -121,6 +124,33 @@ flush_istrusted_cache (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Release all items in *CACHEP and set CACHEP to NULL */
|
||||||
|
static void
|
||||||
|
release_a_keyinfo_cache (keyinfo_cache_item_t *cachep)
|
||||||
|
{
|
||||||
|
keyinfo_cache_item_t mycache;
|
||||||
|
|
||||||
|
/* First unlink the cache to be npth safe. */
|
||||||
|
mycache = *cachep;
|
||||||
|
*cachep = NULL;
|
||||||
|
|
||||||
|
while (mycache)
|
||||||
|
{
|
||||||
|
keyinfo_cache_item_t next = mycache->next;
|
||||||
|
xfree (mycache);
|
||||||
|
mycache = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Flush the keyinfo cache for the session CTRL. */
|
||||||
|
void
|
||||||
|
gpgsm_flush_keyinfo_cache (ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
ctrl->keyinfo_cache_valid = 0;
|
||||||
|
release_a_keyinfo_cache (&ctrl->keyinfo_cache);
|
||||||
|
}
|
||||||
|
|
||||||
/* Print a warning if the server's version number is less than our
|
/* Print a warning if the server's version number is less than our
|
||||||
version number. Returns an error code on a connection problem. */
|
version number. Returns an error code on a connection problem. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -990,9 +1020,10 @@ gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr,
|
|||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (rc) != GPG_ERR_FORBIDDEN)
|
if (gpg_err_code (rc) != GPG_ERR_FORBIDDEN)
|
||||||
log_error ("filling istrusted cache failed: %s\n",
|
log_info ("filling istrusted cache failed: %s\n",
|
||||||
gpg_strerror (rc));
|
gpg_strerror (rc));
|
||||||
istrusted_cache_disabled = 1;
|
istrusted_cache_disabled = 1;
|
||||||
|
flush_istrusted_cache ();
|
||||||
rc = 0; /* Fallback to single requests. */
|
rc = 0; /* Fallback to single requests. */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1330,42 +1361,79 @@ gpgsm_agent_send_nop (ctrl_t ctrl)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct keyinfo_status_parm_s
|
||||||
|
{
|
||||||
|
char *serialno;
|
||||||
|
int fill_mode; /* True if we want to fill the cache. */
|
||||||
|
keyinfo_cache_item_t cache;
|
||||||
|
};
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
keyinfo_status_cb (void *opaque, const char *line)
|
keyinfo_status_cb (void *opaque, const char *line)
|
||||||
{
|
{
|
||||||
char **serialno = opaque;
|
struct keyinfo_status_parm_s *parm = opaque;
|
||||||
const char *s, *s2;
|
const char *s0, *s, *s2;
|
||||||
|
|
||||||
if ((s = has_leading_keyword (line, "KEYINFO")) && !*serialno)
|
if ((s0 = has_leading_keyword (line, "KEYINFO"))
|
||||||
|
&& (!parm->serialno || parm->fill_mode))
|
||||||
{
|
{
|
||||||
s = strchr (s, ' ');
|
s = strchr (s0, ' ');
|
||||||
|
xfree (parm->serialno);
|
||||||
|
parm->serialno = NULL;
|
||||||
if (s && s[1] == 'T' && s[2] == ' ' && s[3])
|
if (s && s[1] == 'T' && s[2] == ' ' && s[3])
|
||||||
{
|
{
|
||||||
s += 3;
|
s += 3;
|
||||||
s2 = strchr (s, ' ');
|
s2 = strchr (s, ' ');
|
||||||
if ( s2 > s )
|
if ( s2 > s )
|
||||||
{
|
{
|
||||||
*serialno = xtrymalloc ((s2 - s)+1);
|
parm->serialno = xtrymalloc ((s2 - s)+1);
|
||||||
if (*serialno)
|
if (parm->serialno)
|
||||||
{
|
{
|
||||||
memcpy (*serialno, s, s2 - s);
|
memcpy (parm->serialno, s, s2 - s);
|
||||||
(*serialno)[s2 - s] = 0;
|
parm->serialno[s2 - s] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parm->fill_mode && *s0)
|
||||||
|
{
|
||||||
|
keyinfo_cache_item_t ci;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
n = s? (s - s0) : strlen (s0);
|
||||||
|
ci = xtrymalloc (sizeof *ci + n);
|
||||||
|
if (!ci)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
memcpy (ci->hexgrip, s0, n);
|
||||||
|
ci->hexgrip[n] = 0;
|
||||||
|
ci->serialno = parm->serialno;
|
||||||
|
parm->serialno = NULL;
|
||||||
|
ci->next = parm->cache;
|
||||||
|
parm->cache = ci;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the serial number for a secret key. If the returned serial
|
/* Return the serial number for a secret key. If the returned serial
|
||||||
number is NULL, the key is not stored on a smartcard. Caller needs
|
* number is NULL, the key is not stored on a smartcard. Caller needs
|
||||||
to free R_SERIALNO. */
|
* to free R_SERIALNO.
|
||||||
|
*
|
||||||
|
* Take care: The cache is currently only used in the key listing and
|
||||||
|
* it should not interfere with import or creation of new keys because
|
||||||
|
* we assume that is done by another process. However we assume that
|
||||||
|
* in server mode the key listing is not directly followed by an import
|
||||||
|
* and another key listing.
|
||||||
|
*/
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
|
gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char line[ASSUAN_LINELENGTH];
|
char line[ASSUAN_LINELENGTH];
|
||||||
char *serialno = NULL;
|
keyinfo_cache_item_t ci;
|
||||||
|
struct keyinfo_status_parm_s parm = { NULL };
|
||||||
|
|
||||||
*r_serialno = NULL;
|
*r_serialno = NULL;
|
||||||
|
|
||||||
@ -1376,20 +1444,70 @@ gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
|
|||||||
if (!hexkeygrip || strlen (hexkeygrip) != 40)
|
if (!hexkeygrip || strlen (hexkeygrip) != 40)
|
||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
|
/* First try to fill the cache. */
|
||||||
|
if (!keyinfo_cache_disabled && !ctrl->keyinfo_cache_valid)
|
||||||
|
{
|
||||||
|
parm.fill_mode = 1;
|
||||||
|
err = assuan_transact (agent_ctx, "KEYINFO --list",
|
||||||
|
NULL, NULL, NULL, NULL,
|
||||||
|
keyinfo_status_cb, &parm);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
if (gpg_err_code (err) != GPG_ERR_FORBIDDEN)
|
||||||
|
log_error ("filling keyinfo cache failed: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
keyinfo_cache_disabled = 1;
|
||||||
|
release_a_keyinfo_cache (&parm.cache);
|
||||||
|
err = 0; /* Fallback to single requests. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctrl->keyinfo_cache_valid = 1;
|
||||||
|
ctrl->keyinfo_cache = parm.cache;
|
||||||
|
parm.cache = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
|
/* Then consult the cache or send a query */
|
||||||
keyinfo_status_cb, &serialno);
|
if (ctrl->keyinfo_cache_valid)
|
||||||
if (!err && serialno)
|
{
|
||||||
|
for (ci = ctrl->keyinfo_cache; ci; ci = ci->next)
|
||||||
|
if (!strcmp (hexkeygrip, ci->hexgrip))
|
||||||
|
break;
|
||||||
|
if (ci)
|
||||||
|
{
|
||||||
|
xfree (parm.serialno);
|
||||||
|
parm.serialno = NULL;
|
||||||
|
err = 0;
|
||||||
|
if (ci->serialno)
|
||||||
|
{
|
||||||
|
parm.serialno = xtrystrdup (ci->serialno);
|
||||||
|
if (!parm.serialno)
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
|
||||||
|
parm.fill_mode = 0;
|
||||||
|
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
|
||||||
|
keyinfo_status_cb, &parm);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!err && parm.serialno)
|
||||||
{
|
{
|
||||||
/* Sanity check for bad characters. */
|
/* Sanity check for bad characters. */
|
||||||
if (strpbrk (serialno, ":\n\r"))
|
if (strpbrk (parm.serialno, ":\n\r"))
|
||||||
err = GPG_ERR_INV_VALUE;
|
err = gpg_error (GPG_ERR_INV_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
xfree (serialno);
|
xfree (parm.serialno);
|
||||||
else
|
else
|
||||||
*r_serialno = serialno;
|
*r_serialno = parm.serialno;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2169,6 +2169,7 @@ gpgsm_deinit_default_ctrl (ctrl_t ctrl)
|
|||||||
{
|
{
|
||||||
unsigned int n;
|
unsigned int n;
|
||||||
|
|
||||||
|
gpgsm_flush_keyinfo_cache (ctrl);
|
||||||
n = 0;
|
n = 0;
|
||||||
while (ctrl->parent_cert_cache)
|
while (ctrl->parent_cert_cache)
|
||||||
{
|
{
|
||||||
|
14
sm/gpgsm.h
14
sm/gpgsm.h
@ -199,6 +199,15 @@ struct cert_cache_item_s
|
|||||||
};
|
};
|
||||||
typedef struct cert_cache_item_s *cert_cache_item_t;
|
typedef struct cert_cache_item_s *cert_cache_item_t;
|
||||||
|
|
||||||
|
/* On object used to keep a KEYINFO data from the agent. */
|
||||||
|
struct keyinfo_cache_item_s
|
||||||
|
{
|
||||||
|
struct keyinfo_cache_item_s *next;
|
||||||
|
char *serialno; /* Malloced serialnumber of a card. */
|
||||||
|
char hexgrip[1]; /* The keygrip in hexformat. */
|
||||||
|
};
|
||||||
|
typedef struct keyinfo_cache_item_s *keyinfo_cache_item_t;
|
||||||
|
|
||||||
|
|
||||||
/* Session control object. This object is passed down to most
|
/* Session control object. This object is passed down to most
|
||||||
functions. Note that the default values for it are set by
|
functions. Note that the default values for it are set by
|
||||||
@ -251,6 +260,10 @@ struct server_control_s
|
|||||||
|
|
||||||
/* The cache used to find the parent cert. */
|
/* The cache used to find the parent cert. */
|
||||||
cert_cache_item_t parent_cert_cache;
|
cert_cache_item_t parent_cert_cache;
|
||||||
|
|
||||||
|
/* Cache of recently gathered KEYINFO data. */
|
||||||
|
keyinfo_cache_item_t keyinfo_cache;
|
||||||
|
int keyinfo_cache_valid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -443,6 +456,7 @@ gpg_error_t gpgsm_qualified_consent (ctrl_t ctrl, ksba_cert_t cert);
|
|||||||
gpg_error_t gpgsm_not_qualified_warning (ctrl_t ctrl, ksba_cert_t cert);
|
gpg_error_t gpgsm_not_qualified_warning (ctrl_t ctrl, ksba_cert_t cert);
|
||||||
|
|
||||||
/*-- call-agent.c --*/
|
/*-- call-agent.c --*/
|
||||||
|
void gpgsm_flush_keyinfo_cache (ctrl_t ctrl);
|
||||||
int gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
|
int gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
|
||||||
unsigned char *digest,
|
unsigned char *digest,
|
||||||
size_t digestlen,
|
size_t digestlen,
|
||||||
|
@ -330,6 +330,7 @@ reset_notify (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
(void) line;
|
(void) line;
|
||||||
|
|
||||||
|
gpgsm_flush_keyinfo_cache (ctrl);
|
||||||
gpgsm_release_certlist (ctrl->server_local->recplist);
|
gpgsm_release_certlist (ctrl->server_local->recplist);
|
||||||
gpgsm_release_certlist (ctrl->server_local->signerlist);
|
gpgsm_release_certlist (ctrl->server_local->signerlist);
|
||||||
ctrl->server_local->recplist = NULL;
|
ctrl->server_local->recplist = NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user