mirror of
git://git.gnupg.org/gnupg.git
synced 2025-05-24 16:43:28 +02:00
scd: New commands SWITCHCARD and SWITCHAPP.
* scd/app.c: Include membuf.h. (app_switch_current_card): New. (send_card_and_app_list): Factor code out to ... (send_serialno_and_app_status): new. (app_send_card_list): New. (app_send_active_apps): New. (app_switch_active_app): New. * scd/command.c (cmd_switchcard): New. (cmd_switchapp): New. (register_commands): Register new commands. (cmd_getinfo): New sub-commands "active_apps" and "all_active_apps". -- These new commands allow to switch between known cards and are in particular useful for the gpg-card tool. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
dd61164410
commit
718555874e
@ -229,6 +229,7 @@ const char *strapptype (apptype_t t);
|
|||||||
|
|
||||||
void app_update_priority_list (const char *arg);
|
void app_update_priority_list (const char *arg);
|
||||||
gpg_error_t app_send_card_list (ctrl_t ctrl);
|
gpg_error_t app_send_card_list (ctrl_t ctrl);
|
||||||
|
gpg_error_t app_send_active_apps (card_t card, ctrl_t ctrl);
|
||||||
char *card_get_serialno (card_t card);
|
char *card_get_serialno (card_t card);
|
||||||
char *app_get_serialno (app_t app);
|
char *app_get_serialno (app_t app);
|
||||||
|
|
||||||
@ -242,6 +243,13 @@ gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app,
|
|||||||
int scan, const unsigned char *serialno_bin,
|
int scan, const unsigned char *serialno_bin,
|
||||||
size_t serialno_bin_len);
|
size_t serialno_bin_len);
|
||||||
gpg_error_t select_additional_application (ctrl_t ctrl, const char *name);
|
gpg_error_t select_additional_application (ctrl_t ctrl, const char *name);
|
||||||
|
|
||||||
|
gpg_error_t app_switch_current_card (ctrl_t ctrl,
|
||||||
|
const unsigned char *serialno,
|
||||||
|
size_t serialnolen);
|
||||||
|
gpg_error_t app_switch_active_app (card_t card, ctrl_t ctrl,
|
||||||
|
const char *appname);
|
||||||
|
|
||||||
char *get_supported_applications (void);
|
char *get_supported_applications (void);
|
||||||
|
|
||||||
card_t card_ref (card_t card);
|
card_t card_ref (card_t card);
|
||||||
|
177
scd/app.c
177
scd/app.c
@ -29,11 +29,14 @@
|
|||||||
#include "iso7816.h"
|
#include "iso7816.h"
|
||||||
#include "apdu.h"
|
#include "apdu.h"
|
||||||
#include "../common/tlv.h"
|
#include "../common/tlv.h"
|
||||||
|
#include "../common/membuf.h"
|
||||||
|
|
||||||
|
|
||||||
/* Forward declaration of internal function. */
|
/* Forward declaration of internal function. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
select_additional_application_internal (card_t card, apptype_t req_apptype);
|
select_additional_application_internal (card_t card, apptype_t req_apptype);
|
||||||
|
static gpg_error_t
|
||||||
|
send_serialno_and_app_status (card_t card, int with_apps, ctrl_t ctrl);
|
||||||
|
|
||||||
/* Lock to protect the list of cards and its associated
|
/* Lock to protect the list of cards and its associated
|
||||||
* applications. */
|
* applications. */
|
||||||
@ -730,6 +733,56 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Switch the current card for the session CTRL and print a SERIALNO
|
||||||
|
* status line on success. (SERIALNO, SERIALNOLEN) is the binary s/n
|
||||||
|
* of the card to switch to. */
|
||||||
|
gpg_error_t
|
||||||
|
app_switch_current_card (ctrl_t ctrl,
|
||||||
|
const unsigned char *serialno, size_t serialnolen)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
card_t card, cardtmp;
|
||||||
|
|
||||||
|
npth_mutex_lock (&card_list_lock);
|
||||||
|
|
||||||
|
if (!ctrl->card_ctx)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (serialno && serialnolen)
|
||||||
|
{
|
||||||
|
for (card = card_top; card; card = card->next)
|
||||||
|
{
|
||||||
|
if (card->serialnolen == serialnolen
|
||||||
|
&& !memcmp (card->serialno, serialno, card->serialnolen))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!card)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: We do not use card_ref here because we only swap the
|
||||||
|
* context of the current session and there is no chance of a
|
||||||
|
* context switch. This also works if the card stays the same. */
|
||||||
|
cardtmp = ctrl->card_ctx;
|
||||||
|
ctrl->card_ctx = card;
|
||||||
|
card->ref_count++;
|
||||||
|
card_unref_locked (cardtmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print the status line. */
|
||||||
|
err = send_serialno_and_app_status (ctrl->card_ctx, 0, ctrl);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
npth_mutex_unlock (&card_list_lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
select_additional_application_internal (card_t card, apptype_t req_apptype)
|
select_additional_application_internal (card_t card, apptype_t req_apptype)
|
||||||
{
|
{
|
||||||
@ -1975,13 +2028,58 @@ compare_card_list_items (const void *arg_a, const void *arg_b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Send status lines with the serialno of all inserted cards. */
|
/* Helper for send_card_and_app_list and app_switch_active_app. */
|
||||||
gpg_error_t
|
static gpg_error_t
|
||||||
app_send_card_list (ctrl_t ctrl)
|
send_serialno_and_app_status (card_t card, int with_apps, ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
app_t a;
|
||||||
|
char buf[65];
|
||||||
|
char *p;
|
||||||
|
membuf_t mb;
|
||||||
|
|
||||||
|
if (DIM (buf) < 2 * card->serialnolen + 1)
|
||||||
|
return 0; /* Oops. */
|
||||||
|
|
||||||
|
bin2hex (card->serialno, card->serialnolen, buf);
|
||||||
|
if (with_apps)
|
||||||
|
{
|
||||||
|
/* Note that in case the additional applications have not yet been
|
||||||
|
* added to the card context (which is commonly done by means of
|
||||||
|
* "SERIALNO --all", we do that here. */
|
||||||
|
err = select_all_additional_applications_internal (card);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
init_membuf (&mb, 256);
|
||||||
|
put_membuf_str (&mb, buf);
|
||||||
|
for (a = card->app; a; a = a->next)
|
||||||
|
{
|
||||||
|
if (!a->fnc.with_keygrip)
|
||||||
|
continue;
|
||||||
|
put_membuf (&mb, " ", 1);
|
||||||
|
put_membuf_str (&mb, xstrapptype (a));
|
||||||
|
}
|
||||||
|
put_membuf (&mb, "", 1);
|
||||||
|
p = get_membuf (&mb, NULL);
|
||||||
|
if (!p)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
send_status_direct (ctrl, "SERIALNO", p);
|
||||||
|
xfree (p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
send_status_direct (ctrl, "SERIALNO", buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Common code for app_send_card_list and app_send_active_apps. */
|
||||||
|
static gpg_error_t
|
||||||
|
send_card_and_app_list (ctrl_t ctrl, card_t wantcard, int with_apps)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
card_t c;
|
card_t c;
|
||||||
char buf[65];
|
|
||||||
card_t *cardlist = NULL;
|
card_t *cardlist = NULL;
|
||||||
int n, ncardlist;
|
int n, ncardlist;
|
||||||
|
|
||||||
@ -2000,11 +2098,11 @@ app_send_card_list (ctrl_t ctrl)
|
|||||||
|
|
||||||
for (n=0; n < ncardlist; n++)
|
for (n=0; n < ncardlist; n++)
|
||||||
{
|
{
|
||||||
if (DIM (buf) < 2 * cardlist[n]->serialnolen + 1)
|
if (wantcard && wantcard != cardlist[n])
|
||||||
continue;
|
continue;
|
||||||
|
err = send_serialno_and_app_status (cardlist[n], with_apps, ctrl);
|
||||||
bin2hex (cardlist[n]->serialno, cardlist[n]->serialnolen, buf);
|
if (err)
|
||||||
send_status_direct (ctrl, "SERIALNO", buf);
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
@ -2016,6 +2114,69 @@ app_send_card_list (ctrl_t ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Send status lines with the serialno of all inserted cards. */
|
||||||
|
gpg_error_t
|
||||||
|
app_send_card_list (ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
return send_card_and_app_list (ctrl, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Send status lines with the serialno and appname of the current card
|
||||||
|
* or of all cards if CARD is NULL. */
|
||||||
|
gpg_error_t
|
||||||
|
app_send_active_apps (card_t card, ctrl_t ctrl)
|
||||||
|
{
|
||||||
|
return send_card_and_app_list (ctrl, card, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Switch to APPNAME and print a respective status line with that app
|
||||||
|
* listed first. If APPNAME is NULL or the empty string no switching
|
||||||
|
* is done but the status line is printed anyway. */
|
||||||
|
gpg_error_t
|
||||||
|
app_switch_active_app (card_t card, ctrl_t ctrl, const char *appname)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
apptype_t apptype;
|
||||||
|
|
||||||
|
if (!card)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
err = lock_card (card, ctrl);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Note that in case the additional applications have not yet been
|
||||||
|
* added to the card context (which is commonly done by means of
|
||||||
|
* "SERIALNO --all", we do that here. */
|
||||||
|
err = select_all_additional_applications_internal (card);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
if (appname && *appname)
|
||||||
|
{
|
||||||
|
apptype = apptype_from_name (appname);
|
||||||
|
if (!apptype)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl->current_apptype = apptype;
|
||||||
|
err = maybe_switch_app (ctrl, card, NULL);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print the status line. */
|
||||||
|
err = send_serialno_and_app_status (card, 1, ctrl);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
unlock_card (card);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Execute an action for each app. ACTION can be one of:
|
/* Execute an action for each app. ACTION can be one of:
|
||||||
*
|
*
|
||||||
* - KEYGRIP_ACTION_SEND_DATA
|
* - KEYGRIP_ACTION_SEND_DATA
|
||||||
|
@ -287,8 +287,7 @@ static const char hlp_serialno[] =
|
|||||||
"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"
|
||||||
"The default is to auto-select the application using a hardwired\n"
|
"The default is to auto-select the application using a hardwired\n"
|
||||||
"preference system. Note, that a future extension to this function\n"
|
"preference system.\n"
|
||||||
"may enable specifying a list and order of applications to try.\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"This function is special in that it can be used to reset the card.\n"
|
"This function is special in that it can be used to reset the card.\n"
|
||||||
"Most other functions will return an error when a card change has\n"
|
"Most other functions will return an error when a card change has\n"
|
||||||
@ -354,6 +353,70 @@ cmd_serialno (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const char hlp_switchcard[] =
|
||||||
|
"SWITCHCARD [<serialno>]\n"
|
||||||
|
"\n"
|
||||||
|
"Make the card with SERIALNO the current card.\n"
|
||||||
|
"The command \"getinfo card_list\" can be used to list\n"
|
||||||
|
"the serial numbers of inserted and known cards. Note\n"
|
||||||
|
"that the command \"SERIALNO\" can be used to refresh\n"
|
||||||
|
"the list of known cards. A simple SERIALNO status\n"
|
||||||
|
"is printed on success.";
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_switchcard (assuan_context_t ctx, char *line)
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
unsigned char *sn_bin = NULL;
|
||||||
|
size_t sn_bin_len = 0;
|
||||||
|
|
||||||
|
if ((err = open_card (ctrl)))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
line = skip_options (line);
|
||||||
|
|
||||||
|
if (*line)
|
||||||
|
{
|
||||||
|
sn_bin = hex_to_buffer (line, &sn_bin_len);
|
||||||
|
if (!sn_bin)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that an SN_BIN of NULL will only print the status. */
|
||||||
|
err = app_switch_current_card (ctrl, sn_bin, sn_bin_len);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
xfree (sn_bin);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char hlp_switchapp[] =
|
||||||
|
"SWITCHAPP [<appname>]\n"
|
||||||
|
"\n"
|
||||||
|
"Make APPNAME the active application for the current card.\n"
|
||||||
|
"Only some cards support switching between application; the\n"
|
||||||
|
"command \"getinfo active_app\" can be used to get a list of\n"
|
||||||
|
"applications which can be switched to. A SERIALNO status\n"
|
||||||
|
"including the active appname is printed on success.";
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_switchapp (assuan_context_t ctx, char *line)
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
|
||||||
|
if ((err = open_card (ctrl)))
|
||||||
|
return err;
|
||||||
|
|
||||||
|
line = skip_options (line);
|
||||||
|
return app_switch_active_app (ctrl->card_ctx, ctrl, line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_learn[] =
|
static const char hlp_learn[] =
|
||||||
"LEARN [--force] [--keypairinfo] [--multi]\n"
|
"LEARN [--force] [--keypairinfo] [--multi]\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -1641,10 +1704,12 @@ static const char hlp_getinfo[] =
|
|||||||
" app_list - Return a list of supported applications. One\n"
|
" app_list - Return a list of supported applications. One\n"
|
||||||
" application per line, fields delimited by colons,\n"
|
" application per line, fields delimited by colons,\n"
|
||||||
" first field is the name.\n"
|
" first field is the name.\n"
|
||||||
" card_list - Return a list of serial numbers of active cards,\n"
|
" card_list - Return a list of serial numbers of all inserted cards.\n"
|
||||||
" using a status response.\n"
|
" active_apps - Return a list of active apps on the current card.\n"
|
||||||
|
" all_active_apps\n"
|
||||||
|
" - Return a list of active apps on all inserted cards.\n"
|
||||||
" cmd_has_option CMD OPT\n"
|
" cmd_has_option CMD OPT\n"
|
||||||
" - Returns OK if command CMD has option OPT.\n";
|
" - Returns OK if command CMD has option OPT.\n";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_getinfo (assuan_context_t ctx, char *line)
|
cmd_getinfo (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
@ -1753,6 +1818,19 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
rc = app_send_card_list (ctrl);
|
rc = app_send_card_list (ctrl);
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (line, "active_apps"))
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
if (!ctrl->card_ctx)
|
||||||
|
rc = 0; /* No current card - no active apps. */
|
||||||
|
else
|
||||||
|
rc = app_send_active_apps (ctrl->card_ctx, ctrl);
|
||||||
|
}
|
||||||
|
else if (!strcmp (line, "all_active_apps"))
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
rc = app_send_active_apps (NULL, ctrl);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
|
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
|
||||||
return rc;
|
return rc;
|
||||||
@ -2069,6 +2147,8 @@ register_commands (assuan_context_t ctx)
|
|||||||
const char * const help;
|
const char * const help;
|
||||||
} table[] = {
|
} table[] = {
|
||||||
{ "SERIALNO", cmd_serialno, hlp_serialno },
|
{ "SERIALNO", cmd_serialno, hlp_serialno },
|
||||||
|
{ "SWITCHCARD", cmd_switchcard,hlp_switchcard },
|
||||||
|
{ "SWITCHAPP", cmd_switchapp,hlp_switchapp },
|
||||||
{ "LEARN", cmd_learn, hlp_learn },
|
{ "LEARN", cmd_learn, hlp_learn },
|
||||||
{ "READCERT", cmd_readcert, hlp_readcert },
|
{ "READCERT", cmd_readcert, hlp_readcert },
|
||||||
{ "READKEY", cmd_readkey, hlp_readkey },
|
{ "READKEY", cmd_readkey, hlp_readkey },
|
||||||
|
Loading…
x
Reference in New Issue
Block a user