2003-08-05 17:11:04 +00:00
|
|
|
|
/* app.c - Application selection.
|
2016-12-28 12:29:17 +09:00
|
|
|
|
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*
|
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
2007-07-04 19:49:40 +00:00
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-08-05 17:11:04 +00:00
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2016-11-05 12:02:19 +01:00
|
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-08-05 17:11:04 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
Port to npth.
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/npth.m4: New file.
* agent/Makefile.am, agent/cache.c, agent/call-pinentry.c,
agent/call-scd.c, agent/findkey.c, agent/gpg-agent.c,
agent/trustlist.c, common/Makefile.am, common/estream.c,
common/exechelp-posix.c, common/exechelp-w32.c,
common/exechelp-w32ce.c, common/http.c, common/init.c,
common/sysutils.c, dirmngr/Makefile.am, dirmngr/crlfetch.c,
dirmngr/dirmngr.c, dirmngr/dirmngr_ldap.c, dirmngr/ldap-wrapper-ce.c,
dirmngr/ldap-wrapper.c, dirmngr/ldap.c, g13/Makefile.am,
g13/call-gpg.c, g13/g13.c, g13/runner.c, scd/Makefile.am,
scd/apdu.c, scd/app.c, scd/ccid-driver.c, scd/command.c,
scd/scdaemon.c, tools/Makefile.am: Port to npth.
2012-01-03 22:12:37 +01:00
|
|
|
|
#include <npth.h>
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
|
|
|
|
#include "scdaemon.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
|
#include "../common/exechelp.h"
|
2003-08-05 17:11:04 +00:00
|
|
|
|
#include "iso7816.h"
|
SCD: API cleanup for keypad handling.
* scd/iso7816.h (struct pininfo_s): Rename from iso7816_pininfo_s.
Change meaning of MODE.
(pininfo_t): Rename from iso7816_pininfo_t.
* scd/sc-copykeys.c: Include "iso7816.h".
* scd/scdaemon.c, scd/command.c: Likewise.
* scd/ccid-driver.c: Include "scdaemon.h" and "iso7816.h".
(ccid_transceive_secure): Follow the change of PININFO_T.
* scd/app.c: Include "apdu.h" after "iso7816.h".
* scd/iso7816.c (iso7816_check_keypad, iso7816_verify_kp)
(iso7816_change_reference_data_kp): Follow the change of API.
* scd/apdu.c (struct reader_table_s): Change API of CHECK_KEYPAD,
KEYPAD_VERIFY, KEYPAD_MODIFY to have arg of PININFO_T.
(check_pcsc_keypad, check_ccid_keypad): Likewise.
(apdu_check_keypad, apdu_keypad_verify, apdu_keypad_modify): Likewise.
(pcsc_keypad_verify, pcsc_keypad_modify, ct_send_apdu)
(pcsc_send_apdu_direct, pcsc_send_apdu_wrapped, pcsc_send_apdu)
(send_apdu_ccid, ccid_keypad_operation, my_rapdu_send_apdu, send_apdu)
(send_le): Follow the change of API.
* scd/apdu.h (apdu_check_keypad, apdu_keypad_verify)
(apdu_keypad_modify): Change the API.
* scd/app-dinsig.c, scd/app-nks.c, scd/app-openpgp.c: Follow the
change.
2013-01-09 14:10:08 +09:00
|
|
|
|
#include "apdu.h"
|
2017-03-07 20:21:23 +09:00
|
|
|
|
#include "../common/tlv.h"
|
2020-01-16 19:42:16 +01:00
|
|
|
|
#include "../common/membuf.h"
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2019-08-21 11:55:45 +09:00
|
|
|
|
|
|
|
|
|
/* Forward declaration of internal function. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
select_additional_application_internal (card_t card, apptype_t req_apptype);
|
2020-01-16 19:42:16 +01:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
send_serialno_and_app_status (card_t card, int with_apps, ctrl_t ctrl);
|
2020-05-26 16:10:57 +02:00
|
|
|
|
static gpg_error_t run_reselect (ctrl_t ctrl, card_t c, app_t a, app_t a_prev);
|
2019-08-21 11:55:45 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Lock to protect the list of cards and its associated
|
|
|
|
|
* applications. */
|
|
|
|
|
static npth_mutex_t card_list_lock;
|
|
|
|
|
|
2020-04-02 15:39:26 +09:00
|
|
|
|
/* Notification to threads which keep watching the status change. */
|
|
|
|
|
static npth_cond_t notify_cond;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* A list of card contexts. A card is a collection of applications
|
|
|
|
|
* (described by app_t) on the same physical token. */
|
|
|
|
|
static card_t card_top;
|
2019-03-22 09:44:04 +01:00
|
|
|
|
|
|
|
|
|
|
2019-06-19 14:30:16 +02:00
|
|
|
|
/* The list of application names and their select function. If no
|
|
|
|
|
* specific application is selected the first available application on
|
2019-03-22 09:44:04 +01:00
|
|
|
|
* a card is selected. */
|
|
|
|
|
struct app_priority_list_s
|
|
|
|
|
{
|
2019-06-19 14:30:16 +02:00
|
|
|
|
apptype_t apptype;
|
2019-03-22 09:44:04 +01:00
|
|
|
|
char const *name;
|
|
|
|
|
gpg_error_t (*select_func)(app_t);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct app_priority_list_s app_priority_list[] =
|
2019-06-19 14:30:16 +02:00
|
|
|
|
{{ APPTYPE_OPENPGP , "openpgp", app_select_openpgp },
|
|
|
|
|
{ APPTYPE_PIV , "piv", app_select_piv },
|
|
|
|
|
{ APPTYPE_NKS , "nks", app_select_nks },
|
|
|
|
|
{ APPTYPE_P15 , "p15", app_select_p15 },
|
|
|
|
|
{ APPTYPE_GELDKARTE, "geldkarte", app_select_geldkarte },
|
|
|
|
|
{ APPTYPE_DINSIG , "dinsig", app_select_dinsig },
|
|
|
|
|
{ APPTYPE_SC_HSM , "sc-hsm", app_select_sc_hsm },
|
|
|
|
|
{ APPTYPE_NONE , NULL, NULL }
|
|
|
|
|
/* APPTYPE_UNDEFINED is special and not listed here. */
|
2019-03-22 09:44:04 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-02-09 18:29:31 +00:00
|
|
|
|
|
2019-06-19 14:30:16 +02:00
|
|
|
|
/* Map a cardtype to a string. Never returns NULL. */
|
|
|
|
|
const char *
|
|
|
|
|
strcardtype (cardtype_t t)
|
|
|
|
|
{
|
|
|
|
|
switch (t)
|
|
|
|
|
{
|
2020-08-27 14:32:04 +09:00
|
|
|
|
case CARDTYPE_GENERIC: return "generic";
|
|
|
|
|
case CARDTYPE_GNUK: return "gnuk";
|
|
|
|
|
case CARDTYPE_YUBIKEY: return "yubikey";
|
|
|
|
|
case CARDTYPE_ZEITCONTROL: return "zeitcontrol";
|
2019-06-19 14:30:16 +02:00
|
|
|
|
}
|
|
|
|
|
return "?";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Map an application type to a string. Never returns NULL. */
|
|
|
|
|
const char *
|
|
|
|
|
strapptype (apptype_t t)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=0; app_priority_list[i].apptype; i++)
|
|
|
|
|
if (app_priority_list[i].apptype == t)
|
|
|
|
|
return app_priority_list[i].name;
|
|
|
|
|
return t == APPTYPE_UNDEFINED? "undefined" : t? "?" : "none";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-09-05 12:59:56 +02:00
|
|
|
|
const char *
|
|
|
|
|
xstrapptype (app_t app)
|
|
|
|
|
{
|
|
|
|
|
return app? strapptype (app->apptype) : "[no_app]";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
/* Return the apptype for NAME. */
|
|
|
|
|
static apptype_t
|
|
|
|
|
apptype_from_name (const char *name)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
|
return APPTYPE_NONE;
|
|
|
|
|
|
|
|
|
|
for (i=0; app_priority_list[i].apptype; i++)
|
|
|
|
|
if (!ascii_strcasecmp (app_priority_list[i].name, name))
|
|
|
|
|
return app_priority_list[i].apptype;
|
|
|
|
|
if (!ascii_strcasecmp ("undefined", name))
|
|
|
|
|
return APPTYPE_UNDEFINED;
|
|
|
|
|
return APPTYPE_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
/* Return the apptype for KEYREF. This is the first part of the
|
|
|
|
|
* KEYREF up to the dot. */
|
|
|
|
|
static apptype_t
|
|
|
|
|
apptype_from_keyref (const char *keyref)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
unsigned int n;
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
if (!keyref)
|
|
|
|
|
return APPTYPE_NONE;
|
|
|
|
|
s = strchr (keyref, '.');
|
|
|
|
|
if (!s || s == keyref || !s[1])
|
|
|
|
|
return APPTYPE_NONE; /* Not a valid keyref. */
|
|
|
|
|
n = s - keyref;
|
|
|
|
|
|
|
|
|
|
for (i=0; app_priority_list[i].apptype; i++)
|
|
|
|
|
if (strlen (app_priority_list[i].name) == n
|
|
|
|
|
&& !ascii_strncasecmp (app_priority_list[i].name, keyref, n))
|
|
|
|
|
return app_priority_list[i].apptype;
|
|
|
|
|
|
|
|
|
|
return APPTYPE_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-11-26 08:46:20 +01:00
|
|
|
|
/* Return true if both serilanumbers are the same. This function
|
|
|
|
|
* takes care of some peculiarities. */
|
|
|
|
|
static int
|
|
|
|
|
is_same_serialno (const unsigned char *sna, size_t snalen,
|
|
|
|
|
const unsigned char *snb, size_t snblen)
|
|
|
|
|
{
|
|
|
|
|
if ((!sna && !snb) || (!snalen && !snblen))
|
|
|
|
|
return 1;
|
|
|
|
|
if (!sna || !snb)
|
|
|
|
|
return 0; /* One of them is NULL. (Both NULL tested above). */
|
|
|
|
|
|
|
|
|
|
if (snalen != snblen)
|
|
|
|
|
return 0; /* (No special cases for this below). */
|
|
|
|
|
|
|
|
|
|
/* The special case for OpenPGP cards where we ignore the version
|
|
|
|
|
* bytes (vvvv). Example: D276000124010304000500009D8A0000
|
|
|
|
|
* ^^^^^^^^^^^^vvvvmmmmssssssssrrrr */
|
|
|
|
|
if (snalen == 16 && !memcmp (sna, "\xD2\x76\x00\x01\x24\x01", 6))
|
|
|
|
|
{
|
|
|
|
|
if (memcmp (snb, "\xD2\x76\x00\x01\x24\x01", 6))
|
|
|
|
|
return 0; /* No */
|
|
|
|
|
return !memcmp (sna + 8, snb + 8, 8);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return !memcmp (sna, snb, snalen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-03-28 17:05:20 +01:00
|
|
|
|
/* Initialization function to change the default app_priority_list.
|
|
|
|
|
* LIST is a list of comma or space separated strings with application
|
|
|
|
|
* names. Unknown names will only result in warning message.
|
|
|
|
|
* Application not mentioned in LIST are used in their original order
|
|
|
|
|
* after the given once. */
|
|
|
|
|
void
|
|
|
|
|
app_update_priority_list (const char *arg)
|
|
|
|
|
{
|
|
|
|
|
struct app_priority_list_s save;
|
|
|
|
|
char **names;
|
|
|
|
|
int i, j, idx;
|
|
|
|
|
|
|
|
|
|
names = strtokenize (arg, ", ");
|
|
|
|
|
if (!names)
|
|
|
|
|
log_fatal ("strtokenize failed: %s\n",
|
|
|
|
|
gpg_strerror (gpg_error_from_syserror ()));
|
|
|
|
|
|
|
|
|
|
idx = 0;
|
|
|
|
|
for (i=0; names[i]; i++)
|
|
|
|
|
{
|
|
|
|
|
ascii_strlwr (names[i]);
|
|
|
|
|
for (j=0; j < i; j++)
|
|
|
|
|
if (!strcmp (names[j], names[i]))
|
|
|
|
|
break;
|
|
|
|
|
if (j < i)
|
|
|
|
|
{
|
|
|
|
|
log_info ("warning: duplicate application '%s' in priority list\n",
|
|
|
|
|
names[i]);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (j=idx; app_priority_list[j].name; j++)
|
|
|
|
|
if (!strcmp (names[i], app_priority_list[j].name))
|
|
|
|
|
break;
|
|
|
|
|
if (!app_priority_list[j].name)
|
|
|
|
|
{
|
|
|
|
|
log_info ("warning: unknown application '%s' in priority list\n",
|
|
|
|
|
names[i]);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
save = app_priority_list[idx];
|
|
|
|
|
app_priority_list[idx] = app_priority_list[j];
|
|
|
|
|
app_priority_list[j] = save;
|
|
|
|
|
idx++;
|
|
|
|
|
}
|
|
|
|
|
log_assert (idx < DIM (app_priority_list));
|
|
|
|
|
|
|
|
|
|
xfree (names);
|
|
|
|
|
for (i=0; app_priority_list[i].name; i++)
|
|
|
|
|
log_info ("app priority %d: %s\n", i, app_priority_list[i].name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-07-13 09:59:22 +00:00
|
|
|
|
static void
|
|
|
|
|
print_progress_line (void *opaque, const char *what, int pc, int cur, int tot)
|
|
|
|
|
{
|
|
|
|
|
ctrl_t ctrl = opaque;
|
|
|
|
|
char line[100];
|
|
|
|
|
|
|
|
|
|
if (ctrl)
|
|
|
|
|
{
|
|
|
|
|
snprintf (line, sizeof line, "%s %c %d %d", what, pc, cur, tot);
|
|
|
|
|
send_status_direct (ctrl, "PROGRESS", line);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Lock the CARD. This function shall be used right before calling
|
|
|
|
|
* any of the actual application functions to serialize access to the
|
|
|
|
|
* reader. We do this always even if the card is not actually used.
|
|
|
|
|
* This allows an actual connection to assume that it never shares a
|
|
|
|
|
* card (while performing one command). Returns 0 on success; only
|
|
|
|
|
* then the unlock_reader function must be called after returning from
|
|
|
|
|
* the handler. Right now we assume a that a reader has just one
|
|
|
|
|
* card; this may eventually need refinement. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
static gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
lock_card (card_t card, ctrl_t ctrl)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (npth_mutex_lock (&card->lock))
|
2005-05-18 10:48:06 +00:00
|
|
|
|
{
|
2016-12-29 10:07:43 +09:00
|
|
|
|
gpg_error_t err = gpg_error_from_syserror ();
|
2019-06-19 08:50:40 +02:00
|
|
|
|
log_error ("failed to acquire CARD lock for %p: %s\n",
|
|
|
|
|
card, gpg_strerror (err));
|
2016-12-29 10:07:43 +09:00
|
|
|
|
return err;
|
2005-05-18 10:48:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
apdu_set_progress_cb (card->slot, print_progress_line, ctrl);
|
|
|
|
|
apdu_set_prompt_cb (card->slot, popup_prompt, ctrl);
|
2009-07-13 09:59:22 +00:00
|
|
|
|
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
|
|
|
|
/* Release a lock on a card. See lock_reader(). */
|
2005-05-18 10:48:06 +00:00
|
|
|
|
static void
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card_t card)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
apdu_set_progress_cb (card->slot, NULL, NULL);
|
|
|
|
|
apdu_set_prompt_cb (card->slot, NULL, NULL);
|
2009-07-13 09:59:22 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (npth_mutex_unlock (&card->lock))
|
2016-12-29 10:07:43 +09:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = gpg_error_from_syserror ();
|
2019-06-19 08:50:40 +02:00
|
|
|
|
log_error ("failed to release CARD lock for %p: %s\n",
|
|
|
|
|
card, gpg_strerror (err));
|
2016-12-29 10:07:43 +09:00
|
|
|
|
}
|
2005-06-03 13:57:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function may be called to print information pertaining to the
|
2019-06-19 08:50:40 +02:00
|
|
|
|
* current state of this module to the log. */
|
2005-06-03 13:57:24 +00:00
|
|
|
|
void
|
|
|
|
|
app_dump_state (void)
|
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_t c;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
app_t a;
|
2005-06-03 13:57:24 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_lock (&card_list_lock);
|
|
|
|
|
for (c = card_top; c; c = c->next)
|
|
|
|
|
{
|
2020-11-26 12:16:56 +01:00
|
|
|
|
log_info ("app_dump_state: card=%p slot=%d type=%s refcount=%u\n",
|
|
|
|
|
c, c->slot, strcardtype (c->cardtype), c->ref_count);
|
2019-09-05 14:05:05 +02:00
|
|
|
|
/* FIXME The use of log_info risks a race! */
|
2019-06-19 08:50:40 +02:00
|
|
|
|
for (a=c->app; a; a = a->next)
|
2019-06-19 14:30:16 +02:00
|
|
|
|
log_info ("app_dump_state: app=%p type='%s'\n",
|
|
|
|
|
a, strapptype (a->apptype));
|
2019-06-19 08:50:40 +02:00
|
|
|
|
}
|
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
2005-06-03 13:57:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2020-04-02 15:39:26 +09:00
|
|
|
|
gpg_error_t
|
|
|
|
|
app_send_devinfo (ctrl_t ctrl)
|
|
|
|
|
{
|
|
|
|
|
card_t c;
|
|
|
|
|
app_t a;
|
|
|
|
|
int no_device;
|
|
|
|
|
|
|
|
|
|
send_status_direct (ctrl, "DEVINFO_START", "");
|
|
|
|
|
|
|
|
|
|
npth_mutex_lock (&card_list_lock);
|
|
|
|
|
no_device = (card_top == NULL);
|
|
|
|
|
for (c = card_top; c; c = c->next)
|
|
|
|
|
{
|
|
|
|
|
char *serialno;
|
|
|
|
|
char card_info[80];
|
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
serialno = card_get_serialno (c);
|
2020-04-02 15:39:26 +09:00
|
|
|
|
snprintf (card_info, sizeof card_info, "DEVICE %s %s",
|
|
|
|
|
strcardtype (c->cardtype), serialno);
|
|
|
|
|
xfree (serialno);
|
|
|
|
|
|
|
|
|
|
for (a = c->app; a; a = a->next)
|
|
|
|
|
send_status_direct (ctrl, card_info, strapptype (a->apptype));
|
|
|
|
|
}
|
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
|
|
|
|
|
|
|
|
|
send_status_direct (ctrl, "DEVINFO_END", "");
|
|
|
|
|
|
|
|
|
|
return no_device ? gpg_error (GPG_ERR_NOT_FOUND): 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-28 10:06:33 +09:00
|
|
|
|
/* Check whether the application NAME is allowed. This does not mean
|
2004-08-05 09:24:36 +00:00
|
|
|
|
we have support for it though. */
|
|
|
|
|
static int
|
|
|
|
|
is_app_allowed (const char *name)
|
|
|
|
|
{
|
|
|
|
|
strlist_t l;
|
|
|
|
|
|
|
|
|
|
for (l=opt.disabled_applications; l; l = l->next)
|
|
|
|
|
if (!strcmp (l->d, name))
|
|
|
|
|
return 0; /* no */
|
|
|
|
|
return 1; /* yes */
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-09 07:28:47 +00:00
|
|
|
|
|
2019-06-21 11:41:58 +02:00
|
|
|
|
/* This function is mainly used by the serialno command to check for
|
|
|
|
|
* an application conflict which may appear if the serialno command is
|
|
|
|
|
* used to request a specific application and the connection has
|
|
|
|
|
* already done a select_application. Return values are:
|
|
|
|
|
* 0 - No conflict
|
|
|
|
|
* GPG_ERR_FALSE - Another application is in use but it is possible
|
|
|
|
|
* to switch to the requested application.
|
2019-06-25 09:48:18 +02:00
|
|
|
|
* Other code - Switching is not possible.
|
|
|
|
|
*
|
2020-01-13 12:08:23 +01:00
|
|
|
|
* If SERIALNO_BIN is not NULL a conflict is only asserted if the
|
2019-06-25 09:48:18 +02:00
|
|
|
|
* serialno of the card matches.
|
2019-06-21 11:41:58 +02:00
|
|
|
|
*/
|
|
|
|
|
gpg_error_t
|
2019-06-25 09:48:18 +02:00
|
|
|
|
check_application_conflict (card_t card, const char *name,
|
|
|
|
|
const unsigned char *serialno_bin,
|
|
|
|
|
size_t serialno_bin_len)
|
2015-12-04 14:13:23 +09:00
|
|
|
|
{
|
2019-08-21 12:42:32 +09:00
|
|
|
|
apptype_t apptype;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !name)
|
|
|
|
|
return 0;
|
|
|
|
|
if (!card->app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */
|
|
|
|
|
|
2019-06-25 09:48:18 +02:00
|
|
|
|
if (serialno_bin && card->serialno)
|
|
|
|
|
{
|
2020-11-26 08:46:20 +01:00
|
|
|
|
if (!is_same_serialno (card->serialno, card->serialnolen,
|
|
|
|
|
serialno_bin, serialno_bin_len))
|
2019-06-25 09:48:18 +02:00
|
|
|
|
return 0; /* The card does not match the requested S/N. */
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-21 12:42:32 +09:00
|
|
|
|
apptype = apptype_from_name (name);
|
|
|
|
|
if (card->app->apptype == apptype)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2019-06-19 14:30:16 +02:00
|
|
|
|
if (card->app->apptype == APPTYPE_UNDEFINED)
|
2019-02-21 08:40:59 +01:00
|
|
|
|
return 0;
|
|
|
|
|
|
2019-06-21 11:41:58 +02:00
|
|
|
|
if (card->cardtype == CARDTYPE_YUBIKEY)
|
|
|
|
|
{
|
|
|
|
|
if (card->app->apptype == APPTYPE_OPENPGP)
|
|
|
|
|
{
|
|
|
|
|
/* Current app is OpenPGP. */
|
|
|
|
|
if (!ascii_strcasecmp (name, "piv"))
|
|
|
|
|
return gpg_error (GPG_ERR_FALSE); /* Switching allowed. */
|
|
|
|
|
}
|
|
|
|
|
else if (card->app->apptype == APPTYPE_PIV)
|
|
|
|
|
{
|
|
|
|
|
/* Current app is PIV. */
|
|
|
|
|
if (!ascii_strcasecmp (name, "openpgp"))
|
|
|
|
|
return gpg_error (GPG_ERR_FALSE); /* Switching allowed. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
log_info ("application '%s' in use - can't switch\n",
|
2019-06-19 14:30:16 +02:00
|
|
|
|
strapptype (card->app->apptype));
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
|
|
|
|
return gpg_error (GPG_ERR_CONFLICT);
|
2006-02-09 18:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2005-02-24 17:36:11 +00:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_reset (card_t card, ctrl_t ctrl, int send_reset)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2017-02-16 11:49:37 +09:00
|
|
|
|
gpg_error_t err = 0;
|
2008-10-20 13:53:23 +00:00
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
if (send_reset)
|
2006-02-09 18:29:31 +00:00
|
|
|
|
{
|
2017-02-17 11:50:40 +09:00
|
|
|
|
int sw;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
lock_card (card, ctrl);
|
|
|
|
|
sw = apdu_reset (card->slot);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
if (sw)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
2015-12-04 14:13:23 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->reset_requested = 1;
|
|
|
|
|
unlock_card (card);
|
2017-02-17 11:50:40 +09:00
|
|
|
|
|
2017-02-15 18:23:01 +09:00
|
|
|
|
scd_kick_the_loop ();
|
|
|
|
|
gnupg_sleep (1);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
|
|
|
|
else
|
2005-06-03 13:57:24 +00:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
ctrl->card_ctx = NULL;
|
2019-08-21 09:57:52 +09:00
|
|
|
|
ctrl->current_apptype = APPTYPE_NONE;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_unref (card);
|
2005-06-03 13:57:24 +00:00
|
|
|
|
}
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gpg_error_t
|
2017-01-27 18:01:52 +09:00
|
|
|
|
app_new_register (int slot, ctrl_t ctrl, const char *name,
|
2017-01-28 00:18:11 +09:00
|
|
|
|
int periodical_check_needed)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = 0;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_t card = NULL;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
app_t app = NULL;
|
|
|
|
|
unsigned char *result = NULL;
|
|
|
|
|
size_t resultlen;
|
|
|
|
|
int want_undefined;
|
2019-03-22 09:44:04 +01:00
|
|
|
|
int i;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Need to allocate a new card object */
|
|
|
|
|
card = xtrycalloc (1, sizeof *card);
|
|
|
|
|
if (!card)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2006-09-14 16:50:33 +00:00
|
|
|
|
err = gpg_error_from_syserror ();
|
2005-05-18 10:48:06 +00:00
|
|
|
|
log_info ("error allocating context: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->slot = slot;
|
|
|
|
|
card->card_status = (unsigned int)-1;
|
2016-12-29 10:07:43 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (npth_mutex_init (&card->lock, NULL))
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
2016-12-29 10:07:43 +09:00
|
|
|
|
log_error ("error initializing mutex: %s\n", gpg_strerror (err));
|
2019-06-19 08:50:40 +02:00
|
|
|
|
xfree (card);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
return err;
|
|
|
|
|
}
|
2004-01-27 16:40:42 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
xfree (card);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
return err;
|
|
|
|
|
}
|
2005-05-18 10:48:06 +00:00
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
want_undefined = (name && !strcmp (name, "undefined"));
|
2004-01-27 16:40:42 +00:00
|
|
|
|
|
2011-12-14 18:56:10 +01:00
|
|
|
|
/* Try to read the GDO file first to get a default serial number.
|
|
|
|
|
We skip this if the undefined application has been requested. */
|
|
|
|
|
if (!want_undefined)
|
2004-01-27 16:40:42 +00:00
|
|
|
|
{
|
2017-03-06 13:39:46 +09:00
|
|
|
|
err = iso7816_select_file (slot, 0x3F00, 1);
|
2019-01-20 11:45:57 +01:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_CARD)
|
|
|
|
|
{
|
|
|
|
|
/* Might be SW==0x7D00. Let's test whether it is a Yubikey
|
|
|
|
|
* by selecting its manager application and then reading the
|
|
|
|
|
* config. */
|
|
|
|
|
static char const yk_aid[] =
|
|
|
|
|
{ 0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 }; /*MGR*/
|
2019-03-27 17:34:50 +01:00
|
|
|
|
static char const otp_aid[] =
|
|
|
|
|
{ 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 }; /*OTP*/
|
2019-01-20 11:45:57 +01:00
|
|
|
|
unsigned char *buf;
|
|
|
|
|
size_t buflen;
|
2019-03-27 17:34:50 +01:00
|
|
|
|
const unsigned char *s0;
|
|
|
|
|
unsigned char formfactor;
|
2019-01-20 11:45:57 +01:00
|
|
|
|
size_t n;
|
|
|
|
|
|
|
|
|
|
if (!iso7816_select_application (slot, yk_aid, sizeof yk_aid,
|
|
|
|
|
0x0001)
|
|
|
|
|
&& !iso7816_apdu_direct (slot, "\x00\x1d\x00\x00\x00", 5, 0,
|
|
|
|
|
NULL, &buf, &buflen))
|
|
|
|
|
{
|
2019-06-19 14:30:16 +02:00
|
|
|
|
card->cardtype = CARDTYPE_YUBIKEY;
|
2019-01-20 11:45:57 +01:00
|
|
|
|
if (opt.verbose)
|
|
|
|
|
{
|
|
|
|
|
log_info ("Yubico: config=");
|
|
|
|
|
log_printhex (buf, buflen, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We skip the first byte which seems to be the total
|
|
|
|
|
* length of the config data. */
|
|
|
|
|
if (buflen > 1)
|
|
|
|
|
{
|
|
|
|
|
s0 = find_tlv (buf+1, buflen-1, 0x04, &n); /* Form factor */
|
2019-03-27 17:34:50 +01:00
|
|
|
|
formfactor = (s0 && n == 1)? *s0 : 0;
|
|
|
|
|
|
|
|
|
|
s0 = find_tlv (buf+1, buflen-1, 0x02, &n); /* Serial */
|
|
|
|
|
if (s0 && n >= 4)
|
2019-01-20 11:45:57 +01:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->serialno = xtrymalloc (3 + 1 + n);
|
|
|
|
|
if (card->serialno)
|
2019-01-20 11:45:57 +01:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->serialnolen = 3 + 1 + n;
|
|
|
|
|
card->serialno[0] = 0xff;
|
|
|
|
|
card->serialno[1] = 0x02;
|
|
|
|
|
card->serialno[2] = 0x0;
|
|
|
|
|
card->serialno[3] = formfactor;
|
|
|
|
|
memcpy (card->serialno + 4, s0, n);
|
2020-11-24 18:02:05 +01:00
|
|
|
|
err = app_munge_serialno (card);
|
2019-01-20 11:45:57 +01:00
|
|
|
|
}
|
2019-03-27 17:34:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s0 = find_tlv (buf+1, buflen-1, 0x05, &n); /* version */
|
|
|
|
|
if (s0 && n == 3)
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->cardversion = ((s0[0]<<16)|(s0[1]<<8)|s0[2]);
|
2019-03-27 17:34:50 +01:00
|
|
|
|
else if (!s0)
|
|
|
|
|
{
|
|
|
|
|
/* No version - this is not a Yubikey 5. We now
|
|
|
|
|
* switch to the OTP app and take the first
|
Spelling cleanup.
No functional changes, just fixing minor spelling issues.
---
Most of these were identified from the command line by running:
codespell \
--ignore-words-list fpr,stati,keyserver,keyservers,asign,cas,iff,ifset \
--skip '*.po,ChangeLog*,help.*.txt,*.jpg,*.eps,*.pdf,*.png,*.gpg,*.asc' \
doc g13 g10 kbx agent artwork scd tests tools am common dirmngr sm \
NEWS README README.maint TODO
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2020-02-18 09:34:42 -05:00
|
|
|
|
* three bytes of the response as version
|
2019-03-27 17:34:50 +01:00
|
|
|
|
* number. */
|
|
|
|
|
xfree (buf);
|
|
|
|
|
buf = NULL;
|
|
|
|
|
if (!iso7816_select_application_ext (slot,
|
|
|
|
|
otp_aid, sizeof otp_aid,
|
|
|
|
|
1, &buf, &buflen)
|
|
|
|
|
&& buflen > 3)
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->cardversion = ((buf[0]<<16)|(buf[1]<<8)|buf[2]);
|
2019-01-20 11:45:57 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
xfree (buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-27 14:32:04 +09:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned char *atr;
|
|
|
|
|
size_t atrlen;
|
|
|
|
|
|
|
|
|
|
/* This is heuristics to identify different implementations. */
|
2020-08-27 11:53:06 +02:00
|
|
|
|
atr = apdu_get_atr (slot, &atrlen);
|
2020-08-27 14:32:04 +09:00
|
|
|
|
if (atr)
|
|
|
|
|
{
|
|
|
|
|
if (atrlen == 21 && atr[2] == 0x11)
|
|
|
|
|
card->cardtype = CARDTYPE_GNUK;
|
|
|
|
|
else if (atrlen == 21 && atr[7] == 0x75)
|
|
|
|
|
card->cardtype = CARDTYPE_ZEITCONTROL;
|
|
|
|
|
xfree (atr);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-20 11:45:57 +01:00
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
if (!err && card->cardtype != CARDTYPE_YUBIKEY)
|
2017-03-06 13:39:46 +09:00
|
|
|
|
err = iso7816_select_file (slot, 0x2F02, 0);
|
2020-11-24 18:02:05 +01:00
|
|
|
|
if (!err && card->cardtype != CARDTYPE_YUBIKEY)
|
2011-12-14 18:56:10 +01:00
|
|
|
|
err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
|
2020-11-24 18:02:05 +01:00
|
|
|
|
if (!err && card->cardtype != CARDTYPE_YUBIKEY)
|
2004-01-27 16:40:42 +00:00
|
|
|
|
{
|
2011-12-14 18:56:10 +01:00
|
|
|
|
size_t n;
|
|
|
|
|
const unsigned char *p;
|
|
|
|
|
|
|
|
|
|
p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
|
|
|
|
|
if (p)
|
|
|
|
|
resultlen -= (p-result);
|
|
|
|
|
if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
|
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* The object does not fit into the buffer. This is an
|
2011-12-14 18:56:10 +01:00
|
|
|
|
invalid encoding (or the buffer is too short. However, I
|
|
|
|
|
have some test cards with such an invalid encoding and
|
|
|
|
|
therefore I use this ugly workaround to return something
|
|
|
|
|
I can further experiment with. */
|
|
|
|
|
log_info ("enabling BMI testcard workaround\n");
|
|
|
|
|
n--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (p && n <= resultlen)
|
|
|
|
|
{
|
|
|
|
|
/* The GDO file is pretty short, thus we simply reuse it for
|
|
|
|
|
storing the serial number. */
|
|
|
|
|
memmove (result, p, n);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->serialno = result;
|
|
|
|
|
card->serialnolen = n;
|
|
|
|
|
err = app_munge_serialno (card);
|
2011-12-14 18:56:10 +01:00
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
xfree (result);
|
|
|
|
|
result = NULL;
|
2004-01-27 16:40:42 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Allocate a new app object. */
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
card->app = app;
|
|
|
|
|
app->card = card;
|
|
|
|
|
|
2005-02-24 17:36:11 +00:00
|
|
|
|
/* Figure out the application to use. */
|
2011-12-14 18:56:10 +01:00
|
|
|
|
if (want_undefined)
|
|
|
|
|
{
|
|
|
|
|
/* We switch to the "undefined" application only if explicitly
|
|
|
|
|
requested. */
|
2019-06-19 14:30:16 +02:00
|
|
|
|
app->apptype = APPTYPE_UNDEFINED;
|
2019-01-25 19:12:32 +01:00
|
|
|
|
/* Clear the error so that we don't run through the application
|
|
|
|
|
* selection chain. */
|
2011-12-14 18:56:10 +01:00
|
|
|
|
err = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-01-25 19:12:32 +01:00
|
|
|
|
{
|
|
|
|
|
/* For certain error codes, there is no need to try more. */
|
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT
|
|
|
|
|
|| gpg_err_code (err) == GPG_ERR_ENODEV)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
/* Set a default error so that we run through the application
|
2019-03-22 09:44:04 +01:00
|
|
|
|
* selection chain. */
|
2019-01-25 19:12:32 +01:00
|
|
|
|
err = gpg_error (GPG_ERR_NOT_FOUND);
|
|
|
|
|
}
|
2005-05-18 10:48:06 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Find the first available app if NAME is NULL or the matching
|
2019-03-22 09:44:04 +01:00
|
|
|
|
* NAME but only if that application is also enabled. */
|
|
|
|
|
for (i=0; err && app_priority_list[i].name; i++)
|
|
|
|
|
{
|
|
|
|
|
if (is_app_allowed (app_priority_list[i].name)
|
|
|
|
|
&& (!name || !strcmp (name, app_priority_list[i].name)))
|
|
|
|
|
err = app_priority_list[i].select_func (app);
|
|
|
|
|
}
|
2014-12-15 17:38:40 +01:00
|
|
|
|
if (err && name && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
2004-01-27 16:40:42 +00:00
|
|
|
|
|
2004-09-09 07:28:47 +00:00
|
|
|
|
leave:
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2004-01-27 16:40:42 +00:00
|
|
|
|
if (name)
|
2012-06-05 19:29:22 +02:00
|
|
|
|
log_info ("can't select application '%s': %s\n",
|
2005-05-18 10:48:06 +00:00
|
|
|
|
name, gpg_strerror (err));
|
2004-01-27 16:40:42 +00:00
|
|
|
|
else
|
|
|
|
|
log_info ("no supported card application found: %s\n",
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_strerror (err));
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
xfree (app);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
xfree (card);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->periodical_check_needed = periodical_check_needed;
|
|
|
|
|
card->next = card_top;
|
|
|
|
|
card_top = card;
|
2019-06-21 10:47:45 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-02-24 17:36:11 +00:00
|
|
|
|
return 0;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
/* If called with NAME as NULL, select the best fitting application
|
2019-06-19 08:50:40 +02:00
|
|
|
|
* and return its card context; otherwise select the application with
|
|
|
|
|
* NAME and return its card context. Returns an error code and stores
|
|
|
|
|
* NULL at R_CARD if no application was found or no card is present. */
|
2016-12-28 12:29:17 +09:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
select_application (ctrl_t ctrl, const char *name, card_t *r_card,
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
int scan, const unsigned char *serialno_bin,
|
|
|
|
|
size_t serialno_bin_len)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
gpg_error_t err = 0;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_t card, card_prev = NULL;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
*r_card = NULL;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_lock (&card_list_lock);
|
2018-11-28 14:59:44 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (scan || !card_top)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
struct dev_list *l;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
int new_card = 0;
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
|
2017-01-31 12:56:11 +09:00
|
|
|
|
/* Scan the devices to find new device(s). */
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
err = apdu_dev_list_start (opt.reader_port, &l);
|
|
|
|
|
if (err)
|
2018-11-28 14:59:44 +09:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
2018-11-28 14:59:44 +09:00
|
|
|
|
return err;
|
|
|
|
|
}
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
|
|
|
|
|
while (1)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
int slot;
|
2017-01-31 12:56:11 +09:00
|
|
|
|
int periodical_check_needed_this;
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
|
2019-09-12 08:48:48 +09:00
|
|
|
|
slot = apdu_open_reader (l);
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
if (slot < 0)
|
|
|
|
|
break;
|
|
|
|
|
|
2017-01-31 12:56:11 +09:00
|
|
|
|
periodical_check_needed_this = apdu_connect (slot);
|
|
|
|
|
if (periodical_check_needed_this < 0)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2017-01-27 18:01:52 +09:00
|
|
|
|
/* We close a reader with no card. */
|
|
|
|
|
err = gpg_error (GPG_ERR_ENODEV);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
else
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
{
|
2017-01-28 00:18:11 +09:00
|
|
|
|
err = app_new_register (slot, ctrl, name,
|
2017-01-31 12:56:11 +09:00
|
|
|
|
periodical_check_needed_this);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
new_card++;
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
}
|
2017-01-27 18:01:52 +09:00
|
|
|
|
|
|
|
|
|
if (err)
|
2020-01-07 18:45:33 +01:00
|
|
|
|
{
|
2020-01-13 17:53:49 +01:00
|
|
|
|
pincache_put (ctrl, slot, NULL, NULL, NULL, 0);
|
2020-01-07 18:45:33 +01:00
|
|
|
|
apdu_close_reader (slot);
|
|
|
|
|
}
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-27 18:01:52 +09:00
|
|
|
|
apdu_dev_list_finish (l);
|
2017-01-31 12:56:11 +09:00
|
|
|
|
|
2017-11-21 11:52:54 +09:00
|
|
|
|
/* If new device(s), kick the scdaemon loop. */
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (new_card)
|
2017-01-31 12:56:11 +09:00
|
|
|
|
scd_kick_the_loop ();
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
for (card = card_top; card; card = card->next)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
lock_card (card, ctrl);
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
if (serialno_bin == NULL)
|
|
|
|
|
break;
|
2020-11-26 08:46:20 +01:00
|
|
|
|
if (is_same_serialno (card->serialno, card->serialnolen,
|
|
|
|
|
serialno_bin, serialno_bin_len))
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
break;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
|
|
|
|
card_prev = card;
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (card)
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
{
|
2019-06-25 09:48:18 +02:00
|
|
|
|
err = check_application_conflict (card, name, NULL, 0);
|
2019-08-21 11:55:45 +09:00
|
|
|
|
if (!err)
|
|
|
|
|
ctrl->current_apptype = card->app ? card->app->apptype : APPTYPE_NONE;
|
|
|
|
|
else if (gpg_err_code (err) == GPG_ERR_FALSE)
|
|
|
|
|
{
|
|
|
|
|
apptype_t req_apptype = apptype_from_name (name);
|
|
|
|
|
|
|
|
|
|
if (!req_apptype)
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_FOUND);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
err = select_additional_application_internal (card, req_apptype);
|
|
|
|
|
if (!err)
|
|
|
|
|
ctrl->current_apptype = req_apptype;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
if (!err)
|
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Note: We do not use card_ref as we are already locked. */
|
|
|
|
|
card->ref_count++;
|
|
|
|
|
*r_card = card;
|
|
|
|
|
if (card_prev)
|
2017-03-27 13:56:02 +09:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_prev->next = card->next;
|
|
|
|
|
card->next = card_top;
|
|
|
|
|
card_top = card;
|
2017-03-27 13:56:02 +09:00
|
|
|
|
}
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
}
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
2016-12-30 15:17:50 +09:00
|
|
|
|
else
|
|
|
|
|
err = gpg_error (GPG_ERR_ENODEV);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
scd: Add --demand option for SERIALNO.
* scd/app.c (select_application): Add SERIALNO_BIN and SERIALNO_BIN_LEN
arguments. Return matched APP with a serial number when specified.
* scd/command.c (open_card): Modify for the implicit open only.
(open_card_with_request): New for explicit open and support match with a
serial number.
(cmd_serialno): Support --demand option.
(cmd_learn, cmd_readcert, cmd_readkey, cmd_pksign, cmd_pkauth)
(cmd_pkdecrypt, cmd_getattr, cmd_setattr, cmd_writecert, cmd_writekey)
(cmd_genkey, cmd_random, cmd_passwd, cmd_checkpin, cmd_apdu): Follow
the change of open_card.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-16 10:26:16 +09:00
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2020-01-16 19:42:16 +01:00
|
|
|
|
/* 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)
|
|
|
|
|
{
|
2020-11-26 08:46:20 +01:00
|
|
|
|
if (is_same_serialno (card->serialno, card->serialnolen,
|
|
|
|
|
serialno, serialnolen))
|
2020-01-16 19:42:16 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-08-21 11:55:45 +09:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
select_additional_application_internal (card_t card, apptype_t req_apptype)
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = 0;
|
2019-08-21 11:55:45 +09:00
|
|
|
|
app_t app;
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* Check that the requested app has not yet been put onto the list. */
|
|
|
|
|
for (app = card->app; app; app = app->next)
|
|
|
|
|
if (app->apptype == req_apptype)
|
|
|
|
|
{
|
|
|
|
|
/* We already got this one. Note that in this case we don't
|
|
|
|
|
* make it the current one but it doesn't matter because
|
|
|
|
|
* maybe_switch_app will do that anyway. */
|
|
|
|
|
err = 0;
|
|
|
|
|
app = NULL;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Allocate a new app object. */
|
|
|
|
|
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;
|
|
|
|
|
}
|
2019-08-21 09:56:44 +09:00
|
|
|
|
app->card = card;
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
|
|
|
|
|
/* Find the app and run the select. */
|
|
|
|
|
for (i=0; app_priority_list[i].apptype; i++)
|
|
|
|
|
{
|
|
|
|
|
if (app_priority_list[i].apptype == req_apptype
|
|
|
|
|
&& is_app_allowed (app_priority_list[i].name))
|
2019-08-21 09:56:44 +09:00
|
|
|
|
{
|
|
|
|
|
err = app_priority_list[i].select_func (app);
|
|
|
|
|
break;
|
|
|
|
|
}
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
}
|
|
|
|
|
if (!app_priority_list[i].apptype
|
|
|
|
|
|| (err && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE))
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
|
|
|
|
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
/* Add this app. We make it the current one to avoid an extra
|
|
|
|
|
* reselect by maybe_switch_app after the select we just did. */
|
|
|
|
|
app->next = card->app;
|
|
|
|
|
card->app = app;
|
2019-09-04 12:27:54 +02:00
|
|
|
|
log_info ("added app '%s' to the card context and switched\n",
|
|
|
|
|
strapptype (app->apptype));
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
|
|
|
|
|
leave:
|
2019-08-21 09:56:44 +09:00
|
|
|
|
if (err)
|
|
|
|
|
xfree (app);
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 13:38:50 +02:00
|
|
|
|
|
|
|
|
|
/* Add all possible additional applications to the card context but do
|
2020-01-03 11:43:55 +01:00
|
|
|
|
* not change the current one. This currently works only for Yubikeys. */
|
2019-09-04 13:38:50 +02:00
|
|
|
|
static gpg_error_t
|
2020-05-26 16:10:57 +02:00
|
|
|
|
select_all_additional_applications_internal (ctrl_t ctrl, card_t card)
|
2019-09-04 13:38:50 +02:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
apptype_t candidates[3];
|
|
|
|
|
int i, j;
|
2020-05-26 16:10:57 +02:00
|
|
|
|
int any_new = 0;
|
2019-09-04 13:38:50 +02:00
|
|
|
|
|
|
|
|
|
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));
|
2020-05-26 16:10:57 +02:00
|
|
|
|
any_new = 1;
|
2019-09-04 13:38:50 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-26 16:10:57 +02:00
|
|
|
|
/* If we found a new application we need to reselect the original
|
|
|
|
|
* application so that we are in a well defined state. */
|
|
|
|
|
if (!err && any_new && card->app && card->app->fnc.reselect)
|
|
|
|
|
err = run_reselect (ctrl, card, card->app, NULL);
|
|
|
|
|
|
2019-09-04 13:38:50 +02:00
|
|
|
|
leave:
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-08-21 11:55:45 +09:00
|
|
|
|
/* 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
|
|
|
|
|
* active application. On error no new application is allocated.
|
|
|
|
|
* Selecting an already selected application has no effect. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
select_additional_application (ctrl_t ctrl, const char *name)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
apptype_t req_apptype;
|
|
|
|
|
card_t card;
|
|
|
|
|
|
2019-09-04 13:38:50 +02:00
|
|
|
|
if (!name)
|
|
|
|
|
req_apptype = 0;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
req_apptype = apptype_from_name (name);
|
|
|
|
|
if (!req_apptype)
|
|
|
|
|
return gpg_error (GPG_ERR_NOT_FOUND);
|
|
|
|
|
}
|
2019-08-21 11:55:45 +09:00
|
|
|
|
|
|
|
|
|
card = ctrl->card_ctx;
|
|
|
|
|
if (!card)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
|
|
|
|
|
|
|
|
|
err = lock_card (card, ctrl);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
|
2019-09-04 13:38:50 +02:00
|
|
|
|
if (req_apptype)
|
|
|
|
|
{
|
|
|
|
|
err = select_additional_application_internal (card, req_apptype);
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
ctrl->current_apptype = req_apptype;
|
2021-02-22 17:51:11 +01:00
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("current_apptype is set to %s\n", name);
|
2019-09-04 13:38:50 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-08-21 11:55:45 +09:00
|
|
|
|
{
|
2020-05-26 16:10:57 +02:00
|
|
|
|
err = select_all_additional_applications_internal (ctrl, card);
|
2019-08-21 11:55:45 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlock_card (card);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
|
2009-02-27 14:36:59 +00:00
|
|
|
|
char *
|
|
|
|
|
get_supported_applications (void)
|
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
size_t nbytes;
|
|
|
|
|
char *buffer, *p;
|
2019-03-28 17:05:20 +01:00
|
|
|
|
const char *s;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2019-03-28 17:05:20 +01:00
|
|
|
|
for (nbytes=1, idx=0; (s=app_priority_list[idx].name); idx++)
|
|
|
|
|
nbytes += strlen (s) + 1 + 1;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2009-02-27 14:36:59 +00:00
|
|
|
|
buffer = xtrymalloc (nbytes);
|
|
|
|
|
if (!buffer)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2019-03-28 17:05:20 +01:00
|
|
|
|
for (p=buffer, idx=0; (s=app_priority_list[idx].name); idx++)
|
|
|
|
|
if (is_app_allowed (s))
|
|
|
|
|
p = stpcpy (stpcpy (p, s), ":\n");
|
2009-02-27 14:36:59 +00:00
|
|
|
|
*p = 0;
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
/* Deallocate the application. */
|
2006-02-09 18:29:31 +00:00
|
|
|
|
static void
|
2019-06-19 08:50:40 +02:00
|
|
|
|
deallocate_card (card_t card)
|
2006-02-09 18:29:31 +00:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_t c, c_prev = NULL;
|
|
|
|
|
app_t a, anext;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
for (c = card_top; c; c = c->next)
|
|
|
|
|
if (c == card)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (c_prev == NULL)
|
|
|
|
|
card_top = c->next;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
else
|
2019-06-19 08:50:40 +02:00
|
|
|
|
c_prev->next = c->next;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
2019-06-19 08:50:40 +02:00
|
|
|
|
c_prev = c;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (card->ref_count)
|
|
|
|
|
log_error ("releasing still used card context (%d)\n", card->ref_count);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
for (a = card->app; a; a = anext)
|
2006-02-09 18:29:31 +00:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (a->fnc.deinit)
|
|
|
|
|
{
|
|
|
|
|
a->fnc.deinit (a);
|
|
|
|
|
a->fnc.deinit = NULL;
|
|
|
|
|
}
|
|
|
|
|
anext = a->next;
|
|
|
|
|
xfree (a);
|
2006-02-09 18:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-21 10:47:45 +02:00
|
|
|
|
xfree (card->serialno);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
|
|
|
|
xfree (card);
|
2006-02-09 18:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-17 16:19:22 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Increment the reference counter of CARD. Returns CARD. */
|
|
|
|
|
card_t
|
|
|
|
|
card_ref (card_t card)
|
2019-06-17 16:19:22 +02:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
lock_card (card, NULL);
|
|
|
|
|
++card->ref_count;
|
|
|
|
|
unlock_card (card);
|
|
|
|
|
return card;
|
2019-06-17 16:19:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* Decrement the reference counter for CARD. Note that we are using
|
|
|
|
|
* reference counting to track the users of the card's application and
|
|
|
|
|
* are deferring the actual deallocation to allow for a later reuse by
|
|
|
|
|
* a new connection. Using NULL for CARD is a no-op. */
|
2004-01-27 16:40:42 +00:00
|
|
|
|
void
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_unref (card_t card)
|
2004-01-27 16:40:42 +00:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card)
|
2004-01-27 16:40:42 +00:00
|
|
|
|
return;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* We don't deallocate CARD here. Instead, we keep it. This is
|
2015-12-04 14:13:23 +09:00
|
|
|
|
useful so that a card does not get reset even if only one session
|
|
|
|
|
is using the card - this way the PIN cache and other cached data
|
|
|
|
|
are preserved. */
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
lock_card (card, NULL);
|
|
|
|
|
card_unref_locked (card);
|
|
|
|
|
unlock_card (card);
|
2019-06-17 16:19:22 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
/* This is the same as card_unref but assumes that CARD is already
|
2019-06-17 16:19:22 +02:00
|
|
|
|
* locked. */
|
|
|
|
|
void
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_unref_locked (card_t card)
|
2019-06-17 16:19:22 +02:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card)
|
2019-06-17 16:19:22 +02:00
|
|
|
|
return;
|
2017-02-17 11:50:40 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card->ref_count)
|
|
|
|
|
log_bug ("tried to release an already released card context\n");
|
2017-02-15 18:23:01 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
--card->ref_count;
|
2004-01-27 16:40:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2004-09-09 07:28:47 +00:00
|
|
|
|
/* The serial number may need some cosmetics. Do it here. This
|
|
|
|
|
function shall only be called once after a new serial number has
|
2011-02-04 12:57:53 +01:00
|
|
|
|
been put into APP->serialno.
|
2004-09-09 07:28:47 +00:00
|
|
|
|
|
|
|
|
|
Prefixes we use:
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2004-09-09 07:28:47 +00:00
|
|
|
|
FF 00 00 = For serial numbers starting with an FF
|
|
|
|
|
FF 01 00 = Some german p15 cards return an empty serial number so the
|
2005-04-27 12:09:21 +00:00
|
|
|
|
serial number from the EF(TokenInfo) is used instead.
|
2020-11-24 18:02:05 +01:00
|
|
|
|
FF 02 00 = Serial number from Yubikey config.
|
|
|
|
|
This is normally not seen because we modify this here
|
|
|
|
|
to an OpenPGP Card s/n.
|
2009-01-27 11:30:02 +00:00
|
|
|
|
FF 7F 00 = No serialno.
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-01-13 12:08:23 +01:00
|
|
|
|
All other serial numbers not starting with FF are used as they are.
|
2004-09-09 07:28:47 +00:00
|
|
|
|
*/
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_munge_serialno (card_t card)
|
2004-09-09 07:28:47 +00:00
|
|
|
|
{
|
2020-11-24 18:02:05 +01:00
|
|
|
|
if (card->cardtype == CARDTYPE_YUBIKEY
|
|
|
|
|
&& card->serialnolen == 3 + 1 + 4
|
|
|
|
|
&& !memcmp (card->serialno, "\xff\x02\x00", 3))
|
|
|
|
|
{
|
|
|
|
|
/* An example for a serial number is
|
|
|
|
|
* FF020001008A77C1
|
|
|
|
|
* ~~~~~~--~~~~~~~~
|
|
|
|
|
* ! ! !--------- 4 byte s/n
|
|
|
|
|
* ! !----------- Form factor
|
|
|
|
|
* !----------------- Our prefix
|
|
|
|
|
* Yubico seems to use the decimalized version of their S/N
|
|
|
|
|
* as the OpenPGP card S/N. Thus in theory we can contruct the
|
|
|
|
|
* number from this information so that we do not rely on having
|
|
|
|
|
* the OpenPGP app enabled.
|
|
|
|
|
*/
|
|
|
|
|
unsigned long sn;
|
|
|
|
|
sn = card->serialno[4] * 16777216;
|
|
|
|
|
sn += card->serialno[5] * 65536;
|
|
|
|
|
sn += card->serialno[6] * 256;
|
|
|
|
|
sn += card->serialno[7];
|
|
|
|
|
if (sn <= 99999999ul)
|
|
|
|
|
{
|
|
|
|
|
char *buf = xtrymalloc (16);
|
|
|
|
|
if (!buf)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
memcpy (buf, "\xD2\x76\x00\x01\x24\x01", 6);
|
|
|
|
|
buf[6] = 0; /* Application version which we don't know */
|
|
|
|
|
buf[7] = 0; /* thus we use 0.0 and don't use this directly. */
|
|
|
|
|
buf[8] = 0; /* Manufacturer: Yubico (0x0006). */
|
|
|
|
|
buf[9] = 6;
|
2020-11-26 12:36:44 +01:00
|
|
|
|
buf[13] = (sn % 10);
|
|
|
|
|
sn /= 10;
|
|
|
|
|
buf[13] |= (sn % 10) << 4;
|
|
|
|
|
sn /= 10;
|
|
|
|
|
buf[12] = (sn % 10);
|
|
|
|
|
sn /= 10;
|
|
|
|
|
buf[12] |= (sn % 10) << 4;
|
|
|
|
|
sn /= 10;
|
|
|
|
|
buf[11] = (sn % 10);
|
|
|
|
|
sn /= 10;
|
|
|
|
|
buf[11] |= (sn % 10) << 4;
|
|
|
|
|
sn /= 10;
|
|
|
|
|
buf[10] = (sn % 10);
|
|
|
|
|
sn /= 10;
|
|
|
|
|
buf[10] |= (sn % 10) << 4;
|
|
|
|
|
sn /= 10;
|
2020-11-24 18:02:05 +01:00
|
|
|
|
buf[14] = 0; /* Last two bytes are RFU. */
|
|
|
|
|
buf[15] = 0;
|
|
|
|
|
xfree (card->serialno);
|
|
|
|
|
card->serialno = buf;
|
|
|
|
|
card->serialnolen = 16;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (card->serialnolen && card->serialno[0] == 0xff)
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2004-09-09 07:28:47 +00:00
|
|
|
|
/* The serial number starts with our special prefix. This
|
|
|
|
|
requires that we put our default prefix "FF0000" in front. */
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unsigned char *p = xtrymalloc (card->serialnolen + 3);
|
2004-09-09 07:28:47 +00:00
|
|
|
|
if (!p)
|
2009-01-27 11:30:02 +00:00
|
|
|
|
return gpg_error_from_syserror ();
|
2004-09-09 07:28:47 +00:00
|
|
|
|
memcpy (p, "\xff\0", 3);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
memcpy (p+3, card->serialno, card->serialnolen);
|
|
|
|
|
card->serialnolen += 3;
|
|
|
|
|
xfree (card->serialno);
|
|
|
|
|
card->serialno = p;
|
2004-09-09 07:28:47 +00:00
|
|
|
|
}
|
2019-06-19 08:50:40 +02:00
|
|
|
|
else if (!card->serialnolen)
|
2011-02-04 12:57:53 +01:00
|
|
|
|
{
|
2009-01-27 11:30:02 +00:00
|
|
|
|
unsigned char *p = xtrymalloc (3);
|
|
|
|
|
if (!p)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
memcpy (p, "\xff\x7f", 3);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->serialnolen = 3;
|
|
|
|
|
xfree (card->serialno);
|
|
|
|
|
card->serialno = p;
|
2009-01-27 11:30:02 +00:00
|
|
|
|
}
|
2004-09-09 07:28:47 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-01-18 15:48:50 +09:00
|
|
|
|
/* Retrieve the serial number of the card. The serial number is
|
|
|
|
|
returned as a malloced string (hex encoded) in SERIAL. Caller must
|
|
|
|
|
free SERIAL unless the function returns an error. */
|
|
|
|
|
char *
|
2020-11-24 18:02:05 +01:00
|
|
|
|
card_get_serialno (card_t card)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2017-01-18 15:48:50 +09:00
|
|
|
|
char *serial;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card)
|
2017-01-18 15:48:50 +09:00
|
|
|
|
return NULL;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card->serialnolen)
|
2017-01-18 15:48:50 +09:00
|
|
|
|
serial = xtrystrdup ("FF7F00");
|
2020-11-24 18:02:05 +01:00
|
|
|
|
else
|
|
|
|
|
serial = bin2hex (card->serialno, card->serialnolen, NULL);
|
2020-10-23 16:31:03 +09:00
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
return serial;
|
|
|
|
|
}
|
2020-10-23 16:31:03 +09:00
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
/* Same as card_get_serialno but takes an APP object. */
|
|
|
|
|
char *
|
|
|
|
|
app_get_serialno (app_t app)
|
|
|
|
|
{
|
|
|
|
|
if (!app || !app->card)
|
|
|
|
|
{
|
|
|
|
|
gpg_err_set_errno (0);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return card_get_serialno (app->card);
|
|
|
|
|
}
|
2020-10-23 16:31:03 +09:00
|
|
|
|
|
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
/* Return an allocated string with the serial number in a format to be
|
|
|
|
|
* show to the user. With NOFALLBACK set to true return NULL if such an
|
|
|
|
|
* abbreviated S/N is not available, else return the full serial
|
|
|
|
|
* number as a hex string. May return NULL on malloc problem. */
|
|
|
|
|
char *
|
|
|
|
|
card_get_dispserialno (card_t card, int nofallback)
|
|
|
|
|
{
|
|
|
|
|
char *result, *p;
|
|
|
|
|
unsigned long sn;
|
|
|
|
|
|
|
|
|
|
if (card && card->serialno && card->serialnolen == 3+1+4
|
|
|
|
|
&& !memcmp (card->serialno, "\xff\x02\x00", 3))
|
|
|
|
|
{
|
|
|
|
|
/* This is a 4 byte S/N of a Yubikey which seems to be printed
|
|
|
|
|
* on the token in decimal. Maybe they will print larger S/N
|
|
|
|
|
* also in decimal but we can't be sure, thus do it only for
|
|
|
|
|
* these 32 bit numbers. */
|
|
|
|
|
sn = card->serialno[4] * 16777216;
|
|
|
|
|
sn += card->serialno[5] * 65536;
|
|
|
|
|
sn += card->serialno[6] * 256;
|
|
|
|
|
sn += card->serialno[7];
|
|
|
|
|
if ((card->cardversion >> 16) >= 5)
|
|
|
|
|
result = xtryasprintf ("%lu %03lu %03lu",
|
|
|
|
|
(sn/1000000ul),
|
|
|
|
|
(sn/1000ul % 1000ul),
|
|
|
|
|
(sn % 1000ul));
|
2020-10-23 16:31:03 +09:00
|
|
|
|
else
|
2020-11-24 18:02:05 +01:00
|
|
|
|
result = xtryasprintf ("%lu", sn);
|
2020-10-23 16:31:03 +09:00
|
|
|
|
}
|
2020-11-24 18:02:05 +01:00
|
|
|
|
else if (card && card->cardtype == CARDTYPE_YUBIKEY)
|
|
|
|
|
{
|
|
|
|
|
/* Get back the printed Yubikey number from the OpenPGP AID
|
2020-11-26 12:36:44 +01:00
|
|
|
|
* Example: D2760001240100000006120808620000
|
2020-11-24 18:02:05 +01:00
|
|
|
|
*/
|
|
|
|
|
result = card_get_serialno (card);
|
|
|
|
|
if (result && strlen (result) >= 28 && !strncmp (result+16, "0006", 4))
|
|
|
|
|
{
|
2020-11-26 12:36:44 +01:00
|
|
|
|
sn = atoi_4 (result+20) * 10000;
|
|
|
|
|
sn += atoi_4 (result+24);
|
2020-11-24 18:02:05 +01:00
|
|
|
|
if ((card->cardversion >> 16) >= 5)
|
|
|
|
|
p = xtryasprintf ("%lu %03lu %03lu",
|
|
|
|
|
(sn/1000000ul),
|
|
|
|
|
(sn/1000ul % 1000ul),
|
|
|
|
|
(sn % 1000ul));
|
|
|
|
|
else
|
|
|
|
|
p = xtryasprintf ("%lu", sn);
|
|
|
|
|
if (p)
|
|
|
|
|
{
|
|
|
|
|
xfree (result);
|
|
|
|
|
result = p;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (nofallback)
|
|
|
|
|
{
|
|
|
|
|
xfree (result);
|
|
|
|
|
result = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (card && card->app && card->app->apptype == APPTYPE_OPENPGP)
|
|
|
|
|
{
|
|
|
|
|
/* Extract number from standard OpenPGP AID. */
|
|
|
|
|
result = card_get_serialno (card);
|
|
|
|
|
if (result && strlen (result) > 16+12)
|
|
|
|
|
{
|
|
|
|
|
memcpy (result, result+16, 4);
|
|
|
|
|
result[4] = ' ';
|
|
|
|
|
memcpy (result+5, result+20, 8);
|
|
|
|
|
result[13] = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (nofallback)
|
|
|
|
|
{
|
|
|
|
|
xfree (result);
|
|
|
|
|
result = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (nofallback)
|
|
|
|
|
result = NULL; /* No Abbreviated S/N. */
|
2009-01-27 11:30:02 +00:00
|
|
|
|
else
|
2020-11-24 18:02:05 +01:00
|
|
|
|
result = card_get_serialno (card);
|
2008-11-03 10:54:18 +00:00
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
return result;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
/* Same as card_get_dispserialno but takes an APP object. */
|
2019-06-19 08:50:40 +02:00
|
|
|
|
char *
|
2020-11-24 18:02:05 +01:00
|
|
|
|
app_get_dispserialno (app_t app, int nofallback)
|
2019-06-19 08:50:40 +02:00
|
|
|
|
{
|
|
|
|
|
if (!app || !app->card)
|
2020-11-24 18:02:05 +01:00
|
|
|
|
{
|
|
|
|
|
gpg_err_set_errno (0);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return card_get_dispserialno (app->card, nofallback);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2020-01-13 12:08:23 +01:00
|
|
|
|
/* 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)
|
|
|
|
|
{
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (a_prev->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = a_prev->fnc.prep_reselect (a_prev, ctrl);
|
2020-01-13 12:08:23 +01:00
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (a->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = a->fnc.reselect (a, ctrl);
|
2020-01-13 12:08:23 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
/* Check that the card has been initialized and whether we need to
|
|
|
|
|
* 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
|
2020-01-07 18:45:33 +01:00
|
|
|
|
* CARD->app. This function must be called with the card lock held. */
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
static gpg_error_t
|
2019-09-05 14:05:05 +02:00
|
|
|
|
maybe_switch_app (ctrl_t ctrl, card_t card, const char *keyref)
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
2019-09-05 14:05:05 +02:00
|
|
|
|
app_t app;
|
|
|
|
|
app_t app_prev = NULL;
|
|
|
|
|
apptype_t apptype;
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
|
|
|
|
|
if (!card->ref_count || !card->app)
|
|
|
|
|
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
|
|
|
|
if (!ctrl->current_apptype)
|
|
|
|
|
{
|
|
|
|
|
/* For whatever reasons the current apptype has not been set -
|
|
|
|
|
* fix that and use the current app. */
|
2020-11-26 12:16:56 +01:00
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d: no current app switching to %s\n",
|
|
|
|
|
card->slot, strapptype (card->app->apptype));
|
|
|
|
|
ctrl->current_apptype = card->app->apptype;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
for (app = card->app; app; app = app->next)
|
|
|
|
|
if (app->apptype == ctrl->current_apptype)
|
|
|
|
|
break;
|
|
|
|
|
if (!app)
|
|
|
|
|
{
|
|
|
|
|
/* The current app is not supported by this card. Set the first
|
|
|
|
|
* app of the card as current. */
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d: current app %s not available switching to %s\n",
|
|
|
|
|
card->slot, strapptype (ctrl->current_apptype),
|
|
|
|
|
strapptype (card->app->apptype));
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
ctrl->current_apptype = card->app->apptype;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d: have=%s want=%s keyref=%s\n",
|
|
|
|
|
card->slot, strapptype (card->app->apptype),
|
|
|
|
|
strapptype (ctrl->current_apptype),
|
|
|
|
|
keyref? keyref:"[none]");
|
|
|
|
|
|
|
|
|
|
app = NULL;
|
|
|
|
|
if (keyref)
|
|
|
|
|
{
|
|
|
|
|
/* Switch based on the requested KEYREF. */
|
|
|
|
|
apptype = apptype_from_keyref (keyref);
|
|
|
|
|
if (apptype)
|
|
|
|
|
{
|
|
|
|
|
for (app = card->app; app; app_prev = app, app = app->next)
|
|
|
|
|
if (app->apptype == apptype)
|
|
|
|
|
break;
|
|
|
|
|
if (!app_prev && ctrl->current_apptype == card->app->apptype)
|
|
|
|
|
return 0; /* Already the first app - no need to switch. */
|
|
|
|
|
}
|
|
|
|
|
else if (strlen (keyref) == 40)
|
|
|
|
|
{
|
|
|
|
|
/* This looks like a keygrip. Iterate over all apps to find
|
|
|
|
|
* the corresponding app. */
|
|
|
|
|
for (app = card->app; app; app_prev = app, app = app->next)
|
|
|
|
|
if (app->fnc.with_keygrip
|
2021-04-01 10:31:52 +02:00
|
|
|
|
&& !app->need_reset
|
2019-09-05 14:05:05 +02:00
|
|
|
|
&& !app->fnc.with_keygrip (app, ctrl,
|
2019-12-19 17:30:59 +09:00
|
|
|
|
KEYGRIP_ACTION_LOOKUP, keyref, 0))
|
2019-09-05 14:05:05 +02:00
|
|
|
|
break;
|
|
|
|
|
if (!app_prev && ctrl->current_apptype == card->app->apptype)
|
|
|
|
|
return 0; /* Already the first app - no need to switch. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!app)
|
|
|
|
|
{
|
|
|
|
|
/* Switch based on the current application of this connection or
|
|
|
|
|
* if a keyref based switch didn't worked. */
|
|
|
|
|
if (ctrl->current_apptype == card->app->apptype)
|
|
|
|
|
return 0; /* No need to switch. */
|
|
|
|
|
app_prev = card->app;
|
|
|
|
|
for (app = app_prev->next; app; app_prev = app, app = app->next)
|
|
|
|
|
if (app->apptype == ctrl->current_apptype)
|
|
|
|
|
break;
|
|
|
|
|
}
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
if (!app)
|
|
|
|
|
return gpg_error (GPG_ERR_WRONG_CARD);
|
|
|
|
|
|
2020-01-13 12:08:23 +01:00
|
|
|
|
err = run_reselect (ctrl, card, app, app_prev);
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
if (err)
|
2020-01-13 12:08:23 +01:00
|
|
|
|
return err;
|
2019-09-05 14:05:05 +02:00
|
|
|
|
|
|
|
|
|
/* Swap APP with the head of the app list if needed. Note that APP
|
|
|
|
|
* is not the head of the list. */
|
|
|
|
|
if (app_prev)
|
|
|
|
|
{
|
|
|
|
|
app_prev->next = app->next;
|
|
|
|
|
app->next = card->app;
|
|
|
|
|
card->app = app;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opt.verbose)
|
2020-01-13 12:08:23 +01:00
|
|
|
|
log_info ("slot %d, app %s: %s\n",
|
|
|
|
|
card->slot, xstrapptype (app),
|
|
|
|
|
app_prev? "switched":"re-selected");
|
2019-09-05 14:05:05 +02:00
|
|
|
|
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
ctrl->current_apptype = app->apptype;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-09-04 12:08:07 +02:00
|
|
|
|
/* Helper for app_write_learn_status. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
write_learn_status_core (card_t card, app_t app, ctrl_t ctrl,
|
|
|
|
|
unsigned int flags)
|
|
|
|
|
{
|
2021-04-01 10:31:52 +02:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2019-09-04 12:08:07 +02:00
|
|
|
|
/* We do not send CARD and APPTYPE if only keypairinfo is requested. */
|
|
|
|
|
if (!(flags & APP_LEARN_FLAG_KEYPAIRINFO))
|
|
|
|
|
{
|
|
|
|
|
if (card && card->cardtype)
|
|
|
|
|
send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
|
|
|
|
|
if (card && card->cardversion)
|
|
|
|
|
send_status_printf (ctrl, "CARDVERSION", "%X", card->cardversion);
|
|
|
|
|
if (app->apptype)
|
|
|
|
|
send_status_direct (ctrl, "APPTYPE", strapptype (app->apptype));
|
|
|
|
|
if (app->appversion)
|
|
|
|
|
send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-01 10:31:52 +02:00
|
|
|
|
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;
|
2019-09-04 12:08:07 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-03-05 17:40:08 +01:00
|
|
|
|
/* Write out the application specific status lines for the LEARN
|
2003-08-05 17:11:04 +00:00
|
|
|
|
command. */
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2020-01-07 18:45:33 +01:00
|
|
|
|
gpg_error_t err, err2, tmperr;
|
|
|
|
|
app_t app, last_app;
|
2019-09-04 12:08:07 +02:00
|
|
|
|
int any_reselect = 0;
|
2005-05-18 10:48:06 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-01-29 13:28:10 +01:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-04 12:08:07 +02:00
|
|
|
|
/* Always make sure that the current app for this connection has
|
|
|
|
|
* been selected and is at the top of the list. */
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, NULL)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
|
|
|
|
else if (!card->app->fnc.learn_status)
|
2019-06-21 14:01:06 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
|
|
|
|
{
|
2019-09-04 12:08:07 +02:00
|
|
|
|
err = write_learn_status_core (card, card->app, ctrl, flags);
|
|
|
|
|
if (!err && card->app->fnc.reselect && (flags & APP_LEARN_FLAG_MULTI))
|
2019-06-21 14:01:06 +02:00
|
|
|
|
{
|
2019-09-04 12:08:07 +02:00
|
|
|
|
/* The current app has the reselect feature so that we can
|
|
|
|
|
* loop over all other apps which are capable of a reselect
|
|
|
|
|
* and finally reselect the first app again. Note that we
|
|
|
|
|
* did the learn for the currently selected card above. */
|
2020-01-07 18:45:33 +01:00
|
|
|
|
app = last_app = card->app;
|
2019-09-04 12:08:07 +02:00
|
|
|
|
for (app = app->next; app && !err; app = app->next)
|
|
|
|
|
if (app->fnc.reselect)
|
|
|
|
|
{
|
2020-01-07 18:45:33 +01:00
|
|
|
|
if (last_app && last_app->fnc.prep_reselect)
|
|
|
|
|
{
|
|
|
|
|
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
|
|
|
|
if (tmperr)
|
2020-01-13 12:08:23 +01:00
|
|
|
|
log_info ("slot %d, app %s:"
|
|
|
|
|
" preparing re-select from %s failed: %s\n",
|
|
|
|
|
card->slot, xstrapptype (app),
|
|
|
|
|
xstrapptype (last_app),
|
2020-01-07 18:45:33 +01:00
|
|
|
|
gpg_strerror (tmperr));
|
|
|
|
|
}
|
2019-09-04 12:08:07 +02:00
|
|
|
|
any_reselect = 1;
|
|
|
|
|
err = app->fnc.reselect (app, ctrl);
|
|
|
|
|
if (!err)
|
2020-01-07 18:45:33 +01:00
|
|
|
|
{
|
|
|
|
|
last_app = app;
|
|
|
|
|
err = write_learn_status_core (NULL, app, ctrl, flags);
|
|
|
|
|
}
|
2019-09-04 12:08:07 +02:00
|
|
|
|
}
|
|
|
|
|
app = card->app;
|
|
|
|
|
if (any_reselect)
|
|
|
|
|
{
|
2020-01-07 18:45:33 +01:00
|
|
|
|
if (last_app && last_app->fnc.prep_reselect)
|
|
|
|
|
{
|
|
|
|
|
tmperr = last_app->fnc.prep_reselect (last_app, ctrl);
|
|
|
|
|
if (tmperr)
|
2020-01-13 12:08:23 +01:00
|
|
|
|
log_info ("slot %d, app %s:"
|
|
|
|
|
" preparing re-select from %s failed: %s\n",
|
|
|
|
|
card->slot, xstrapptype (app),
|
|
|
|
|
xstrapptype (last_app), gpg_strerror (tmperr));
|
2020-01-07 18:45:33 +01:00
|
|
|
|
}
|
2019-09-04 12:08:07 +02:00
|
|
|
|
err2 = app->fnc.reselect (app, ctrl);
|
|
|
|
|
if (err2)
|
|
|
|
|
{
|
|
|
|
|
log_error ("error re-selecting '%s': %s\n",
|
|
|
|
|
strapptype(app->apptype), gpg_strerror (err2));
|
|
|
|
|
if (!err)
|
|
|
|
|
err = err2;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2004-01-27 16:40:42 +00:00
|
|
|
|
/* Read the certificate with id CERTID (as returned by learn_status in
|
|
|
|
|
the CERTINFO status lines) and return it in the freshly allocated
|
|
|
|
|
buffer put into CERT and the length of the certificate put into
|
|
|
|
|
CERTLEN. */
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_readcert (card_t card, ctrl_t ctrl, const char *certid,
|
2004-01-27 16:40:42 +00:00
|
|
|
|
unsigned char **cert, size_t *certlen)
|
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card)
|
2004-01-27 16:40:42 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, certid)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.readcert)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling readcert(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), certid);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.readcert (card->app, certid, cert, certlen);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return err;
|
2004-01-27 16:40:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-02-22 17:29:07 +00:00
|
|
|
|
/* Read the key with ID KEYID. On success a canonical encoded
|
2019-04-03 17:31:09 +02:00
|
|
|
|
* S-expression with the public key will get stored at PK and its
|
|
|
|
|
* length (for assertions) at PKLEN; the caller must release that
|
|
|
|
|
* buffer. On error NULL will be stored at PK and PKLEN and an error
|
|
|
|
|
* code returned. If the key is not required NULL may be passed for
|
Spelling cleanup.
No functional changes, just fixing minor spelling issues.
---
Most of these were identified from the command line by running:
codespell \
--ignore-words-list fpr,stati,keyserver,keyservers,asign,cas,iff,ifset \
--skip '*.po,ChangeLog*,help.*.txt,*.jpg,*.eps,*.pdf,*.png,*.gpg,*.asc' \
doc g13 g10 kbx agent artwork scd tests tools am common dirmngr sm \
NEWS README README.maint TODO
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2020-02-18 09:34:42 -05:00
|
|
|
|
* PK; this makes sense if the APP_READKEY_FLAG_INFO has also been set.
|
2019-04-03 17:31:09 +02:00
|
|
|
|
*
|
|
|
|
|
* This function might not be supported by all applications. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags,
|
2016-11-04 13:45:57 +09:00
|
|
|
|
unsigned char **pk, size_t *pklen)
|
2005-02-22 17:29:07 +00:00
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2005-02-22 17:29:07 +00:00
|
|
|
|
if (pk)
|
|
|
|
|
*pk = NULL;
|
|
|
|
|
if (pklen)
|
|
|
|
|
*pklen = 0;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !keyid)
|
2005-02-22 17:29:07 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, keyid)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.readkey)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling readkey(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), keyid);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
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);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return err;
|
2005-02-22 17:29:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-09-30 17:35:05 +00:00
|
|
|
|
/* Perform a GETATTR operation. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_getattr (card_t card, ctrl_t ctrl, const char *name)
|
2003-09-30 17:35:05 +00:00
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !name || !*name)
|
2003-09-30 17:35:05 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-21 14:01:06 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2005-02-24 21:40:48 +00:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, NULL)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (name && !strcmp (name, "CARDTYPE"))
|
2019-01-29 13:28:10 +01:00
|
|
|
|
{
|
2019-06-19 14:30:16 +02:00
|
|
|
|
send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
|
2019-01-29 13:28:10 +01:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (name && !strcmp (name, "APPTYPE"))
|
2005-02-24 21:40:48 +00:00
|
|
|
|
{
|
2019-06-19 14:30:16 +02:00
|
|
|
|
send_status_direct (ctrl, "APPTYPE", strapptype (card->app->apptype));
|
2005-02-24 21:40:48 +00:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (name && !strcmp (name, "SERIALNO"))
|
2005-02-24 21:40:48 +00:00
|
|
|
|
{
|
|
|
|
|
char *serial;
|
2011-02-04 12:57:53 +01:00
|
|
|
|
|
2020-10-23 15:25:07 +09:00
|
|
|
|
serial = app_get_serialno (card->app);
|
2017-01-18 15:48:50 +09:00
|
|
|
|
if (!serial)
|
2019-06-21 14:01:06 +02:00
|
|
|
|
err = gpg_error (GPG_ERR_INV_VALUE);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
send_status_direct (ctrl, "SERIALNO", serial);
|
|
|
|
|
xfree (serial);
|
|
|
|
|
}
|
2005-02-24 21:40:48 +00:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.getattr)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling getattr(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), name);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.getattr (card->app, ctrl, name);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2005-02-24 21:40:48 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return err;
|
2003-09-30 17:35:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
/* Perform a SETATTR operation. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_setattr (card_t card, ctrl_t ctrl, const char *name,
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const unsigned char *value, size_t valuelen)
|
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !name || !*name || !value)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, NULL)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.setattr)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling setattr(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), name);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.setattr (card->app, ctrl, name, pincb, pincb_arg,
|
|
|
|
|
value, valuelen);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
/* Create the signature and return the allocated result in OUTDATA.
|
|
|
|
|
If a PIN is required the PINCB will be used to ask for the PIN; it
|
|
|
|
|
should return the PIN in an allocated buffer and put it into PIN. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const void *indata, size_t indatalen,
|
|
|
|
|
unsigned char **outdata, size_t *outdatalen )
|
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, keyidstr)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.sign)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling sign(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), keyidstr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.sign (card->app, ctrl, keyidstr, hashalgo,
|
|
|
|
|
pincb, pincb_arg,
|
|
|
|
|
indata, indatalen,
|
|
|
|
|
outdata, outdatalen);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
if (opt.verbose)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
log_info ("operation sign result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2003-08-05 17:11:04 +00:00
|
|
|
|
/* Create the signature using the INTERNAL AUTHENTICATE command and
|
|
|
|
|
return the allocated result in OUTDATA. If a PIN is required the
|
|
|
|
|
PINCB will be used to ask for the PIN; it should return the PIN in
|
|
|
|
|
an allocated buffer and put it into PIN. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const void *indata, size_t indatalen,
|
|
|
|
|
unsigned char **outdata, size_t *outdatalen )
|
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, keyidstr)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.auth)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling auth(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), keyidstr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.auth (card->app, ctrl, keyidstr,
|
|
|
|
|
pincb, pincb_arg,
|
|
|
|
|
indata, indatalen,
|
|
|
|
|
outdata, outdatalen);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
if (opt.verbose)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
log_info ("operation auth result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Decrypt the data in INDATA and return the allocated result in OUTDATA.
|
|
|
|
|
If a PIN is required the PINCB will be used to ask for the PIN; it
|
|
|
|
|
should return the PIN in an allocated buffer and put it into PIN. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const void *indata, size_t indatalen,
|
2013-08-26 17:29:54 +02:00
|
|
|
|
unsigned char **outdata, size_t *outdatalen,
|
|
|
|
|
unsigned int *r_info)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2013-08-26 17:29:54 +02:00
|
|
|
|
*r_info = 0;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, keyidstr)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.decipher)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling decipher(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), keyidstr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.decipher (card->app, ctrl, keyidstr,
|
|
|
|
|
pincb, pincb_arg,
|
|
|
|
|
indata, indatalen,
|
|
|
|
|
outdata, outdatalen,
|
|
|
|
|
r_info);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
if (opt.verbose)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
log_info ("operation decipher result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2008-09-23 09:57:45 +00:00
|
|
|
|
/* Perform the WRITECERT operation. */
|
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_writecert (card_t card, ctrl_t ctrl,
|
|
|
|
|
const char *certidstr,
|
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const unsigned char *data, size_t datalen)
|
2008-09-23 09:57:45 +00:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !certidstr || !*certidstr || !pincb)
|
2008-09-23 09:57:45 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2008-09-23 09:57:45 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, certidstr)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.writecert)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling writecert(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), certidstr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.writecert (card->app, ctrl, certidstr,
|
|
|
|
|
pincb, pincb_arg, data, datalen);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2008-09-23 09:57:45 +00:00
|
|
|
|
if (opt.verbose)
|
|
|
|
|
log_info ("operation writecert result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-05-20 20:39:36 +00:00
|
|
|
|
/* Perform the WRITEKEY operation. */
|
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_writekey (card_t card, ctrl_t ctrl,
|
2005-05-20 20:39:36 +00:00
|
|
|
|
const char *keyidstr, unsigned int flags,
|
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const unsigned char *keydata, size_t keydatalen)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !keyidstr || !*keyidstr || !pincb)
|
2005-05-20 20:39:36 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-20 20:39:36 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, keyidstr)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.writekey)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling writekey(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), keyidstr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags,
|
|
|
|
|
pincb, pincb_arg, keydata, keydatalen);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-05-20 20:39:36 +00:00
|
|
|
|
if (opt.verbose)
|
|
|
|
|
log_info ("operation writekey result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-06-21 14:01:06 +02:00
|
|
|
|
/* Perform a GENKEY operation. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_genkey (card_t card, ctrl_t ctrl, const char *keynostr,
|
2019-02-06 14:07:42 +01:00
|
|
|
|
const char *keytype, unsigned int flags, time_t createtime,
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void *pincb_arg)
|
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !keynostr || !*keynostr || !pincb)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, keynostr)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.genkey)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling genkey(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), keynostr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags,
|
|
|
|
|
createtime, pincb, pincb_arg);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
if (opt.verbose)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
log_info ("operation genkey result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2015-11-16 12:41:46 +01:00
|
|
|
|
/* Perform a GET CHALLENGE operation. This function is special as it
|
2003-08-05 17:11:04 +00:00
|
|
|
|
directly accesses the card without any application specific
|
|
|
|
|
wrapper. */
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_get_challenge (card_t card, ctrl_t ctrl,
|
|
|
|
|
size_t nbytes, unsigned char *buffer)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !nbytes || !buffer)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
|
|
|
|
if (!card->ref_count)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
|
|
|
|
|
else
|
|
|
|
|
err = iso7816_get_challenge (card->slot, nbytes, buffer);
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr,
|
2019-02-06 12:24:30 +01:00
|
|
|
|
unsigned int flags,
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
2003-08-05 17:11:04 +00:00
|
|
|
|
void *pincb_arg)
|
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !chvnostr || !*chvnostr || !pincb)
|
2003-08-05 17:11:04 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, NULL)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.change_pin)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling change_pin(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), chvnostr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.change_pin (card->app, ctrl,
|
|
|
|
|
chvnostr, flags, pincb, pincb_arg);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2003-08-05 17:11:04 +00:00
|
|
|
|
if (opt.verbose)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
log_info ("operation change_pin result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-08-05 17:11:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-01-21 14:06:51 +01:00
|
|
|
|
/* Perform a VERIFY operation without doing anything else. This may
|
2017-04-28 10:06:33 +09:00
|
|
|
|
be used to initialize a the PIN cache for long lasting other
|
2003-10-21 17:12:50 +00:00
|
|
|
|
operations. Its use is highly application dependent. */
|
2011-02-04 12:57:53 +01:00
|
|
|
|
gpg_error_t
|
2019-06-19 08:50:40 +02:00
|
|
|
|
app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
2003-10-21 17:12:50 +00:00
|
|
|
|
void *pincb_arg)
|
|
|
|
|
{
|
2005-05-18 10:48:06 +00:00
|
|
|
|
gpg_error_t err;
|
2003-10-21 17:12:50 +00:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (!card || !keyidstr || !*keyidstr || !pincb)
|
2003-10-21 17:12:50 +00:00
|
|
|
|
return gpg_error (GPG_ERR_INV_VALUE);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
err = lock_card (card, ctrl);
|
2005-05-18 10:48:06 +00:00
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-09-05 14:05:05 +02:00
|
|
|
|
if ((err = maybe_switch_app (ctrl, card, NULL)))
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
;
|
2019-06-21 14:01:06 +02:00
|
|
|
|
else if (!card->app->fnc.check_pin)
|
|
|
|
|
err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
|
|
|
|
|
else
|
2019-09-05 12:59:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("slot %d app %s: calling check_pin(%s)\n",
|
|
|
|
|
card->slot, xstrapptype (card->app), keyidstr);
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (card->app->need_reset)
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_RESET);
|
|
|
|
|
else
|
|
|
|
|
err = card->app->fnc.check_pin (card->app, ctrl, keyidstr,
|
|
|
|
|
pincb, pincb_arg);
|
2019-09-05 12:59:56 +02:00
|
|
|
|
}
|
2019-06-21 14:01:06 +02:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2003-10-21 17:12:50 +00:00
|
|
|
|
if (opt.verbose)
|
2005-05-18 10:48:06 +00:00
|
|
|
|
log_info ("operation check_pin result: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2003-10-21 17:12:50 +00:00
|
|
|
|
}
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2016-12-28 12:29:17 +09:00
|
|
|
|
static void
|
|
|
|
|
report_change (int slot, int old_status, int cur_status)
|
|
|
|
|
{
|
|
|
|
|
char *homestr, *envstr;
|
|
|
|
|
char *fname;
|
|
|
|
|
char templ[50];
|
2020-10-20 11:52:16 +02:00
|
|
|
|
estream_t fp;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
|
|
|
|
snprintf (templ, sizeof templ, "reader_%d.status", slot);
|
|
|
|
|
fname = make_filename (gnupg_homedir (), templ, NULL );
|
2020-10-20 11:52:16 +02:00
|
|
|
|
fp = es_fopen (fname, "w");
|
2016-12-28 12:29:17 +09:00
|
|
|
|
if (fp)
|
|
|
|
|
{
|
2020-10-20 11:52:16 +02:00
|
|
|
|
es_fprintf (fp, "%s\n",
|
2016-12-28 12:29:17 +09:00
|
|
|
|
(cur_status & 1)? "USABLE":
|
|
|
|
|
(cur_status & 4)? "ACTIVE":
|
|
|
|
|
(cur_status & 2)? "PRESENT": "NOCARD");
|
2020-10-20 11:52:16 +02:00
|
|
|
|
es_fclose (fp);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
|
|
|
|
xfree (fname);
|
|
|
|
|
|
|
|
|
|
homestr = make_filename (gnupg_homedir (), NULL);
|
|
|
|
|
if (gpgrt_asprintf (&envstr, "GNUPGHOME=%s", homestr) < 0)
|
|
|
|
|
log_error ("out of core while building environment\n");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
const char *args[9], *envs[2];
|
|
|
|
|
char numbuf1[30], numbuf2[30], numbuf3[30];
|
|
|
|
|
|
|
|
|
|
envs[0] = envstr;
|
|
|
|
|
envs[1] = NULL;
|
|
|
|
|
|
|
|
|
|
sprintf (numbuf1, "%d", slot);
|
|
|
|
|
sprintf (numbuf2, "0x%04X", old_status);
|
|
|
|
|
sprintf (numbuf3, "0x%04X", cur_status);
|
|
|
|
|
args[0] = "--reader-port";
|
|
|
|
|
args[1] = numbuf1;
|
|
|
|
|
args[2] = "--old-code";
|
|
|
|
|
args[3] = numbuf2;
|
|
|
|
|
args[4] = "--new-code";
|
|
|
|
|
args[5] = numbuf3;
|
|
|
|
|
args[6] = "--status";
|
|
|
|
|
args[7] = ((cur_status & 1)? "USABLE":
|
|
|
|
|
(cur_status & 4)? "ACTIVE":
|
|
|
|
|
(cur_status & 2)? "PRESENT": "NOCARD");
|
|
|
|
|
args[8] = NULL;
|
|
|
|
|
|
|
|
|
|
fname = make_filename (gnupg_homedir (), "scd-event", NULL);
|
|
|
|
|
err = gnupg_spawn_process_detached (fname, args, envs);
|
|
|
|
|
if (err && gpg_err_code (err) != GPG_ERR_ENOENT)
|
|
|
|
|
log_error ("failed to run event handler '%s': %s\n",
|
|
|
|
|
fname, gpg_strerror (err));
|
|
|
|
|
xfree (fname);
|
|
|
|
|
xfree (envstr);
|
|
|
|
|
}
|
|
|
|
|
xfree (homestr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2017-01-31 12:56:11 +09:00
|
|
|
|
int
|
2016-12-28 12:29:17 +09:00
|
|
|
|
scd_update_reader_status_file (void)
|
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_t card, card_next;
|
2017-01-28 00:18:11 +09:00
|
|
|
|
int periodical_check_needed = 0;
|
2020-04-02 15:39:26 +09:00
|
|
|
|
int reported = 0;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_lock (&card_list_lock);
|
|
|
|
|
for (card = card_top; card; card = card_next)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2017-01-27 18:01:52 +09:00
|
|
|
|
int sw;
|
|
|
|
|
unsigned int status;
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
lock_card (card, NULL);
|
|
|
|
|
card_next = card->next;
|
2017-01-27 18:01:52 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (card->reset_requested)
|
2017-02-15 18:23:01 +09:00
|
|
|
|
status = 0;
|
|
|
|
|
else
|
2017-01-27 18:01:52 +09:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
sw = apdu_get_status (card->slot, 0, &status);
|
2017-02-15 18:23:01 +09:00
|
|
|
|
if (sw == SW_HOST_NO_READER)
|
|
|
|
|
{
|
|
|
|
|
/* Most likely the _reader_ has been unplugged. */
|
|
|
|
|
status = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (sw)
|
|
|
|
|
{
|
|
|
|
|
/* Get status failed. Ignore that. */
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (card->periodical_check_needed)
|
2017-02-15 18:23:01 +09:00
|
|
|
|
periodical_check_needed = 1;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2017-02-15 18:23:01 +09:00
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-01-27 18:01:52 +09:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (card->card_status != status)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
report_change (card->slot, card->card_status, status);
|
|
|
|
|
send_client_notifications (card, status == 0);
|
2020-04-02 15:39:26 +09:00
|
|
|
|
reported++;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2017-01-27 18:01:52 +09:00
|
|
|
|
if (status == 0)
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2021-02-22 17:51:11 +01:00
|
|
|
|
if (DBG_APP)
|
|
|
|
|
log_debug ("Removal of a card: %d\n", card->slot);
|
2020-01-13 17:53:49 +01:00
|
|
|
|
pincache_put (NULL, card->slot, NULL, NULL, NULL, 0);
|
2019-06-19 08:50:40 +02:00
|
|
|
|
apdu_close_reader (card->slot);
|
|
|
|
|
deallocate_card (card);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
2017-01-27 18:01:52 +09:00
|
|
|
|
else
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card->card_status = status;
|
|
|
|
|
if (card->periodical_check_needed)
|
2017-01-28 00:18:11 +09:00
|
|
|
|
periodical_check_needed = 1;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-01-27 18:01:52 +09:00
|
|
|
|
else
|
|
|
|
|
{
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (card->periodical_check_needed)
|
2017-01-28 00:18:11 +09:00
|
|
|
|
periodical_check_needed = 1;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
unlock_card (card);
|
2017-01-27 18:01:52 +09:00
|
|
|
|
}
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2020-04-02 15:39:26 +09:00
|
|
|
|
if (reported)
|
|
|
|
|
npth_cond_broadcast (¬ify_cond);
|
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
2017-01-27 18:01:52 +09:00
|
|
|
|
|
2017-01-31 12:56:11 +09:00
|
|
|
|
return periodical_check_needed;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This function must be called once to initialize this module. This
|
|
|
|
|
has to be done before a second thread is spawned. We can't do the
|
|
|
|
|
static initialization because Pth emulation code might not be able
|
|
|
|
|
to do a static init; in particular, it is not possible for W32. */
|
2016-12-29 10:07:43 +09:00
|
|
|
|
gpg_error_t
|
2016-12-28 12:29:17 +09:00
|
|
|
|
initialize_module_command (void)
|
|
|
|
|
{
|
2016-12-29 10:07:43 +09:00
|
|
|
|
gpg_error_t err;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
if (npth_mutex_init (&card_list_lock, NULL))
|
2016-12-28 12:29:17 +09:00
|
|
|
|
{
|
2016-12-29 10:07:43 +09:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error ("app: error initializing mutex: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
2016-12-29 10:07:43 +09:00
|
|
|
|
|
2020-04-02 15:39:26 +09:00
|
|
|
|
err = npth_cond_init (¬ify_cond, NULL);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error ("npth_cond_init failed: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-29 10:07:43 +09:00
|
|
|
|
return apdu_init ();
|
2016-12-28 12:29:17 +09:00
|
|
|
|
}
|
scd: Support multiple readers by CCID driver.
* scd/apdu.c (new_reader_slot): Lock is now in apdu_dev_list_start.
(close_pcsc_reader_direct, close_ccid_reader): RDRNAME is handled...
(apdu_close_reader): ... by this function now.
(apdu_prepare_exit): Likewise.
(open_ccid_reader): Open with dev_list.
(apdu_dev_list_start, apdu_dev_list_finish): New.
(apdu_open_one_reader): New.
(apdu_open_reader): Support multiple readers.
* scd/app.c (select_application): With SCAN, opening all readers
available, and register as new APP.
(app_write_learn_status): app->ref_count == 0 is valid for APP which is
not yet used.
(app_list_start, app_list_finish): New.
* scd/ccid-driver.c (struct ccid_driver_s): Remove RID and BCD_DEVICE.
Add BAI.
(parse_ccid_descriptor): BCD_DEVICE is now on the arguments.
(ccid_dev_scan, ccid_dev_scan_finish): New.
(ccid_get_BAI, ccid_compare_BAI, ccid_open_usb_reader): New.
(ccid_open_reader): Support multiple readers.
(ccid_set_progress_cb, ccid_close_reader): No RID any more.
--
With this change, multiple readers/tokens are supported by the internal
CCID driver of GnuPG. Until the changes of upper layers (scdaemon,
gpg-agent, and gpg front end), only a single reader is used, though.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2017-01-06 09:14:13 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2019-06-25 09:23:38 +02:00
|
|
|
|
/* Sort helper for app_send_card_list. */
|
|
|
|
|
static int
|
|
|
|
|
compare_card_list_items (const void *arg_a, const void *arg_b)
|
|
|
|
|
{
|
|
|
|
|
const card_t a = *(const card_t *)arg_a;
|
|
|
|
|
const card_t b = *(const card_t *)arg_b;
|
|
|
|
|
|
|
|
|
|
return a->slot - b->slot;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-01-16 19:42:16 +01:00
|
|
|
|
/* Helper for send_card_and_app_list and app_switch_active_app. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
send_serialno_and_app_status (card_t card, int with_apps, ctrl_t ctrl)
|
2017-01-18 15:19:38 +09:00
|
|
|
|
{
|
2019-06-25 09:23:38 +02:00
|
|
|
|
gpg_error_t err;
|
2020-01-16 19:42:16 +01:00
|
|
|
|
app_t a;
|
2020-10-23 16:31:03 +09:00
|
|
|
|
char *serial;
|
2020-01-16 19:42:16 +01:00
|
|
|
|
char *p;
|
|
|
|
|
membuf_t mb;
|
2020-02-13 15:43:17 +01:00
|
|
|
|
int any = 0;
|
2020-01-16 19:42:16 +01:00
|
|
|
|
|
2020-11-24 18:02:05 +01:00
|
|
|
|
serial = card_get_serialno (card);
|
2020-10-23 16:31:03 +09:00
|
|
|
|
if (!serial)
|
2020-01-16 19:42:16 +01:00
|
|
|
|
return 0; /* Oops. */
|
|
|
|
|
|
|
|
|
|
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. */
|
2020-05-26 16:10:57 +02:00
|
|
|
|
err = select_all_additional_applications_internal (ctrl, card);
|
2020-01-16 19:42:16 +01:00
|
|
|
|
if (err)
|
2020-10-23 16:31:03 +09:00
|
|
|
|
{
|
|
|
|
|
xfree (serial);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2020-01-16 19:42:16 +01:00
|
|
|
|
|
|
|
|
|
init_membuf (&mb, 256);
|
2020-10-23 16:31:03 +09:00
|
|
|
|
put_membuf_str (&mb, serial);
|
2020-01-16 19:42:16 +01:00
|
|
|
|
for (a = card->app; a; a = a->next)
|
|
|
|
|
{
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (!a->fnc.with_keygrip || a->need_reset)
|
2020-01-16 19:42:16 +01:00
|
|
|
|
continue;
|
2020-02-13 15:43:17 +01:00
|
|
|
|
any = 1;
|
2020-01-16 19:42:16 +01:00
|
|
|
|
put_membuf (&mb, " ", 1);
|
|
|
|
|
put_membuf_str (&mb, xstrapptype (a));
|
|
|
|
|
}
|
2020-02-13 15:43:17 +01:00
|
|
|
|
if (!any && card->app)
|
|
|
|
|
{
|
|
|
|
|
/* No card app supports the with_keygrip function. Use the
|
|
|
|
|
* main app as fallback. */
|
|
|
|
|
put_membuf (&mb, " ", 1);
|
|
|
|
|
put_membuf_str (&mb, xstrapptype (card->app));
|
|
|
|
|
}
|
2020-01-16 19:42:16 +01:00
|
|
|
|
put_membuf (&mb, "", 1);
|
|
|
|
|
p = get_membuf (&mb, NULL);
|
|
|
|
|
if (!p)
|
2020-10-23 16:31:03 +09:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
xfree (serial);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
2020-01-16 19:42:16 +01:00
|
|
|
|
send_status_direct (ctrl, "SERIALNO", p);
|
|
|
|
|
xfree (p);
|
|
|
|
|
}
|
|
|
|
|
else
|
2020-10-23 16:31:03 +09:00
|
|
|
|
send_status_direct (ctrl, "SERIALNO", serial);
|
2020-01-16 19:42:16 +01:00
|
|
|
|
|
2020-10-23 16:31:03 +09:00
|
|
|
|
xfree (serial);
|
2020-01-16 19:42:16 +01:00
|
|
|
|
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;
|
|
|
|
|
card_t c;
|
2019-06-25 09:23:38 +02:00
|
|
|
|
card_t *cardlist = NULL;
|
|
|
|
|
int n, ncardlist;
|
2017-01-18 15:19:38 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_lock (&card_list_lock);
|
2019-06-25 09:23:38 +02:00
|
|
|
|
for (n=0, c = card_top; c; c = c->next)
|
|
|
|
|
n++;
|
2020-04-17 16:05:37 +02:00
|
|
|
|
if (!n)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2019-06-25 09:23:38 +02:00
|
|
|
|
cardlist = xtrycalloc (n, sizeof *cardlist);
|
|
|
|
|
if (!cardlist)
|
2017-01-18 15:19:38 +09:00
|
|
|
|
{
|
2019-06-25 09:23:38 +02:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
for (ncardlist=0, c = card_top; c; c = c->next)
|
|
|
|
|
cardlist[ncardlist++] = c;
|
|
|
|
|
qsort (cardlist, ncardlist, sizeof *cardlist, compare_card_list_items);
|
|
|
|
|
|
|
|
|
|
for (n=0; n < ncardlist; n++)
|
|
|
|
|
{
|
2020-01-16 19:42:16 +01:00
|
|
|
|
if (wantcard && wantcard != cardlist[n])
|
2017-01-18 15:48:50 +09:00
|
|
|
|
continue;
|
2020-01-16 19:42:16 +01:00
|
|
|
|
err = send_serialno_and_app_status (cardlist[n], with_apps, ctrl);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
2017-01-18 15:19:38 +09:00
|
|
|
|
}
|
2019-06-25 09:23:38 +02:00
|
|
|
|
|
|
|
|
|
err = 0;
|
|
|
|
|
|
|
|
|
|
leave:
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
2019-06-25 09:23:38 +02:00
|
|
|
|
xfree (cardlist);
|
|
|
|
|
return err;
|
2017-01-18 15:19:38 +09:00
|
|
|
|
}
|
2019-04-25 14:49:49 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
|
2020-01-16 19:42:16 +01:00
|
|
|
|
/* 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. */
|
2020-05-26 16:10:57 +02:00
|
|
|
|
err = select_all_additional_applications_internal (ctrl, card);
|
2020-01-16 19:42:16 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-04-25 14:49:49 +09:00
|
|
|
|
/* Execute an action for each app. ACTION can be one of:
|
2019-06-17 14:35:21 +02:00
|
|
|
|
*
|
|
|
|
|
* - KEYGRIP_ACTION_SEND_DATA
|
|
|
|
|
*
|
|
|
|
|
* If KEYGRIP_STR matches a public key of any active application
|
|
|
|
|
* send information as LF terminated data lines about the public
|
|
|
|
|
* key. The format of these lines is
|
|
|
|
|
* <keygrip> T <serialno> <idstr>
|
|
|
|
|
* If a match was found a pointer to the matching application is
|
|
|
|
|
* returned. With the KEYGRIP_STR given as NULL, lines for all
|
2019-12-19 17:30:59 +09:00
|
|
|
|
* keys (with CAPABILITY) will be send and the return value is
|
|
|
|
|
* GPG_ERR_TRUE.
|
2019-06-17 14:35:21 +02:00
|
|
|
|
*
|
|
|
|
|
* - KEYGRIP_ACTION_WRITE_STATUS
|
|
|
|
|
*
|
|
|
|
|
* Same as KEYGRIP_ACTION_SEND_DATA but uses status lines instead
|
|
|
|
|
* of data lines.
|
|
|
|
|
*
|
|
|
|
|
* - KEYGRIP_ACTION_LOOKUP
|
|
|
|
|
*
|
|
|
|
|
* Returns a pointer to the application matching KEYGRIP_STR but
|
|
|
|
|
* does not emit any status or data lines. If no key with that
|
2019-12-19 17:30:59 +09:00
|
|
|
|
* keygrip is available or KEYGRIP_STR is NULL, GPG_ERR_NOT_FOUND
|
|
|
|
|
* is returned.
|
2019-04-25 14:49:49 +09:00
|
|
|
|
*/
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_t
|
2019-12-19 17:30:59 +09:00
|
|
|
|
app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
|
|
|
|
|
int capability)
|
2019-04-25 14:49:49 +09:00
|
|
|
|
{
|
2019-09-05 12:58:54 +02:00
|
|
|
|
int locked = 0;
|
2019-06-19 08:50:40 +02:00
|
|
|
|
card_t c;
|
2020-01-13 12:08:23 +01:00
|
|
|
|
app_t a, a_prev;
|
2019-04-25 14:49:49 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_lock (&card_list_lock);
|
2019-04-25 14:49:49 +09:00
|
|
|
|
|
2019-06-19 08:50:40 +02:00
|
|
|
|
for (c = card_top; c; c = c->next)
|
2019-09-05 12:58:54 +02:00
|
|
|
|
{
|
|
|
|
|
if (lock_card (c, ctrl))
|
2019-06-21 14:51:55 +02:00
|
|
|
|
{
|
2019-09-05 12:58:54 +02:00
|
|
|
|
c = NULL;
|
|
|
|
|
goto leave_the_loop;
|
2019-06-21 14:51:55 +02:00
|
|
|
|
}
|
2019-09-05 12:58:54 +02:00
|
|
|
|
locked = 1;
|
2020-01-13 12:08:23 +01:00
|
|
|
|
a_prev = NULL;
|
2019-09-05 12:58:54 +02:00
|
|
|
|
for (a = c->app; a; a = a->next)
|
2020-01-13 12:08:23 +01:00
|
|
|
|
{
|
2021-04-01 10:31:52 +02:00
|
|
|
|
if (!a->fnc.with_keygrip || a->need_reset)
|
2020-01-13 12:08:23 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Note that we need to do a re-select even for the current
|
|
|
|
|
* app because the last selected application (e.g. after
|
|
|
|
|
* 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":
|
2020-03-31 19:55:15 +02:00
|
|
|
|
action == KEYGRIP_ACTION_WRITE_STATUS? "status":
|
2020-01-13 12:08:23 +01:00
|
|
|
|
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);
|
|
|
|
|
|
2019-09-05 12:58:54 +02:00
|
|
|
|
unlock_card (c);
|
|
|
|
|
locked = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-08 12:26:51 +09:00
|
|
|
|
leave_the_loop:
|
scd: Add an re-select mechanism to switch apps.
* scd/app-common.h (struct app_ctx_s): Add func ptr 'reselect'.
* scd/app-piv.c (do_reselect): New.
(app_select_piv): Move AID constant to file scope.
* scd/app-openpgp.c (do_reselect): New.
(app_select_openpgp): Move AID constant to file scope.
* scd/app.c (apptype_from_name): New.
(check_application_conflict): Check against all apps of the card.
Always set current_apptype.
(select_additional_application): New.
(maybe_switch_app): New.
(app_write_learn_status, app_readcert, app_readkey, app_getattr)
(app_setattr, app_sign, app_auth, app_decipher, app_writecert)
(app_writekey, app_genkey, app_change_pin, app_check_pin): Use it here.
(app_do_with_keygrip): Force reselect on success.
(app_new_register): Move setting of CURRENT_APPTYPE to ...
(select_application): here so that it will be set to the requested
card.
* scd/command.c (open_card_with_request): Select additional
application if possible.
--
Noet that we will likely need to rework this even more so to get well
defined semantics for card access.
Signed-off-by: Werner Koch <wk@gnupg.org>
2019-06-25 08:30:04 +02:00
|
|
|
|
/* Force switching of the app if the selected one is not the current
|
|
|
|
|
* one. Changing the current apptype is sufficient to do this. */
|
|
|
|
|
if (c && c->app && c->app->apptype != a->apptype)
|
|
|
|
|
ctrl->current_apptype = a->apptype;
|
2019-04-25 14:49:49 +09:00
|
|
|
|
|
2019-09-05 12:58:54 +02:00
|
|
|
|
if (locked && c)
|
|
|
|
|
{
|
|
|
|
|
unlock_card (c);
|
|
|
|
|
locked = 0;
|
|
|
|
|
}
|
2019-06-19 08:50:40 +02:00
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
|
|
|
|
return c;
|
2019-04-25 14:49:49 +09:00
|
|
|
|
}
|
2020-04-02 15:39:26 +09:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
app_wait (void)
|
|
|
|
|
{
|
|
|
|
|
npth_mutex_lock (&card_list_lock);
|
|
|
|
|
npth_cond_wait (¬ify_cond, &card_list_lock);
|
|
|
|
|
npth_mutex_unlock (&card_list_lock);
|
|
|
|
|
}
|