1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-03 12:11:33 +01:00

scd: Make SERIALNO --all work correctly and use it.

* scd/app.c (maybe_switch_app): Factor reselect code out to ...
(run_reselect): new.
(app_write_learn_status): Tweak diagnostics.
(app_do_with_keygrip): Run reselect if a card has more than one
switchable application.

* agent/call-scd.c (agent_card_serialno): Ditto.
* tools/card-call-scd.c (start_agent): Use option --all with SERIALNO.
(scd_serialno): Ditto.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-01-13 12:08:23 +01:00
parent 15028627a1
commit 0e48aa0849
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
5 changed files with 94 additions and 57 deletions

View File

@ -854,7 +854,7 @@ agent_card_serialno (ctrl_t ctrl, char **r_serialno, const char *demand)
return rc; return rc;
if (!demand) if (!demand)
strcpy (line, "SERIALNO"); strcpy (line, "SERIALNO --all");
else else
snprintf (line, DIM(line), "SERIALNO --demand=%s", demand); snprintf (line, DIM(line), "SERIALNO --demand=%s", demand);

View File

@ -764,13 +764,13 @@ get_dispserialno (app_t app, int failmode)
/* The verify command can be used to retrieve the security status of /* The verify command can be used to retrieve the security status of
* the card. Given the PIN name (e.g. "PIV.80" for thge application * the card. Given the PIN name (e.g. "PIV.80" for the application
* pin, a status is returned: * pin, a status is returned:
* *
* -1 = Error retrieving the data, * -1 = Error retrieving the data,
* -2 = No such PIN, * -2 = No such PIN,
* -3 = PIN blocked, * -3 = PIN blocked,
* -5 = Verify still valid, * -5 = Verified and still valid,
* n >= 0 = Number of verification attempts left. * n >= 0 = Number of verification attempts left.
*/ */
static int static int

139
scd/app.c
View File

