* app-common.h: New members FNC.DEINIT and APP_LOCAL.

* app.c (release_application): Call new deconstructor.
* app-openpgp.c (do_deinit): New.
(get_cached_data, flush_cache_item, flush_cache_after_error)
(flush_cache): New.
(get_one_do): Replaced arg SLOT by APP.  Make used of cached data.
(verify_chv2, verify_chv3): Flush some cache item after error.
(do_change_pin): Ditto.
(do_sign): Ditto.
(do_setattr): Flush cache item.
(do_genkey): Flush the entire cache.
(compare_fingerprint): Use cached data.
This commit is contained in:
Werner Koch 2004-04-26 18:28:06 +00:00
parent 6efe46d4ff
commit 869a2bbad2
4 changed files with 235 additions and 33 deletions

View File

@ -1,5 +1,18 @@
2004-04-26 Werner Koch <wk@gnupg.org>
* app-common.h: New members FNC.DEINIT and APP_LOCAL.
* app.c (release_application): Call new deconstructor.
* app-openpgp.c (do_deinit): New.
(get_cached_data, flush_cache_item, flush_cache_after_error)
(flush_cache): New.
(get_one_do): Replaced arg SLOT by APP. Make used of cached data.
(verify_chv2, verify_chv3): Flush some cache item after error.
(do_change_pin): Ditto.
(do_sign): Ditto.
(do_setattr): Flush cache item.
(do_genkey): Flush the entire cache.
(compare_fingerprint): Use cached data.
* scdaemon.c (main): Do the last change the usual way. This is so
that we can easily test for versioned config files above.

View File

@ -23,6 +23,8 @@
#include <ksba.h>
struct app_local_s; /* Defined by all app-*.c. */
struct app_ctx_s {
int initialized; /* The application has been initialied and the
function pointers may be used. Note that for
@ -37,7 +39,9 @@ struct app_ctx_s {
int force_chv1; /* True if the card does not cache CHV1. */
int did_chv2;
int did_chv3;
struct app_local_s *app_local; /* Local to the application. */
struct {
void (*deinit) (app_t app);
int (*learn_status) (app_t app, ctrl_t ctrl);
int (*readcert) (app_t app, const char *certid,
unsigned char **cert, size_t *certlen);
@ -75,7 +79,6 @@ struct app_ctx_s {
void *pincb_arg);
} fnc;
};
#if GNUPG_MAJOR_VERSION == 1

View File

