mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
card: Allow switching of cards and applications.
* tools/card-call-scd.c (struct card_cardlist_parm_s): Add field with_apps. (card_cardlist_cb): Handle the new with_apps flag. (scd_switchcard): New. (scd_switchapp): New. (scd_applist): New. (scd_serialno): Pass --all also in --demand mode. * tools/gpg-card.c (cmd_list): Simplify switching of cards. Add switching of alls. Print a list of apps per card. -- Note that the output format of "list --card" slightly changes: The current card is indicated with an asterisk. That should not harm any robust parsers which might already be in use. It is anyway a development version. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
718555874e
commit
bd85f9232a
@ -1,5 +1,5 @@
|
||||
/* card-call-scd.c - IPC calls to scdaemon.
|
||||
* Copyright (C) 2019 g10 Code GmbH
|
||||
* Copyright (C) 2019, 2020 g10 Code GmbH
|
||||
* Copyright (C) 2001-2003, 2006-2011, 2013 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2013-2015 Werner Koch
|
||||
*
|
||||
@ -88,6 +88,7 @@ struct genkey_parm_s
|
||||
struct card_cardlist_parm_s
|
||||
{
|
||||
gpg_error_t error;
|
||||
int with_apps;
|
||||
strlist_t list;
|
||||
};
|
||||
|
||||
@ -558,6 +559,45 @@ get_serialno_cb (void *opaque, const char *line)
|
||||
}
|
||||
|
||||
|
||||
/* Make the card with SERIALNO the current one. */
|
||||
gpg_error_t
|
||||
scd_switchcard (const char *serialno)
|
||||
{
|
||||
int err;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
err = start_agent (START_AGENT_SUPPRESS_ERRORS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
snprintf (line, DIM(line), "SCD SWITCHCARD -- %s", serialno);
|
||||
return assuan_transact (agent_ctx, line,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Make the app APPNAME the one on the card. */
|
||||
gpg_error_t
|
||||
scd_switchapp (const char *appname)
|
||||
{
|
||||
int err;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
if (appname && !*appname)
|
||||
appname = NULL;
|
||||
|
||||
err = start_agent (START_AGENT_SUPPRESS_ERRORS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
snprintf (line, DIM(line), "SCD SWITCHAPP --%s%s",
|
||||
appname? " ":"", appname? appname:"");
|
||||
return assuan_transact (agent_ctx, line,
|
||||
NULL, NULL, NULL, NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* For historical reasons OpenPGP cards simply use the numbers 1 to 3
|
||||
* for the <keyref>. Other cards and future versions of
|
||||
@ -1286,7 +1326,7 @@ scd_serialno (char **r_serialno, const char *demand)
|
||||
if (!demand)
|
||||
strcpy (line, "SCD SERIALNO --all");
|
||||
else
|
||||
snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand);
|
||||
snprintf (line, DIM(line), "SCD SERIALNO --demand=%s --all", demand);
|
||||
|
||||
err = assuan_transact (agent_ctx, line,
|
||||
NULL, NULL, NULL, NULL,
|
||||
@ -1407,11 +1447,25 @@ card_cardlist_cb (void *opaque, const char *line)
|
||||
for (n=0,s=line; hexdigitp (s); s++, n++)
|
||||
;
|
||||
|
||||
if (!n || (n&1) || *s)
|
||||
if (!n || (n&1))
|
||||
parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
|
||||
if (parm->with_apps)
|
||||
{
|
||||
/* Format of the stored string is the S/N, a space, and a
|
||||
* space separated list of appnames. */
|
||||
if (*s != ' ' || spacep (s+1) || !s[1])
|
||||
parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
|
||||
else /* We assume the rest of the line is well formatted. */
|
||||
add_to_strlist (&parm->list, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*s)
|
||||
parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
|
||||
else
|
||||
add_to_strlist (&parm->list, line);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1446,6 +1500,39 @@ scd_cardlist (strlist_t *result)
|
||||
}
|
||||
|
||||
|
||||
/* Return the serial numbers and appnames of the current card or, with
|
||||
* ALL given has true, of all cards currently inserted. */
|
||||
gpg_error_t
|
||||
scd_applist (strlist_t *result, int all)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct card_cardlist_parm_s parm;
|
||||
|
||||
memset (&parm, 0, sizeof parm);
|
||||
*result = NULL;
|
||||
|
||||
err = start_agent (START_AGENT_SUPPRESS_ERRORS);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
parm.with_apps = 1;
|
||||
err = assuan_transact (agent_ctx,
|
||||
all ? "SCD GETINFO all_active_apps"
|
||||
/**/: "SCD GETINFO active_apps",
|
||||
NULL, NULL, NULL, NULL,
|
||||
card_cardlist_cb, &parm);
|
||||
if (!err && parm.error)
|
||||
err = parm.error;
|
||||
|
||||
if (!err)
|
||||
*result = parm.list;
|
||||
else
|
||||
free_strlist (parm.list);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Change the PIN of an OpenPGP card or reset the retry counter.
|
||||
* CHVNO 1: Change the PIN
|
||||
|
116
tools/gpg-card.c
116
tools/gpg-card.c
@ -1,5 +1,5 @@
|
||||
/* gpg-card.c - An interactive tool to work with cards.
|
||||
* Copyright (C) 2019 g10 Code GmbH
|
||||
* Copyright (C) 2019, 2020 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -1000,53 +1000,118 @@ list_card (card_info_t info)
|
||||
|
||||
|
||||
|
||||
/* The LIST command. This also updates INFO. */
|
||||
/* The LIST command. This also updates INFO if needed. */
|
||||
static gpg_error_t
|
||||
cmd_list (card_info_t info, char *argstr)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int opt_cards;
|
||||
int opt_cards, opt_apps;
|
||||
strlist_t cards = NULL;
|
||||
strlist_t sl;
|
||||
estream_t fp = opt.interactive? NULL : es_stdout;
|
||||
int cardno, count;
|
||||
|
||||
int cardno = -1;
|
||||
char *appstr = NULL;
|
||||
int count;
|
||||
int need_learn = 0;
|
||||
int star;
|
||||
size_t snlen;
|
||||
const char *s;
|
||||
|
||||
if (!info)
|
||||
return print_help
|
||||
("LIST [--cards] [N]\n\n"
|
||||
"Show the content of the current card or with N given the N-th card.\n"
|
||||
"Option --cards lists available cards.",
|
||||
("LIST [--cards] [--apps] [N] [APP]\n\n"
|
||||
"Show the content of the current card.\n"
|
||||
"With N given select and list the n-th card;\n"
|
||||
"with APP also given select that application.\n"
|
||||
"To select an APP on the current card use '-' for N.\n"
|
||||
"Option --cards lists available cards.\n"
|
||||
"Option --apps lists additional card applications",
|
||||
0);
|
||||
|
||||
opt_cards = has_leading_option (argstr, "--cards");
|
||||
opt_apps = has_leading_option (argstr, "--apps");
|
||||
argstr = skip_options (argstr);
|
||||
|
||||
|
||||
if (digitp (argstr))
|
||||
if (digitp (argstr) || (*argstr == '-' && spacep (argstr+1)))
|
||||
{
|
||||
if (*argstr == '-' && (argstr[1] || spacep (argstr+1)))
|
||||
argstr++; /* Keep current card. */
|
||||
else
|
||||
{
|
||||
cardno = atoi (argstr);
|
||||
while (digitp (argstr))
|
||||
argstr++;
|
||||
}
|
||||
while (spacep (argstr))
|
||||
argstr++;
|
||||
}
|
||||
else
|
||||
cardno = -1;
|
||||
|
||||
|
||||
if (opt_cards)
|
||||
if (*argstr)
|
||||
{
|
||||
appstr = argstr;
|
||||
while (*argstr && !spacep (argstr))
|
||||
argstr++;
|
||||
while (spacep (argstr))
|
||||
argstr++;
|
||||
if (*argstr)
|
||||
{
|
||||
/* Extra arguments found. */
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (*argstr)
|
||||
{
|
||||
/* First argument needs to be a digit. */
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
if (!info->serialno)
|
||||
{
|
||||
/* This is probably the first call. We need to send a SERIALNO
|
||||
* command to scd so that our session knows all cards. */
|
||||
err = scd_serialno (NULL, NULL);
|
||||
if (err)
|
||||
goto leave;
|
||||
need_learn = 1;
|
||||
}
|
||||
|
||||
|
||||
if (opt_cards || opt_apps)
|
||||
{
|
||||
/* Note that with option --apps CARDS is here the list of all
|
||||
* apps. Format is "SERIALNO APPNAME {APPNAME}". We print the
|
||||
* card number in the first column. */
|
||||
if (opt_apps)
|
||||
err = scd_applist (&cards, opt_cards);
|
||||
else
|
||||
err = scd_cardlist (&cards);
|
||||
if (err)
|
||||
goto leave;
|
||||
for (count = 0, sl = cards; sl; sl = sl->next, count++)
|
||||
tty_fprintf (fp, "%d %s\n", count, sl->d);
|
||||
{
|
||||
if (info && info->serialno)
|
||||
{
|
||||
s = strchr (sl->d, ' ');
|
||||
if (s)
|
||||
snlen = s - sl->d;
|
||||
else
|
||||
snlen = strlen (sl->d);
|
||||
star = (strlen (info->serialno) == snlen
|
||||
&& !memcmp (info->serialno, sl->d, snlen));
|
||||
}
|
||||
else
|
||||
star = 0;
|
||||
tty_fprintf (fp, "%d%c %s\n", count, star? '*':' ', sl->d);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cardno != -1)
|
||||
{
|
||||
/* Switch to the requested card. */
|
||||
err = scd_cardlist (&cards);
|
||||
if (err)
|
||||
goto leave;
|
||||
@ -1058,12 +1123,23 @@ cmd_list (card_info_t info, char *argstr)
|
||||
err = gpg_error (GPG_ERR_INV_INDEX);
|
||||
goto leave;
|
||||
}
|
||||
err = scd_serialno (NULL, sl->d);
|
||||
if (err)
|
||||
goto leave;
|
||||
err = scd_switchcard (sl->d);
|
||||
need_learn = 1;
|
||||
}
|
||||
|
||||
if (appstr && *appstr)
|
||||
{
|
||||
/* Switch to the requested app. */
|
||||
err = scd_switchapp (appstr);
|
||||
if (err)
|
||||
goto leave;
|
||||
need_learn = 1;
|
||||
}
|
||||
|
||||
if (need_learn)
|
||||
err = scd_learn (info);
|
||||
else
|
||||
err = 0;
|
||||
if (!err)
|
||||
list_card (info);
|
||||
}
|
||||
@ -3341,7 +3417,7 @@ interactive_loop (void)
|
||||
|
||||
if (!info)
|
||||
{
|
||||
/* Copy the pending help arg into our answer. Noe that
|
||||
/* Copy the pending help arg into our answer. Note that
|
||||
* help_arg points into answer. */
|
||||
p = xstrdup (help_arg);
|
||||
help_arg = NULL;
|
||||
|
@ -204,6 +204,10 @@ const char *app_type_string (app_type_t app_type);
|
||||
|
||||
gpg_error_t scd_apdu (const char *hexapdu, unsigned int *r_sw,
|
||||
unsigned char **r_data, size_t *r_datalen);
|
||||
|
||||
gpg_error_t scd_switchcard (const char *serialno);
|
||||
gpg_error_t scd_switchapp (const char *appname);
|
||||
|
||||
gpg_error_t scd_learn (card_info_t info);
|
||||
gpg_error_t scd_getattr (const char *name, struct card_info_s *info);
|
||||
gpg_error_t scd_setattr (const char *name,
|
||||
@ -214,10 +218,12 @@ gpg_error_t scd_writekey (const char *keyref, int force, const char *keygrip);
|
||||
gpg_error_t scd_genkey (const char *keyref, int force, const char *algo,
|
||||
u32 *createtime);
|
||||
gpg_error_t scd_serialno (char **r_serialno, const char *demand);
|
||||
|
||||
gpg_error_t scd_readcert (const char *certidstr,
|
||||
void **r_buf, size_t *r_buflen);
|
||||
gpg_error_t scd_readkey (const char *keyrefstr, gcry_sexp_t *r_result);
|
||||
gpg_error_t scd_cardlist (strlist_t *result);
|
||||
gpg_error_t scd_applist (strlist_t *result, int all);
|
||||
gpg_error_t scd_change_pin (const char *pinref, int reset_mode);
|
||||
gpg_error_t scd_checkpin (const char *serialno);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user