@ -300,7 +300,7 @@ is_app_allowed (const char *name)
* to switch to the requested application. * to switch to the requested application.
* Other code - Switching is not possible. * Other code - Switching is not possible.
* *
* If SERIALNO_BIN is not NULL a coflict is onl asserted if the * If SERIALNO_BIN is not NULL a conflict is only asserted if the
* serialno of the card matches. * serialno of the card matches.
*/ */
gpg_error_t gpg_error_t
@ -1032,7 +1032,7 @@ card_unref_locked (card_t card)
FF 02 00 = Serial number from Yubikey config FF 02 00 = Serial number from Yubikey config
FF 7F 00 = No serialno. FF 7F 00 = No serialno.
All other serial number not starting with FF are used as they are. All other serial numbers not starting with FF are used as they are.
*/ */
gpg_error_t gpg_error_t
app_munge_serialno (card_t card) app_munge_serialno (card_t card)
@ -1094,6 +1094,46 @@ app_get_serialno (app_t app)
} }
/* Helper to run the reselect function. */
static gpg_error_t
run_reselect (ctrl_t ctrl, card_t c, app_t a, app_t a_prev)
{
gpg_error_t err;
if (!a->fnc.reselect)
{
log_info ("slot %d, app %s: re-select not implemented\n",
c->slot, xstrapptype (a));
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
}
/* Give the current app a chance to save some state before another
* app is selected. We ignore errors here because that state saving
* (e.g. putting PINs into a cache) is a convenience feature and not
* required to always work. */
if (a_prev && a_prev->fnc.prep_reselect)
{
err = a_prev->fnc.prep_reselect (a_prev, ctrl);
if (err)
log_error ("slot %d, app %s: preparing re-select from %s failed: %s\n",
c->slot, xstrapptype (a),
xstrapptype (a_prev), gpg_strerror (err));
}
err = a->fnc.reselect (a, ctrl);
if (err)
{
log_error ("slot %d, app %s: error re-selecting: %s\n",
c->slot, xstrapptype (a), gpg_strerror (err));
return err;
}
if (DBG_APP)
log_debug ("slot %d, app %s: re-selected\n", c->slot, xstrapptype (a));
return 0;
}
/* Check that the card has been initialized and whether we need to /* Check that the card has been initialized and whether we need to
* switch to another application on the same card. Switching means * switch to another application on the same card. Switching means
* that the new active app will be moved to the head of the list at * that the new active app will be moved to the head of the list at
@ -1162,33 +1202,9 @@ maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
if (!app) if (!app)
return gpg_error (GPG_ERR_WRONG_CARD); return gpg_error (GPG_ERR_WRONG_CARD);
if (!app->fnc.reselect) err = run_reselect (ctrl, card, app, app_prev);
{
log_error ("oops: reselect function missing for '%s'\n",
strapptype (app->apptype));
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
}
/* Give the current app a chance to save some state before another
* app is selected. We ignore errors here because that state saving
* (e.g. putting PINs into a cache) is a convenience feature and not
* required to always work. */
if (app_prev && app_prev->fnc.prep_reselect)
{
err = app_prev->fnc.prep_reselect (app_prev, ctrl);
if (err)
log_info ("card %d: preparing re-select failed for '%s': %s\n",
card->slot, xstrapptype (app_prev), gpg_strerror (err));
err = 0;
}
err = app->fnc.reselect (app, ctrl);
if (err) if (err)
{ return err;
log_error ("card %d: error re-selecting '%s': %s\n",
card->slot, xstrapptype (app), gpg_strerror (err));
return err;
}
/* Swap APP with the head of the app list if needed. Note that APP /* Swap APP with the head of the app list if needed. Note that APP
* is not the head of the list. */ * is not the head of the list. */
@ -1200,9 +1216,9 @@ maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
} }
if (opt.verbose) if (opt.verbose)
log_info ("card %d: %s '%s'\n", log_info ("slot %d, app %s: %s\n",
card->slot, app_prev? "switched to":"re-selected", card->slot, xstrapptype (app),
xstrapptype (app)); app_prev? "switched":"re-selected");
ctrl->current_apptype = app->apptype; ctrl->current_apptype = app->apptype;
@ -1271,8 +1287,10 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
{ {
tmperr = last_app->fnc.prep_reselect (last_app, ctrl); tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
if (tmperr) if (tmperr)
log_info ("card %d: preparing re-select failed for '%s'" log_info ("slot %d, app %s:"
": %s\n", card->slot, xstrapptype (last_app), " preparing re-select from %s failed: %s\n",
card->slot, xstrapptype (app),
xstrapptype (last_app),
gpg_strerror (tmperr)); gpg_strerror (tmperr));
} }
any_reselect = 1; any_reselect = 1;
@ -1290,9 +1308,10 @@ app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
{ {
tmperr = last_app->fnc.prep_reselect (last_app, ctrl); tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
if (tmperr) if (tmperr)
log_info ("card %d: preparing re-select failed for '%s'" log_info ("slot %d, app %s:"
": %s\n", card->slot, xstrapptype (last_app), " preparing re-select from %s failed: %s\n",
gpg_strerror (tmperr)); card->slot, xstrapptype (app),
xstrapptype (last_app), gpg_strerror (tmperr));
} }
err2 = app->fnc.reselect (app, ctrl); err2 = app->fnc.reselect (app, ctrl);
if (err2) if (err2)
@ -2027,8 +2046,9 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
int capability) int capability)
{ {
int locked = 0; int locked = 0;
gpg_error_t err;
card_t c; card_t c;
app_t a; app_t a, a_prev;
npth_mutex_lock (&card_list_lock); npth_mutex_lock (&card_list_lock);
@ -2040,26 +2060,43 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
goto leave_the_loop; goto leave_the_loop;
} }
locked = 1; locked = 1;
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)
if (DBG_APP) continue;
log_debug ("slot %d app %s: calling with_keygrip(action=%d)\n",
c->slot, xstrapptype (a), action); /* Note that we need to do a re-select even for the current
if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability)) * app because the last selected application (e.g. after
goto leave_the_loop; * init) might be a different one and we do not run
} * maybe_switch_app here. Of course we we do this only iff
* we have an additional app. */
if (c->app->next)
{
if (run_reselect (ctrl, c, a, a_prev))
continue;
}
a_prev = a;
if (DBG_APP)
log_debug ("slot %d, app %s: calling with_keygrip(%s)\n",
c->slot, xstrapptype (a),
action == KEYGRIP_ACTION_SEND_DATA? "send_data":
action == KEYGRIP_ACTION_WRITE_STATUS? "write_data":
action == KEYGRIP_ACTION_LOOKUP? "lookup":"?");
if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability))
goto leave_the_loop; /* ACTION_LOOKUP succeeded. */
}
/* Select the first app again. */
if (c->app->next)
run_reselect (ctrl, c, c->app, a_prev);
unlock_card (c); unlock_card (c);
locked = 0; locked = 0;
} }
leave_the_loop: leave_the_loop:
/* FIXME: Add app switching logic. The above code assumes that the
* actions can be performend without switching. This needs to be
* checked. */
/* Force switching of the app if the selected one is not the current /* Force switching of the app if the selected one is not the current
* one. Changing the current apptype is sufficient to do this. */ * one. Changing the current apptype is sufficient to do this. */
if (c && c->app && c->app->apptype != a->apptype) if (c && c->app && c->app->apptype != a->apptype)

View File

@ -282,7 +282,7 @@ static const char hlp_serialno[] =
"selected and an error is returned if no such card available.\n" "selected and an error is returned if no such card available.\n"
"\n" "\n"
"If --all is given, all possible other applications of the card are\n" "If --all is given, all possible other applications of the card are\n"
"also selected to prepare for \"LEARN --force --multi\".\n" "also selected to prepare for things like \"LEARN --force --multi\".\n"
"\n" "\n"
"If APPTYPE is given, an application of that type is selected and an\n" "If APPTYPE is given, an application of that type is selected and an\n"
"error is returned if the application is not supported or available.\n" "error is returned if the application is not supported or available.\n"

View File

@ -360,7 +360,7 @@ start_agent (unsigned int flags)
err = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2); err = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
if (!err) if (!err)
err = assuan_transact (agent_ctx, "SCD SERIALNO", err = assuan_transact (agent_ctx, "SCD SERIALNO --all",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
learn_status_cb, &info); learn_status_cb, &info);
if (err && !(flags & START_AGENT_SUPPRESS_ERRORS)) if (err && !(flags & START_AGENT_SUPPRESS_ERRORS))
@ -1284,7 +1284,7 @@ scd_serialno (char **r_serialno, const char *demand)
return err; return err;
if (!demand) if (!demand)
strcpy (line, "SCD SERIALNO"); strcpy (line, "SCD SERIALNO --all");
else else
snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand); snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand);