scd: New flag --reread for LEARN

* scd/command.c (cmd_learn): Add flag --reread.
* scd/app-common.h (struct app_ctx_s): New field need_reset.
* scd/app.c (write_learn_status_core): Set need_reset if we notice an
error after returning from a reread.  Change all callers of card
functions to return GPG_ERR_CARD_RESET so that that app is not anymore
used.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2021-04-01 10:31:52 +02:00
parent e17d3f8660
commit ff87f4e578
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
3 changed files with 101 additions and 39 deletions

View File

@ -136,6 +136,7 @@ struct app_ctx_s {
unsigned int force_chv1:1; /* True if the card does not cache CHV1. */ unsigned int force_chv1:1; /* True if the card does not cache CHV1. */
unsigned int did_chv2:1; unsigned int did_chv2:1;
unsigned int did_chv3:1; unsigned int did_chv3:1;
unsigned int need_reset:1; /* Do't allow any functions but deinit. */
struct app_local_s *app_local; /* Local to the application. */ struct app_local_s *app_local; /* Local to the application. */
struct { struct {
void (*deinit) (app_t app); void (*deinit) (app_t app);

119
scd/app.c
View File

@ -1407,14 +1407,20 @@ run_reselect (ctrl_t ctrl, card_t c, app_t a, app_t a_prev)
* required to always work. */ * required to always work. */
if (a_prev && a_prev->fnc.prep_reselect) if (a_prev && a_prev->fnc.prep_reselect)
{ {
err = a_prev->fnc.prep_reselect (a_prev, ctrl); if (a_prev->need_reset)
err = gpg_error (GPG_ERR_CARD_RESET);
else
err = a_prev->fnc.prep_reselect (a_prev, ctrl);
if (err) if (err)
log_error ("slot %d, app %s: preparing re-select from %s failed: %s\n", log_error ("slot %d, app %s: preparing re-select from %s failed: %s\n",
c->slot, xstrapptype (a), c->slot, xstrapptype (a),
xstrapptype (a_prev), gpg_strerror (err)); xstrapptype (a_prev), gpg_strerror (err));
} }
err = a->fnc.reselect (a, ctrl); if (a->need_reset)
err = gpg_error (GPG_ERR_CARD_RESET);
else
err = a->fnc.reselect (a, ctrl);
if (err) if (err)
{ {
log_error ("slot %d, app %s: error re-selecting: %s\n", log_error ("slot %d, app %s: error re-selecting: %s\n",
@ -1491,6 +1497,7 @@ maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
* the corresponding app. */ * the corresponding app. */
for (app = card->app; app; app_prev = app, app = app->next) for (app = card->app; app; app_prev = app, app = app->next)
if (app->fnc.with_keygrip if (app->fnc.with_keygrip
&& !app->need_reset
&& !app->fnc.with_keygrip (app, ctrl, && !app->fnc.with_keygrip (app, ctrl,
KEYGRIP_ACTION_LOOKUP, keyref, 0)) KEYGRIP_ACTION_LOOKUP, keyref, 0))
break; break;
@ -1542,6 +1549,8 @@ static gpg_error_t
write_learn_status_core (card_t card, app_t app, ctrl_t ctrl, write_learn_status_core (card_t card, app_t app, ctrl_t ctrl,
unsigned int flags) unsigned int flags)
{ {
gpg_error_t err;
/* We do not send CARD and APPTYPE if only keypairinfo is requested. */ /* We do not send CARD and APPTYPE if only keypairinfo is requested. */
if (!(flags & APP_LEARN_FLAG_KEYPAIRINFO)) if (!(flags & APP_LEARN_FLAG_KEYPAIRINFO))
{ {
@ -1555,7 +1564,15 @@ write_learn_status_core (card_t card, app_t app, ctrl_t ctrl,
send_status_printf (ctrl, "APPVERSION", "%X", app->appversion); send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
} }
return app->fnc.learn_status (app, ctrl, flags); if (app->need_reset)
err = gpg_error (GPG_ERR_CARD_RESET);
else
{
err = app->fnc.learn_status (app, ctrl, flags);
if (err && (flags & APP_LEARN_FLAG_REREAD))
app->need_reset = 1;
}
return err;
} }
@ -1666,7 +1683,10 @@ app_readcert (card_t card, ctrl_t ctrl, const char *certid,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling readcert(%s)\n", log_debug ("slot %d app %s: calling readcert(%s)\n",
card->slot, xstrapptype (card->app), certid); card->slot, xstrapptype (card->app), certid);
err = card->app->fnc.readcert (card->app, certid, cert, certlen); if (card->app->need_reset)
err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.readcert (card->app, certid, cert, certlen);
} }
unlock_card (card); unlock_card (card);
@ -1708,7 +1728,10 @@ app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling readkey(%s)\n", log_debug ("slot %d app %s: calling readkey(%s)\n",
card->slot, xstrapptype (card->app), keyid); card->slot, xstrapptype (card->app), keyid);
err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen); if (card->app->need_reset)
err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen);
} }
unlock_card (card); unlock_card (card);
@ -1758,7 +1781,10 @@ app_getattr (card_t card, ctrl_t ctrl, const char *name)
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling getattr(%s)\n", log_debug ("slot %d app %s: calling getattr(%s)\n",
card->slot, xstrapptype (card->app), name); card->slot, xstrapptype (card->app), name);
err = card->app->fnc.getattr (card->app, ctrl, name); if (card->app->need_reset)
err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.getattr (card->app, ctrl, name);
} }
unlock_card (card); unlock_card (card);
@ -1790,8 +1816,11 @@ app_setattr (card_t card, ctrl_t ctrl, const char *name,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling setattr(%s)\n", log_debug ("slot %d app %s: calling setattr(%s)\n",
card->slot, xstrapptype (card->app), name); card->slot, xstrapptype (card->app), name);
err = card->app->fnc.setattr (card->app, ctrl, name, pincb, pincb_arg, if (card->app->need_reset)
value, valuelen); err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.setattr (card->app, ctrl, name, pincb, pincb_arg,
value, valuelen);
} }
unlock_card (card); unlock_card (card);
@ -1826,10 +1855,13 @@ app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling sign(%s)\n", log_debug ("slot %d app %s: calling sign(%s)\n",
card->slot, xstrapptype (card->app), keyidstr); card->slot, xstrapptype (card->app), keyidstr);
err = card->app->fnc.sign (card->app, ctrl, keyidstr, hashalgo, if (card->app->need_reset)
pincb, pincb_arg, err = gpg_error (GPG_ERR_CARD_RESET);
indata, indatalen, else
outdata, outdatalen); err = card->app->fnc.sign (card->app, ctrl, keyidstr, hashalgo,
pincb, pincb_arg,
indata, indatalen,
outdata, outdatalen);
} }
unlock_card (card); unlock_card (card);
@ -1867,10 +1899,13 @@ app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling auth(%s)\n", log_debug ("slot %d app %s: calling auth(%s)\n",
card->slot, xstrapptype (card->app), keyidstr); card->slot, xstrapptype (card->app), keyidstr);
err = card->app->fnc.auth (card->app, ctrl, keyidstr, if (card->app->need_reset)
pincb, pincb_arg, err = gpg_error (GPG_ERR_CARD_RESET);
indata, indatalen, else
outdata, outdatalen); err = card->app->fnc.auth (card->app, ctrl, keyidstr,
pincb, pincb_arg,
indata, indatalen,
outdata, outdatalen);
} }
unlock_card (card); unlock_card (card);
@ -1910,11 +1945,14 @@ app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling decipher(%s)\n", log_debug ("slot %d app %s: calling decipher(%s)\n",
card->slot, xstrapptype (card->app), keyidstr); card->slot, xstrapptype (card->app), keyidstr);
err = card->app->fnc.decipher (card->app, ctrl, keyidstr, if (card->app->need_reset)
pincb, pincb_arg, err = gpg_error (GPG_ERR_CARD_RESET);
indata, indatalen, else
outdata, outdatalen, err = card->app->fnc.decipher (card->app, ctrl, keyidstr,
r_info); pincb, pincb_arg,
indata, indatalen,
outdata, outdatalen,
r_info);
} }
unlock_card (card); unlock_card (card);
@ -1949,8 +1987,11 @@ app_writecert (card_t card, ctrl_t ctrl,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling writecert(%s)\n", log_debug ("slot %d app %s: calling writecert(%s)\n",
card->slot, xstrapptype (card->app), certidstr); card->slot, xstrapptype (card->app), certidstr);
err = card->app->fnc.writecert (card->app, ctrl, certidstr, if (card->app->need_reset)
pincb, pincb_arg, data, datalen); err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.writecert (card->app, ctrl, certidstr,
pincb, pincb_arg, data, datalen);
} }
unlock_card (card); unlock_card (card);
@ -1985,8 +2026,11 @@ app_writekey (card_t card, ctrl_t ctrl,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling writekey(%s)\n", log_debug ("slot %d app %s: calling writekey(%s)\n",
card->slot, xstrapptype (card->app), keyidstr); card->slot, xstrapptype (card->app), keyidstr);
err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags, if (card->app->need_reset)
pincb, pincb_arg, keydata, keydatalen); err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags,
pincb, pincb_arg, keydata, keydatalen);
} }
unlock_card (card); unlock_card (card);
@ -2020,8 +2064,11 @@ app_genkey (card_t card, ctrl_t ctrl, const char *keynostr,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling genkey(%s)\n", log_debug ("slot %d app %s: calling genkey(%s)\n",
card->slot, xstrapptype (card->app), keynostr); card->slot, xstrapptype (card->app), keynostr);
err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags, if (card->app->need_reset)
createtime, pincb, pincb_arg); err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags,
createtime, pincb, pincb_arg);
} }
unlock_card (card); unlock_card (card);
@ -2080,8 +2127,11 @@ app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling change_pin(%s)\n", log_debug ("slot %d app %s: calling change_pin(%s)\n",
card->slot, xstrapptype (card->app), chvnostr); card->slot, xstrapptype (card->app), chvnostr);
err = card->app->fnc.change_pin (card->app, ctrl, if (card->app->need_reset)
chvnostr, flags, pincb, pincb_arg); err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.change_pin (card->app, ctrl,
chvnostr, flags, pincb, pincb_arg);
} }
unlock_card (card); unlock_card (card);
@ -2116,8 +2166,11 @@ app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
if (DBG_APP) if (DBG_APP)
log_debug ("slot %d app %s: calling check_pin(%s)\n", log_debug ("slot %d app %s: calling check_pin(%s)\n",
card->slot, xstrapptype (card->app), keyidstr); card->slot, xstrapptype (card->app), keyidstr);
err = card->app->fnc.check_pin (card->app, ctrl, keyidstr, if (card->app->need_reset)
pincb, pincb_arg); err = gpg_error (GPG_ERR_CARD_RESET);
else
err = card->app->fnc.check_pin (card->app, ctrl, keyidstr,
pincb, pincb_arg);
} }
unlock_card (card); unlock_card (card);
@ -2331,7 +2384,7 @@ send_serialno_and_app_status (card_t card, int with_apps, ctrl_t ctrl)
put_membuf_str (&mb, serial); put_membuf_str (&mb, serial);
for (a = card->app; a; a = a->next) for (a = card->app; a; a = a->next)
{ {
if (!a->fnc.with_keygrip) if (!a->fnc.with_keygrip || a->need_reset)
continue; continue;
any = 1; any = 1;
put_membuf (&mb, " ", 1); put_membuf (&mb, " ", 1);
@ -2517,7 +2570,7 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
a_prev = NULL; a_prev = NULL;
for (a = c->app; a; a = a->next) for (a = c->app; a; a = a->next)
{ {
if (!a->fnc.with_keygrip) if (!a->fnc.with_keygrip || a->need_reset)
continue; continue;
/* Note that we need to do a re-select even for the current /* Note that we need to do a re-select even for the current

View File

@ -420,7 +420,7 @@ cmd_switchapp (assuan_context_t ctx, char *line)
static const char hlp_learn[] = static const char hlp_learn[] =
"LEARN [--force] [--keypairinfo] [--multi]\n" "LEARN [--force] [--keypairinfo] [--reread] [--multi]\n"
"\n" "\n"
"Learn all useful information of the currently inserted card. When\n" "Learn all useful information of the currently inserted card. When\n"
"used without the force options, the command might do an INQUIRE\n" "used without the force options, the command might do an INQUIRE\n"
@ -433,7 +433,8 @@ static const char hlp_learn[] =
"error message.\n" "error message.\n"
"\n" "\n"
"With the option --keypairinfo only KEYPAIRINFO status lines are\n" "With the option --keypairinfo only KEYPAIRINFO status lines are\n"
"returned.\n" "returned. With the option --reread information from the card are\n"
"read again without the need for a reset (sone some cards).\n"
"\n" "\n"
"The response of this command is a list of status lines formatted as\n" "The response of this command is a list of status lines formatted as\n"
"this:\n" "this:\n"
@ -498,6 +499,8 @@ cmd_learn (assuan_context_t ctx, char *line)
int rc = 0; int rc = 0;
int only_keypairinfo = has_option (line, "--keypairinfo"); int only_keypairinfo = has_option (line, "--keypairinfo");
int opt_multi = has_option (line, "--multi"); int opt_multi = has_option (line, "--multi");
int opt_reread = has_option (line, "--reread");
unsigned int flags;
if ((rc = open_card (ctrl))) if ((rc = open_card (ctrl)))
return rc; return rc;
@ -559,11 +562,16 @@ cmd_learn (assuan_context_t ctx, char *line)
/* Let the application print out its collection of useful status /* Let the application print out its collection of useful status
information. */ information. */
flags = 0;
if (only_keypairinfo)
flags |= APP_LEARN_FLAG_KEYPAIRINFO;
if (opt_multi)
flags |= APP_LEARN_FLAG_MULTI;
if (opt_reread)
flags |= APP_LEARN_FLAG_REREAD;
if (!rc) if (!rc)
rc = app_write_learn_status rc = app_write_learn_status (ctrl->card_ctx, ctrl, flags);
(ctrl->card_ctx, ctrl,
( (only_keypairinfo? APP_LEARN_FLAG_KEYPAIRINFO : 0)
| (opt_multi? APP_LEARN_FLAG_MULTI : 0)) );
return rc; return rc;
} }