scd: Add option --all to the SERIALNO command.

* scd/command.c (cmd_serialno): Add option --all.
(open_card_with_request): Implement that option.
* scd/app.c (select_all_additional_applications_internal): New.
(select_additional_application): Add mode to call new function.
--

This option is currently only useful for Yubikeys and basically
ignored with other cards.  Its use is

  SERIALNO --all
  LEARN --force --multi

which will then print keypairinfo and other stuff for the OpenPGP and
PIV application of a Yubikey.  Scute is going to use this to allow
using certificates from OpenPGP and PIV at the same time.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2019-09-04 13:38:50 +02:00
parent fa25837942
commit 9a0d8f2d89
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 105 additions and 11 deletions

View File

@ -753,6 +753,78 @@ select_additional_application_internal (card_t card, apptype_t req_apptype)
return err;
}
/* Add all possible additional applications to the card context but do
* not change the current one. This current works only for Yubikeys. */
static gpg_error_t
select_all_additional_applications_internal (card_t card)
{
gpg_error_t err = 0;
apptype_t candidates[3];
int i, j;
if (card->cardtype == CARDTYPE_YUBIKEY)
{
candidates[0] = APPTYPE_OPENPGP;
candidates[1] = APPTYPE_PIV;
candidates[2] = APPTYPE_NONE;
}
else
{
candidates[0] = APPTYPE_NONE;
}
/* Find the app and run the select. */
for (i=0; app_priority_list[i].apptype; i++)
{
app_t app, app_r, app_prev;
for (j=0; candidates[j]; j++)
if (candidates[j] == app_priority_list[i].apptype
&& is_app_allowed (app_priority_list[i].name))
break;
if (!candidates[j])
continue;
for (app = card->app; app; app = app->next)
if (app->apptype == candidates[j])
break;
if (app)
continue; /* Already on the list of apps. */
app = xtrycalloc (1, sizeof *app);
if (!app)
{
err = gpg_error_from_syserror ();
log_info ("error allocating app context: %s\n", gpg_strerror (err));
goto leave;
}
app->card = card;
err = app_priority_list[i].select_func (app);
if (err)
{
log_error ("error selecting additional app '%s': %s - skipped\n",
strapptype (candidates[j]), gpg_strerror (err));
err = 0;
xfree (app);
}
else
{
/* Append to the list of apps. */
app_prev = card->app;
for (app_r=app_prev->next; app_r; app_prev=app_r, app_r=app_r->next)
;
app_prev->next = app;
log_info ("added app '%s' to the card context\n",
strapptype (app->apptype));
}
}
leave:
return err;
}
/* This function needs to be called with the NAME of the new
* application to be selected on CARD. On success the application is
* added to the list of the card's active applications as currently
@ -765,9 +837,14 @@ select_additional_application (ctrl_t ctrl, const char *name)
apptype_t req_apptype;
card_t card;
req_apptype = apptype_from_name (name);
if (!req_apptype)
return gpg_error (GPG_ERR_NOT_FOUND);
if (!name)
req_apptype = 0;
else
{
req_apptype = apptype_from_name (name);
if (!req_apptype)
return gpg_error (GPG_ERR_NOT_FOUND);
}
card = ctrl->card_ctx;
if (!card)
@ -777,11 +854,18 @@ select_additional_application (ctrl_t ctrl, const char *name)
if (err)
return err;
err = select_additional_application_internal (card, req_apptype);
if (!err)
if (req_apptype)
{
ctrl->current_apptype = req_apptype;
log_debug ("current_apptype is set to %s\n", name);
err = select_additional_application_internal (card, req_apptype);
if (!err)
{
ctrl->current_apptype = req_apptype;
log_debug ("current_apptype is set to %s\n", name);
}
}
else
{
err = select_all_additional_applications_internal (card);
}
unlock_card (card);

View File

@ -218,10 +218,12 @@ open_card (ctrl_t ctrl)
return select_application (ctrl, NULL, &ctrl->card_ctx, 0, NULL, 0);
}
/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */
/* Explicitly open a card for a specific use of APPTYPE or SERIALNO.
* If OPT_ALL ist set also add all possible additional apps. */
static gpg_error_t
open_card_with_request (ctrl_t ctrl,
const char *apptypestr, const char *serialno)
const char *apptypestr, const char *serialno,
int opt_all)
{
gpg_error_t err;
unsigned char *serialno_bin = NULL;
@ -254,6 +256,8 @@ open_card_with_request (ctrl_t ctrl,
err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1,
serialno_bin, serialno_bin_len);
if (!err && opt_all)
err = select_additional_application (ctrl, APPTYPE_NONE);
leave:
xfree (serialno_bin);
@ -262,7 +266,7 @@ open_card_with_request (ctrl_t ctrl,
static const char hlp_serialno[] =
"SERIALNO [--demand=<serialno>] [<apptype>]\n"
"SERIALNO [--demand=<serialno>] [--all] [<apptype>]\n"
"\n"
"Return the serial number of the card using a status response. This\n"
"function should be used to check for the presence of a card.\n"
@ -270,6 +274,9 @@ static const char hlp_serialno[] =
"If --demand is given, an application on the card with SERIALNO is\n"
"selected and an error is returned if no such card available.\n"
"\n"
"If --all is given, all possible other applications of the card are\n"
"will also be selected for on-the-fly swicthing.\n"
"\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"
"The default is to auto-select the application using a hardwired\n"
@ -291,6 +298,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
int rc = 0;
char *serial;
const char *demand;
int opt_all = has_option (line, "--all");
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
@ -308,11 +316,13 @@ cmd_serialno (assuan_context_t ctx, char *line)
else
demand = NULL;
line = skip_options (line);
/* Clear the remove flag so that the open_card is able to reread it. */
if (ctrl->server_local->card_removed)
ctrl->server_local->card_removed = 0;
if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand)))
if ((rc = open_card_with_request (ctrl, *line? line:NULL, demand, opt_all)))
{
ctrl->server_local->card_removed = 1;
return rc;