@ -50,35 +50,199 @@ static struct {
int constructed;
int get_from; /* Constructed DO with this DO or 0 for direct access. */
int binary;
int dont_cache;
int flush_on_error;
char *desc;
} data_objects[] = {
{ 0x005E, 0, 0, 1, "Login Data" },
{ 0x5F50, 0, 0, 0, "URL" },
{ 0x0065, 1, 0, 1, "Cardholder Related Data"},
{ 0x005B, 0, 0x65, 0, "Name" },
{ 0x5F2D, 0, 0x65, 0, "Language preferences" },
{ 0x5F35, 0, 0x65, 0, "Sex" },
{ 0x006E, 1, 0, 1, "Application Related Data" },
{ 0x004F, 0, 0x6E, 1, "AID" },
{ 0x0073, 1, 0, 1, "Discretionary Data Objects" },
{ 0x0047, 0, 0x6E, 1, "Card Capabilities" },
{ 0x00C0, 0, 0x6E, 1, "Extended Card Capabilities" },
{ 0x00C1, 0, 0x6E, 1, "Algorithm Attributes Signature" },
{ 0x00C2, 0, 0x6E, 1, "Algorithm Attributes Decryption" },
{ 0x00C3, 0, 0x6E, 1, "Algorithm Attributes Authentication" },
{ 0x00C4, 0, 0x6E, 1, "CHV Status Bytes" },
{ 0x00C5, 0, 0x6E, 1, "Fingerprints" },
{ 0x00C6, 0, 0x6E, 1, "CA Fingerprints" },
{ 0x007A, 1, 0, 1, "Security Support Template" },
{ 0x0093, 0, 0x7A, 1, "Digital Signature Counter" },
{ 0x005E, 0, 0, 1, 0, 0, "Login Data" },
{ 0x5F50, 0, 0, 0, 0, 0, "URL" },
{ 0x0065, 1, 0, 1, 0, 0, "Cardholder Related Data"},
{ 0x005B, 0, 0x65, 0, 0, 0, "Name" },
{ 0x5F2D, 0, 0x65, 0, 0, 0, "Language preferences" },
{ 0x5F35, 0, 0x65, 0, 0, 0, "Sex" },
{ 0x006E, 1, 0, 1, 0, 0, "Application Related Data" },
{ 0x004F, 0, 0x6E, 1, 0, 0, "AID" },
{ 0x0073, 1, 0, 1, 0, 0, "Discretionary Data Objects" },
{ 0x0047, 0, 0x6E, 1, 0, 0, "Card Capabilities" },
{ 0x00C0, 0, 0x6E, 1, 0, 0, "Extended Card Capabilities" },
{ 0x00C1, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Signature" },
{ 0x00C2, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Decryption" },
{ 0x00C3, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Authentication" },
{ 0x00C4, 0, 0x6E, 1, 0, 1, "CHV Status Bytes" },
{ 0x00C5, 0, 0x6E, 1, 0, 0, "Fingerprints" },
{ 0x00C6, 0, 0x6E, 1, 0, 0, "CA Fingerprints" },
{ 0x007A, 1, 0, 1, 0, 0, "Security Support Template" },
{ 0x0093, 0, 0x7A, 1, 1, 0, "Digital Signature Counter" },
{ 0 }
};
struct cache_s {
struct cache_s *next;
int tag;
size_t length;
unsigned char data[1];
};
struct app_local_s {
struct cache_s *cache;
};
static unsigned long convert_sig_counter_value (const unsigned char *value,
size_t valuelen);
static unsigned long get_sig_counter (APP app);
/* Deconstructor. */
static void
do_deinit (app_t app)
{
if (app && app->app_local)
{
struct cache_s *c, *c2;
for (c = app->app_local->cache; c; c = c2)
{
c2 = c->next;
xfree (c);
}
xfree (app->app_local);
app->app_local = NULL;
}
}
/* Wrapper around iso7816_get_data which first tries to get the data
from the cache. */
static gpg_error_t
get_cached_data (app_t app, int tag,
unsigned char **result, size_t *resultlen)
{
gpg_error_t err;
int i;
unsigned char *p;
size_t len;
struct cache_s *c;
*result = NULL;
*resultlen = 0;
if (app->app_local)
{
for (c=app->app_local->cache; c; c = c->next)
if (c->tag == tag)
{
p = xtrymalloc (c->length);
if (!p)
return gpg_error (gpg_err_code_from_errno (errno));
memcpy (p, c->data, c->length);
*resultlen = c->length;
*result = p;
return 0;
}
}
err = iso7816_get_data (app->slot, tag, &p, &len);
if (err)
return err;
*result = p;
*resultlen = len;
/* Check whether we should cache this object. */
for (i=0; data_objects[i].tag; i++)
if (data_objects[i].tag == tag)
{
if (data_objects[i].dont_cache)
return 0;
break;
}
/* No, cache it. */
if (!app->app_local)
app->app_local = xtrycalloc (1, sizeof *app->app_local);
/* Note that we can safely ignore out of core errors. */
if (app->app_local)
{
for (c=app->app_local->cache; c; c = c->next)
assert (c->tag != tag);
c = xtrymalloc (sizeof *c + len);
if (c)
{
memcpy (c->data, p, len);
log_debug (" caching tag %04X\n", tag);
c->length = len;
c->tag = tag;
c->next = app->app_local->cache;
app->app_local->cache = c;
}
}
return 0;
}
/* Remove DO at TAG from the cache. */
static void
flush_cache_item (app_t app, int tag)
{
struct cache_s *c, *cprev;
int i;
if (!app->app_local)
return;
for (c=app->app_local->cache, cprev=NULL; c ; cprev=c, c = c->next)
if (c->tag == tag)
{
if (cprev)
cprev->next = c->next;
else
app->app_local->cache = c->next;
xfree (c);
for (c=app->app_local->cache; c ; c = c->next)
assert (c->tag != tag); /* Oops: duplicated entry. */
return;
}
/* Try again if we have an outer tag. */
for (i=0; data_objects[i].tag; i++)
if (data_objects[i].tag == tag && data_objects[i].get_from
&& data_objects[i].get_from != tag)
flush_cache_item (app, data_objects[i].get_from);
}
/* Flush all entries from the cache which might be out of sync after
an error. */
static void
flush_cache_after_error (app_t app)
{
int i;
for (i=0; data_objects[i].tag; i++)
if (data_objects[i].flush_on_error)
flush_cache_item (app, data_objects[i].tag);
}
/* Flush the entire cache. */
static void
flush_cache (app_t app)
{
if (app && app->app_local)
{
struct cache_s *c, *c2;
for (c = app->app_local->cache; c; c = c2)
{
c2 = c->next;
xfree (c);
}
app->app_local->cache = NULL;
}
}
/* Get the DO identified by TAG from the card in SLOT and return a
@ -86,7 +250,7 @@ static unsigned long get_sig_counter (APP app);
NULL if not found or a pointer which must be used to release the
buffer holding value. */
static void *
get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes)
get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes)
{
int rc, i;
unsigned char *buffer;
@ -103,8 +267,8 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes)
rc = -1;
if (data_objects[i].tag && data_objects[i].get_from)
{
rc = iso7816_get_data (slot, data_objects[i].get_from,
&buffer, &buflen);
rc = get_cached_data (app, data_objects[i].get_from,
&buffer, &buflen);
if (!rc)
{
const unsigned char *s;
@ -125,7 +289,7 @@ get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes)
if (!value) /* Not in a constructed DO, try simple. */
{
rc = iso7816_get_data (slot, tag, &buffer, &buflen);
rc = get_cached_data (app, tag, &buffer, &buflen);
if (!rc)
{
value = buffer;
@ -374,7 +538,7 @@ do_getattr (APP app, CTRL ctrl, const char *name)
return 0;
}
relptr = get_one_do (app->slot, table[idx].tag, &value, &valuelen);
relptr = get_one_do (app, table[idx].tag, &value, &valuelen);
if (relptr)
{
if (table[idx].special == 1)
@ -429,7 +593,7 @@ do_learn_status (APP app, CTRL ctrl)
/* Verify CHV2 if required. Depending on the configuration of the
card CHV1 will also be verified. */
static int
verify_chv2 (APP app,
verify_chv2 (app_t app,
int (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
@ -458,6 +622,7 @@ verify_chv2 (APP app,
{
log_error ("verify CHV2 failed: %s\n", gpg_strerror (rc));
xfree (pinvalue);
flush_cache_after_error (app);
return rc;
}
app->did_chv2 = 1;
@ -471,6 +636,7 @@ verify_chv2 (APP app,
{
log_error ("verify CHV1 failed: %s\n", gpg_strerror (rc));
xfree (pinvalue);
flush_cache_after_error (app);
return rc;
}
app->did_chv1 = 1;
@ -517,6 +683,7 @@ verify_chv3 (APP app,
if (rc)
{
log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc));
flush_cache_after_error (app);
return rc;
}
app->did_chv3 = 1;
@ -561,6 +728,10 @@ do_setattr (APP app, const char *name,
if (rc)
return rc;
/* Flush the cache before writing it, so that the next get operation
will reread the data from the card and thus get synced in case of
errors (e.g. data truncated by the card). */
flush_cache_item (app, table[idx].tag);
rc = iso7816_put_data (app->slot, table[idx].tag, value, valuelen);
if (rc)
log_error ("failed to set `%s': %s\n", table[idx].name, gpg_strerror (rc));
@ -647,7 +818,8 @@ do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
pinvalue, strlen (pinvalue));
}
xfree (pinvalue);
if (rc)
flush_cache_after_error (app);
leave:
return rc;
@ -678,6 +850,10 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
return gpg_error (GPG_ERR_INV_ID);
keyno--;
/* We flush the cache to increase the traffic before a key
generation. This _might_ help a card to gather more entropy. */
flush_cache (app);
rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
if (rc)
{
@ -711,6 +887,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
goto leave;
xfree (buffer); buffer = NULL;
#if 1
log_info ("please wait while key is being generated ...\n");
start_at = time (NULL);
@ -801,7 +978,7 @@ get_sig_counter (APP app)
size_t valuelen;
unsigned long ul;
relptr = get_one_do (app->slot, 0x0093, &value, &valuelen);
relptr = get_one_do (app, 0x0093, &value, &valuelen);
if (!relptr)
return 0;
ul = convert_sig_counter_value (value, valuelen);
@ -819,7 +996,7 @@ compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr)
assert (keyno >= 1 && keyno <= 3);
rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
rc = get_cached_data (app, 0x006E, &buffer, &buflen);
if (rc)
{
log_error ("error reading application data\n");
@ -979,6 +1156,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo,
{
log_error ("verify CHV1 failed\n");
xfree (pinvalue);
flush_cache_after_error (app);
return rc;
}
app->did_chv1 = 1;
@ -992,6 +1170,7 @@ do_sign (APP app, const char *keyidstr, int hashalgo,
{
log_error ("verify CHV2 failed\n");
xfree (pinvalue);
flush_cache_after_error (app);
return rc;
}
app->did_chv2 = 1;
@ -1220,7 +1399,7 @@ app_select_openpgp (APP app)
app->serialnolen = buflen;
buffer = NULL;
relptr = get_one_do (app->slot, 0x00C4, &buffer, &buflen);
relptr = get_one_do (app, 0x00C4, &buffer, &buflen);
if (!relptr)
{
log_error ("can't access CHV Status Bytes - invalid OpenPGP card?\n");
@ -1232,6 +1411,7 @@ app_select_openpgp (APP app)
if (opt.verbose > 1)
dump_all_do (slot);
app->fnc.deinit = do_deinit;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = NULL;
app->fnc.getattr = do_getattr;
@ -1285,7 +1465,7 @@ app_openpgp_cardinfo (APP app,
if (disp_name)
{
*disp_name = NULL;
relptr = get_one_do (app->slot, 0x005B, &value, &valuelen);
relptr = get_one_do (app, 0x005B, &value, &valuelen);
if (relptr)
{
*disp_name = make_printable_string (value, valuelen, 0);
@ -1296,7 +1476,7 @@ app_openpgp_cardinfo (APP app,
if (pubkey_url)
{
*pubkey_url = NULL;
relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen);
relptr = get_one_do (app, 0x5F50, &value, &valuelen);
if (relptr)
{
*pubkey_url = make_printable_string (value, valuelen, 0);
@ -1310,7 +1490,7 @@ app_openpgp_cardinfo (APP app,
*fpr2 = NULL;
if (fpr3)
*fpr3 = NULL;
relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen);
relptr = get_one_do (app, 0x00C5, &value, &valuelen);
if (relptr && valuelen >= 60)
{
if (fpr1)

View File

@ -116,6 +116,12 @@ release_application (app_t app)
if (!app)
return;
if (app->fnc.deinit)
{
app->fnc.deinit (app);
app->fnc.deinit = NULL;
}
xfree (app->serialno);
xfree (app);
}