aboutsummaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
Diffstat (limited to 'scd')
-rw-r--r--scd/apdu.c27
-rw-r--r--scd/app-common.h187
-rw-r--r--scd/app-dinsig.c29
-rw-r--r--scd/app-geldkarte.c18
-rw-r--r--scd/app-help.c46
-rw-r--r--scd/app-nks.c78
-rw-r--r--scd/app-openpgp.c515
-rw-r--r--scd/app-p15.c84
-rw-r--r--scd/app-piv.c273
-rw-r--r--scd/app-sc-hsm.c48
-rw-r--r--scd/app.c1320
-rw-r--r--scd/ccid-driver.c187
-rw-r--r--scd/command.c360
-rw-r--r--scd/iso7816.c17
-rw-r--r--scd/scdaemon.c13
-rw-r--r--scd/scdaemon.h19
16 files changed, 2176 insertions, 1045 deletions
diff --git a/scd/apdu.c b/scd/apdu.c
index 816938ac5..2df113c5e 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -42,23 +42,11 @@
#include "rapdu.h"
#endif /*USE_G10CODE_RAPDU*/
-#if defined(GNUPG_SCD_MAIN_HEADER)
-#include GNUPG_SCD_MAIN_HEADER
-#elif GNUPG_MAJOR_VERSION == 1
-/* This is used with GnuPG version < 1.9. The code has been source
- copied from the current GnuPG >= 1.9 and is maintained over
- there. */
-#include "../common/options.h"
-#include "errors.h"
-#include "memory.h"
-#include "../common/util.h"
-#include "../common/i18n.h"
-#include "dynload.h"
-#include "cardglue.h"
-#else /* GNUPG_MAJOR_VERSION != 1 */
-#include "scdaemon.h"
-#include "../common/exechelp.h"
-#endif /* GNUPG_MAJOR_VERSION != 1 */
+#if defined(GNUPG_MAJOR_VERSION)
+# include "scdaemon.h"
+# include "../common/exechelp.h"
+#endif /*GNUPG_MAJOR_VERSION*/
+
#include "../common/host2net.h"
#include "iso7816.h"
@@ -266,8 +254,13 @@ static npth_mutex_t reader_table_lock;
struct pcsc_io_request_s
{
+#if defined(_WIN32) || defined(__CYGWIN__)
+ pcsc_dword_t protocol;
+ pcsc_dword_t pci_len;
+#else
unsigned long protocol;
unsigned long pci_len;
+#endif
};
typedef struct pcsc_io_request_s *pcsc_io_request_t;
diff --git a/scd/app-common.h b/scd/app-common.h
index 3df896228..5866c9b32 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -36,35 +36,95 @@
/* Flags used with app_writekey. */
#define APP_WRITEKEY_FLAG_FORCE 1 /* Force overwriting existing key. */
+/* Flags used with app_readkey. */
+#define APP_READKEY_FLAG_INFO 1 /* Send also a KEYPAIRINFO line. */
+
/* Bit flags set by the decipher function into R_INFO. */
#define APP_DECIPHER_INFO_NOPAD 1 /* Padding has been removed. */
+/* List of supported card types. Generic is the usual ISO7817-4
+ * compliant card. More specific card or token versions can be given
+ * here. Use strcardtype() to map them to a string. */
+typedef enum
+ {
+ CARDTYPE_GENERIC = 0,
+ CARDTYPE_YUBIKEY
+
+ } cardtype_t;
+
+/* List of supported card applications. The source code for each
+ * application can usually be found in an app-NAME.c file. Use
+ * strapptype() to map them to a string. */
+typedef enum
+ {
+ APPTYPE_NONE = 0,
+ APPTYPE_UNDEFINED,
+ APPTYPE_OPENPGP,
+ APPTYPE_PIV,
+ APPTYPE_NKS,
+ APPTYPE_P15,
+ APPTYPE_GELDKARTE,
+ APPTYPE_DINSIG,
+ APPTYPE_SC_HSM
+ } apptype_t;
+
+
+/* Forward declarations. */
+struct card_ctx_s;
+struct app_ctx_s;
struct app_local_s; /* Defined by all app-*.c. */
-struct app_ctx_s {
- struct app_ctx_s *next;
+
+typedef struct card_ctx_s *card_t;
+typedef struct app_ctx_s *app_t;
+
+/* The object describing a card. */
+struct card_ctx_s {
+ card_t next;
npth_mutex_t lock;
- /* Number of connections currently using this application context.
- If this is not 0 the application has been initialized and the
- function pointers may be used. Note that for unsupported
- operations the particular function pointer is set to NULL */
+ /* Number of connections currently using this application context. */
unsigned int ref_count;
/* Used reader slot. */
int slot;
- unsigned char *serialno; /* Serialnumber in raw form, allocated. */
- size_t serialnolen; /* Length in octets of serialnumber. */
- const char *cardtype; /* NULL or string with the token's type. */
- const char *apptype;
+ cardtype_t cardtype; /* The token's type. */
unsigned int cardversion;/* Firmware version of the token or 0. */
- unsigned int appversion; /* Version of the application or 0. */
+
unsigned int card_status;
+
+ /* The serial number is associated with the card and not with a
+ * specific app. If a card uses different serial numbers for its
+ * applications, our code picks the serial number of a specific
+ * application and uses that. */
+ unsigned char *serialno; /* Serialnumber in raw form, allocated. */
+ size_t serialnolen; /* Length in octets of serialnumber. */
+
+ /* A linked list of applications used on this card. The app at the
+ * head of the list is the currently active app; To work with the
+ * other apps, switching to that app might be needed. Switching will
+ * put the active app at the head of the list. */
+ app_t app;
+
+ /* Various flags. */
unsigned int reset_requested:1;
unsigned int periodical_check_needed:1;
+};
+
+
+/* The object describing a card's applications. A card may have
+ * several applications and it is usuallay required to explicity
+ * switch between applications. */
+struct app_ctx_s {
+ app_t next;
+
+ card_t card; /* Link back to the card. */
+
+ apptype_t apptype; /* The type of the application. */
+ unsigned int appversion; /* Version of the application or 0. */
unsigned int did_chv1:1;
unsigned int force_chv1:1; /* True if the card does not cache CHV1. */
unsigned int did_chv2:1;
@@ -72,11 +132,13 @@ struct app_ctx_s {
struct app_local_s *app_local; /* Local to the application. */
struct {
void (*deinit) (app_t app);
+ gpg_error_t (*reselect) (app_t app, ctrl_t ctrl);
gpg_error_t (*learn_status) (app_t app, ctrl_t ctrl, unsigned int flags);
gpg_error_t (*readcert) (app_t app, const char *certid,
unsigned char **cert, size_t *certlen);
- gpg_error_t (*readkey) (app_t app, const char *certid,
- unsigned char **pk, size_t *pklen);
+ gpg_error_t (*readkey) (app_t app, ctrl_t ctrl,
+ const char *certid, unsigned int flags,
+ unsigned char **pk, size_t *pklen);
gpg_error_t (*getattr) (app_t app, ctrl_t ctrl, const char *name);
gpg_error_t (*setattr) (app_t app, const char *name,
gpg_error_t (*pincb)(void*, const char *, char **),
@@ -121,11 +183,35 @@ struct app_ctx_s {
gpg_error_t (*check_pin) (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
+ gpg_error_t (*with_keygrip) (app_t app, ctrl_t ctrl, int action,
+ const char *keygrip_str);
} fnc;
};
+
+/* Action values for app_do_with_keygrip. */
+enum
+ {
+ KEYGRIP_ACTION_SEND_DATA,
+ KEYGRIP_ACTION_WRITE_STATUS,
+ KEYGRIP_ACTION_LOOKUP
+ };
+
+
+/* Helper to get the slot from an APP object. */
+static inline int
+app_get_slot (app_t app)
+{
+ if (app && app->card)
+ return app->card->slot;
+ return -1;
+}
+
+
/*-- app-help.c --*/
unsigned int app_help_count_bits (const unsigned char *a, size_t len);
+gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen,
+ char *hexkeygrip);
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen,
unsigned char **r_pk, size_t *r_pklen);
@@ -133,70 +219,85 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
/*-- app.c --*/
-void app_send_card_list (ctrl_t ctrl);
+const char *strcardtype (cardtype_t t);
+const char *strapptype (apptype_t t);
+
+void app_update_priority_list (const char *arg);
+gpg_error_t app_send_card_list (ctrl_t ctrl);
+char *card_get_serialno (card_t card);
char *app_get_serialno (app_t app);
void app_dump_state (void);
void application_notify_card_reset (int slot);
-gpg_error_t check_application_conflict (const char *name, app_t app);
-gpg_error_t app_reset (app_t app, ctrl_t ctrl, int send_reset);
-gpg_error_t select_application (ctrl_t ctrl, const char *name, app_t *r_app,
+gpg_error_t check_application_conflict (card_t card, const char *name,
+ const unsigned char *serialno_bin,
+ size_t serialno_bin_len);
+gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset);
+gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app,
int scan, const unsigned char *serialno_bin,
size_t serialno_bin_len);
+gpg_error_t select_additional_application (ctrl_t ctrl, const char *name);
char *get_supported_applications (void);
-void release_application (app_t app, int locked_already);
-gpg_error_t app_munge_serialno (app_t app);
-gpg_error_t app_write_learn_status (app_t app, ctrl_t ctrl,
+
+card_t card_ref (card_t card);
+void card_unref (card_t card);
+void card_unref_locked (card_t card);
+
+gpg_error_t app_munge_serialno (card_t card);
+gpg_error_t app_write_learn_status (card_t card, ctrl_t ctrl,
unsigned int flags);
-gpg_error_t app_readcert (app_t app, ctrl_t ctrl, const char *certid,
+gpg_error_t app_readcert (card_t card, ctrl_t ctrl, const char *certid,
unsigned char **cert, size_t *certlen);
-gpg_error_t app_readkey (app_t app, ctrl_t ctrl,
- const char *keyid, unsigned char **pk, size_t *pklen);
-gpg_error_t app_getattr (app_t app, ctrl_t ctrl, const char *name);
-gpg_error_t app_setattr (app_t app, ctrl_t ctrl, const char *name,
- gpg_error_t (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *value, size_t valuelen);
-gpg_error_t app_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
- gpg_error_t (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen );
-gpg_error_t app_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
+gpg_error_t app_readkey (card_t card, ctrl_t ctrl,
+ const char *keyid, unsigned int flags,
+ unsigned char **pk, size_t *pklen);
+gpg_error_t app_getattr (card_t card, ctrl_t ctrl, const char *name);
+gpg_error_t app_setattr (card_t card, ctrl_t ctrl, const char *name,
+ gpg_error_t (*pincb)(void*, const char *, char **),
+ void *pincb_arg,
+ const unsigned char *value, size_t valuelen);
+gpg_error_t app_sign (card_t card, ctrl_t ctrl,
+ const char *keyidstr, int hashalgo,
+ gpg_error_t (*pincb)(void*, const char *, char **),
+ void *pincb_arg,
+ const void *indata, size_t indatalen,
+ unsigned char **outdata, size_t *outdatalen);
+gpg_error_t app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen);
-gpg_error_t app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
+gpg_error_t app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen,
unsigned int *r_info);
-gpg_error_t app_writecert (app_t app, ctrl_t ctrl,
+gpg_error_t 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 *keydata, size_t keydatalen);
-gpg_error_t app_writekey (app_t app, ctrl_t ctrl,
+gpg_error_t app_writekey (card_t card, ctrl_t ctrl,
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 app_genkey (app_t app, ctrl_t ctrl,
+gpg_error_t app_genkey (card_t card, ctrl_t ctrl,
const char *keynostr, const char *keytype,
unsigned int flags, time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
-gpg_error_t app_get_challenge (app_t app, ctrl_t ctrl, size_t nbytes,
+gpg_error_t app_get_challenge (card_t card, ctrl_t ctrl, size_t nbytes,
unsigned char *buffer);
-gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,
+gpg_error_t app_change_pin (card_t card, ctrl_t ctrl,
const char *chvnostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
-gpg_error_t app_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr,
- gpg_error_t (*pincb)(void*, const char *, char **),
- void *pincb_arg);
+gpg_error_t app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
+ gpg_error_t (*pincb)(void*, const char *, char **),
+ void *pincb_arg);
+card_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str);
/*-- app-openpgp.c --*/
diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c
index 983bed6e1..9993b68ff 100644
--- a/scd/app-dinsig.c
+++ b/scd/app-dinsig.c
@@ -81,7 +81,6 @@
#include "../common/i18n.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
@@ -101,7 +100,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
/* Return the certificate of the card holder. */
fid = 0xC000;
- len = app_help_read_length_of_cert (app->slot, fid, &certoff);
+ len = app_help_read_length_of_cert (app_get_slot (app), fid, &certoff);
if (!len)
return 0; /* Card has not been personalized. */
@@ -114,7 +113,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
/* Now we need to read the certificate, so that we can get the
public key out of it. */
- err = iso7816_read_binary (app->slot, certoff, len-certoff, &der, &derlen);
+ err = iso7816_read_binary (app_get_slot (app), certoff, len-certoff,
+ &der, &derlen);
if (err)
{
log_info ("error reading entire certificate from FID 0x%04X: %s\n",
@@ -193,14 +193,14 @@ do_readcert (app_t app, const char *certid,
/* Read the entire file. fixme: This could be optimized by first
reading the header to figure out how long the certificate
actually is. */
- err = iso7816_select_file (app->slot, fid, 0);
+ err = iso7816_select_file (app_get_slot (app), fid, 0);
if (err)
{
log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
return err;
}
- err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
+ err = iso7816_read_binary (app_get_slot (app), 0, 0, &buffer, &buflen);
if (err)
{
log_error ("error reading certificate from FID 0x%04X: %s\n",
@@ -293,7 +293,7 @@ verify_pin (app_t app,
pininfo.maxlen = 8;
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) )
+ && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) )
{
rc = pincb (pincb_arg,
_("||Please enter your PIN at the reader's pinpad"),
@@ -304,7 +304,7 @@ verify_pin (app_t app,
gpg_strerror (rc));
return rc;
}
- rc = iso7816_verify_kp (app->slot, 0x81, &pininfo);
+ rc = iso7816_verify_kp (app_get_slot (app), 0x81, &pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
}
@@ -345,7 +345,8 @@ verify_pin (app_t app,
return gpg_error (GPG_ERR_BAD_PIN);
}
- rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
+ rc = iso7816_verify (app_get_slot (app), 0x81,
+ pinvalue, strlen (pinvalue));
if (gpg_err_code (rc) == GPG_ERR_INV_VALUE)
{
/* We assume that ISO 9564-1 encoding is used and we failed
@@ -366,7 +367,8 @@ verify_pin (app_t app,
paddedpin[i++] = (((*s - '0') << 4) | 0x0f);
while (i < sizeof paddedpin)
paddedpin[i++] = 0xff;
- rc = iso7816_verify (app->slot, 0x81, paddedpin, sizeof paddedpin);
+ rc = iso7816_verify (app_get_slot (app), 0x81,
+ paddedpin, sizeof paddedpin);
}
xfree (pinvalue);
}
@@ -482,7 +484,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
rc = verify_pin (app, pincb, pincb_arg);
if (!rc)
- rc = iso7816_compute_ds (app->slot, 0, data, datalen, 0,
+ rc = iso7816_compute_ds (app_get_slot (app), 0, data, datalen, 0,
outdata, outdatalen);
return rc;
}
@@ -532,7 +534,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
return err;
}
- err = iso7816_change_reference_data (app->slot, 0x81,
+ err = iso7816_change_reference_data (app_get_slot (app), 0x81,
oldpin, oldpinlen,
pinvalue, strlen (pinvalue));
xfree (pinvalue);
@@ -547,14 +549,15 @@ gpg_error_t
app_select_dinsig (app_t app)
{
static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 };
- int slot = app->slot;
+ int slot = app_get_slot (app);
int rc;
rc = iso7816_select_application (slot, aid, sizeof aid, 0);
if (!rc)
{
- app->apptype = "DINSIG";
+ app->apptype = APPTYPE_DINSIG;
+ app->fnc.reselect = NULL;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.getattr = NULL;
diff --git a/scd/app-geldkarte.c b/scd/app-geldkarte.c
index 85bcedc4f..141985932 100644
--- a/scd/app-geldkarte.c
+++ b/scd/app-geldkarte.c
@@ -39,7 +39,6 @@
#include "../common/i18n.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
@@ -277,7 +276,7 @@ app_select_geldkarte (app_t app)
static char const aid[] =
{ 0xD2, 0x76, 0x00, 0x00, 0x25, 0x45, 0x50, 0x02, 0x00 };
gpg_error_t err;
- int slot = app->slot;
+ int slot = app_get_slot (app);
unsigned char *result = NULL;
size_t resultlen;
struct app_local_s *ld;
@@ -312,21 +311,22 @@ app_select_geldkarte (app_t app)
goto leave; /* Probably not a Geldkarte. */
}
- app->apptype = "GELDKARTE";
+ app->apptype = APPTYPE_GELDKARTE;
app->fnc.deinit = do_deinit;
+ app->fnc.reselect = NULL;
/* If we don't have a serialno yet construct it from the EF_ID. */
- if (!app->serialno)
+ if (!app->card->serialno)
{
- app->serialno = xtrymalloc (10);
- if (!app->serialno)
+ app->card->serialno = xtrymalloc (10);
+ if (!app->card->serialno)
{
err = gpg_error_from_syserror ();
goto leave;
}
- memcpy (app->serialno, result, 10);
- app->serialnolen = 10;
- err = app_munge_serialno (app);
+ memcpy (app->card->serialno, result, 10);
+ app->card->serialnolen = 10;
+ err = app_munge_serialno (app->card);
if (err)
goto leave;
}
diff --git a/scd/app-help.c b/scd/app-help.c
index f0f551c55..e3ad74434 100644
--- a/scd/app-help.c
+++ b/scd/app-help.c
@@ -24,7 +24,6 @@
#include <string.h>
#include "scdaemon.h"
-#include "app-common.h"
#include "iso7816.h"
#include "../common/tlv.h"
@@ -52,26 +51,17 @@ app_help_count_bits (const unsigned char *a, size_t len)
}
-/* Return the KEYGRIP for the certificate CERT as an hex encoded
- string in the user provided buffer HEXKEYGRIP which must be of at
- least 41 bytes. */
+/* Return the KEYGRIP for the canonical encoded public key (PK,PKLEN)
+ * as an hex encoded string in the user provided buffer HEXKEYGRIP
+ * which must be of at least 41 bytes. */
gpg_error_t
-app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
+app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip)
{
gpg_error_t err;
gcry_sexp_t s_pkey;
- ksba_sexp_t p;
- size_t n;
- unsigned char array[20];
+ unsigned char array[KEYGRIP_LEN];
- p = ksba_cert_get_public_key (cert);
- if (!p)
- return gpg_error (GPG_ERR_BUG);
- n = gcry_sexp_canon_len (p, 0, NULL, NULL);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- err = gcry_sexp_sscan (&s_pkey, NULL, (char*)p, n);
- xfree (p);
+ err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen);
if (err)
return err; /* Can't parse that S-expression. */
if (!gcry_pk_get_keygrip (s_pkey, array))
@@ -81,12 +71,34 @@ app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
}
gcry_sexp_release (s_pkey);
- bin2hex (array, 20, hexkeygrip);
+ bin2hex (array, KEYGRIP_LEN, hexkeygrip);
return 0;
}
+/* Return the KEYGRIP for the certificate CERT as an hex encoded
+ string in the user provided buffer HEXKEYGRIP which must be of at
+ least 41 bytes. */
+gpg_error_t
+app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
+{
+ gpg_error_t err;
+ ksba_sexp_t p;
+ size_t n;
+
+ p = ksba_cert_get_public_key (cert);
+ if (!p)
+ return gpg_error (GPG_ERR_BUG);
+ n = gcry_sexp_canon_len (p, 0, NULL, NULL);
+ if (!n)
+ return gpg_error (GPG_ERR_INV_SEXP);
+ err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip);
+ ksba_free (p);
+ return err;
+}
+
+
gpg_error_t
app_help_pubkey_from_cert (const void *cert, size_t certlen,
unsigned char **r_pk, size_t *r_pklen)
diff --git a/scd/app-nks.c b/scd/app-nks.c
index 40c941616..d12720cf6 100644
--- a/scd/app-nks.c
+++ b/scd/app-nks.c
@@ -53,7 +53,6 @@
#include "scdaemon.h"
#include "../common/i18n.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
#include "apdu.h"
#include "../common/host2net.h"
@@ -151,13 +150,15 @@ keygripstr_from_pk_file (app_t app, int fid, char *r_gripstr)
int i;
int offset[2] = { 0, 0 };
- err = iso7816_select_file (app->slot, fid, 0);
+ err = iso7816_select_file (app_get_slot (app), fid, 0);
if (err)
return err;
- err = iso7816_read_record (app->slot, 1, 1, 0, &buffer[0], &buflen[0]);
+ err = iso7816_read_record (app_get_slot (app), 1, 1, 0,
+ &buffer[0], &buflen[0]);
if (err)
return err;
- err = iso7816_read_record (app->slot, 2, 1, 0, &buffer[1], &buflen[1]);
+ err = iso7816_read_record (app_get_slot (app), 2, 1, 0,
+ &buffer[1], &buflen[1]);
if (err)
{
xfree (buffer[0]);
@@ -272,7 +273,7 @@ get_chv_status (app_t app, int sigg, int pwid)
command[2] = 0x00;
command[3] = pwid;
- if (apdu_send_direct (app->slot, 0, (unsigned char *)command,
+ if (apdu_send_direct (app_get_slot (app), 0, (unsigned char *)command,
4, 0, NULL, &result, &resultlen))
rc = -1; /* Error. */
else if (resultlen < 2)
@@ -406,7 +407,7 @@ do_learn_status_core (app_t app, ctrl_t ctrl, unsigned int flags, int is_sigg)
{
size_t len;
- len = app_help_read_length_of_cert (app->slot,
+ len = app_help_read_length_of_cert (app_get_slot (app),
filelist[i].fid, NULL);
if (len)
{
@@ -528,14 +529,14 @@ do_readcert (app_t app, const char *certid,
/* Read the entire file. fixme: This could be optimized by first
reading the header to figure out how long the certificate
actually is. */
- err = iso7816_select_file (app->slot, fid, 0);
+ err = iso7816_select_file (app_get_slot (app), fid, 0);
if (err)
{
log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
return err;
}
- err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
+ err = iso7816_read_binary (app_get_slot (app), 0, 0, &buffer, &buflen);
if (err)
{
log_error ("error reading certificate from FID 0x%04X: %s\n",
@@ -618,7 +619,8 @@ do_readcert (app_t app, const char *certid,
certificate parsing code in commands.c:cmd_readkey. For internal
use PK and PKLEN may be NULL to just check for an existing key. */
static gpg_error_t
-do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
+do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags,
+ unsigned char **pk, size_t *pklen)
{
gpg_error_t err;
unsigned char *buffer[2];
@@ -632,13 +634,14 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
/* Access the KEYD file which is always in the master directory. */
- err = iso7816_select_path (app->slot, path, DIM (path));
+ err = iso7816_select_path (app_get_slot (app), path, DIM (path));
if (err)
return err;
/* Due to the above select we need to re-select our application. */
app->app_local->need_app_select = 1;
/* Get the two records. */
- err = iso7816_read_record (app->slot, 5, 1, 0, &buffer[0], &buflen[0]);
+ err = iso7816_read_record (app_get_slot (app), 5, 1, 0,
+ &buffer[0], &buflen[0]);
if (err)
return err;
if (all_zero_p (buffer[0], buflen[0]))
@@ -646,13 +649,22 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
xfree (buffer[0]);
return gpg_error (GPG_ERR_NOT_FOUND);
}
- err = iso7816_read_record (app->slot, 6, 1, 0, &buffer[1], &buflen[1]);
+ err = iso7816_read_record (app_get_slot (app), 6, 1, 0,
+ &buffer[1], &buflen[1]);
if (err)
{
xfree (buffer[0]);
return err;
}
+ if ((flags & APP_READKEY_FLAG_INFO))
+ {
+ /* Not yet implemented but we won't get here for any regular
+ * keyrefs anyway, thus the top layer will provide the
+ * keypairinfo from the certificate. */
+ (void)ctrl;
+ }
+
if (pk && pklen)
{
*pk = make_canon_sexp_from_rsa_pk (buffer[0], buflen[0],
@@ -698,7 +710,7 @@ do_writekey (app_t app, ctrl_t ctrl,
else
return gpg_error (GPG_ERR_INV_ID);
- if (!force && !do_readkey (app, keyid, NULL, NULL))
+ if (!force && !do_readkey (app, ctrl, keyid, 0, NULL, NULL))
return gpg_error (GPG_ERR_EEXIST);
/* Parse the S-expression. */
@@ -751,7 +763,7 @@ do_writekey (app_t app, ctrl_t ctrl,
/* mse[10] = 0x82; /\* RSA public exponent of up to 4 bytes. *\/ */
/* mse[12] = rsa_e_len; */
/* memcpy (mse+12, rsa_e, rsa_e_len); */
-/* err = iso7816_manage_security_env (app->slot, 0x81, 0xB6, */
+/* err = iso7816_manage_security_env (app_get_slot (app), 0x81, 0xB6, */
/* mse, sizeof mse); */
leave:
@@ -794,7 +806,7 @@ verify_pin (app_t app, int pwid, const char *desc,
pininfo.maxlen = 16;
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) )
+ && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) )
{
rc = pincb (pincb_arg, desc, NULL);
if (rc)
@@ -804,7 +816,7 @@ verify_pin (app_t app, int pwid, const char *desc,
return rc;
}
- rc = iso7816_verify_kp (app->slot, pwid, &pininfo);
+ rc = iso7816_verify_kp (app_get_slot (app), pwid, &pininfo);
pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
}
else
@@ -825,7 +837,8 @@ verify_pin (app_t app, int pwid, const char *desc,
return rc;
}
- rc = iso7816_verify (app->slot, pwid, pinvalue, strlen (pinvalue));
+ rc = iso7816_verify (app_get_slot (app), pwid,
+ pinvalue, strlen (pinvalue));
xfree (pinvalue);
}
@@ -963,7 +976,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
mse[3] = 0x84; /* Private key reference. */
mse[4] = 1;
mse[5] = kid;
- rc = iso7816_manage_security_env (app->slot, 0x41, 0xB6,
+ rc = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB6,
mse, sizeof mse);
}
/* Verify using PW1.CH. */
@@ -971,7 +984,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
rc = verify_pin (app, 0, NULL, pincb, pincb_arg);
/* Compute the signature. */
if (!rc)
- rc = iso7816_compute_ds (app->slot, 0, data, datalen, 0,
+ rc = iso7816_compute_ds (app_get_slot (app), 0, data, datalen, 0,
outdata, outdatalen);
return rc;
}
@@ -1038,7 +1051,7 @@ do_decipher (app_t app, const char *keyidstr,
mse[3] = 0x84; /* Private key reference. */
mse[4] = 1;
mse[5] = kid;
- rc = iso7816_manage_security_env (app->slot, 0x41, 0xB8,
+ rc = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xB8,
mse, sizeof mse);
}
else
@@ -1048,7 +1061,7 @@ do_decipher (app_t app, const char *keyidstr,
0x80, 1, 0x10, /* Select algorithm RSA. */
0x84, 1, 0x81 /* Select local secret key 1 for decryption. */
};
- rc = iso7816_manage_security_env (app->slot, 0xC1, 0xB8,
+ rc = iso7816_manage_security_env (app_get_slot (app), 0xC1, 0xB8,
mse, sizeof mse);
}
@@ -1059,7 +1072,8 @@ do_decipher (app_t app, const char *keyidstr,
/* Note that we need to use extended length APDUs for TCOS 3 cards.
Command chaining does not work. */
if (!rc)
- rc = iso7816_decipher (app->slot, app->app_local->nks_version > 2? 1:0,
+ rc = iso7816_decipher (app_get_slot (app),
+ app->app_local->nks_version > 2? 1:0,
indata, indatalen, 0, 0x81,
outdata, outdatalen);
return rc;
@@ -1251,13 +1265,13 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *pwidstr,
}
memcpy (data, oldpin, oldpinlen);
memcpy (data+oldpinlen, newpin, newpinlen);
- err = iso7816_reset_retry_counter_with_rc (app->slot, pwid,
+ err = iso7816_reset_retry_counter_with_rc (app_get_slot (app), pwid,
data, datalen);
wipememory (data, datalen);
xfree (data);
}
else
- err = iso7816_change_reference_data (app->slot, pwid,
+ err = iso7816_change_reference_data (app_get_slot (app), pwid,
oldpin, oldpinlen,
newpin, newpinlen);
leave:
@@ -1338,9 +1352,11 @@ switch_application (app_t app, int enable_sigg)
log_info ("app-nks: switching to %s\n", enable_sigg? "SigG":"NKS");
if (enable_sigg)
- err = iso7816_select_application (app->slot, aid_sigg, sizeof aid_sigg, 0);
+ err = iso7816_select_application (app_get_slot (app),
+ aid_sigg, sizeof aid_sigg, 0);
else
- err = iso7816_select_application (app->slot, aid_nks, sizeof aid_nks, 0);
+ err = iso7816_select_application (app_get_slot (app),
+ aid_nks, sizeof aid_nks, 0);
if (!err && enable_sigg && app->app_local->nks_version >= 3
&& !app->app_local->sigg_msig_checked)
@@ -1353,9 +1369,10 @@ switch_application (app_t app, int enable_sigg)
app->app_local->sigg_msig_checked = 1;
app->app_local->sigg_is_msig = 1;
- err = iso7816_select_file (app->slot, 0x5349, 0);
+ err = iso7816_select_file (app_get_slot (app), 0x5349, 0);
if (!err)
- err = iso7816_read_record (app->slot, 1, 1, 0, &buffer, &buflen);
+ err = iso7816_read_record (app_get_slot (app), 1, 1, 0,
+ &buffer, &buflen);
if (!err)
{
tmpl = find_tlv (buffer, buflen, 0x7a, &tmpllen);
@@ -1387,13 +1404,13 @@ switch_application (app_t app, int enable_sigg)
gpg_error_t
app_select_nks (app_t app)
{
- int slot = app->slot;
+ int slot = app_get_slot (app);
int rc;
rc = iso7816_select_application (slot, aid_nks, sizeof aid_nks, 0);
if (!rc)
{
- app->apptype = "NKS";
+ app->apptype = APPTYPE_NKS;
app->app_local = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
@@ -1407,6 +1424,7 @@ app_select_nks (app_t app)
log_info ("Detected NKS version: %d\n", app->app_local->nks_version);
app->fnc.deinit = do_deinit;
+ app->fnc.reselect = NULL;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.readkey = do_readkey;
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 1e904b578..767f29d26 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -50,27 +50,20 @@
#include <assert.h>
#include <time.h>
-#if GNUPG_MAJOR_VERSION == 1
-/* This is used with GnuPG version < 1.9. The code has been source
- copied from the current GnuPG >= 1.9 and is maintained over
- there. */
-#include "options.h"
-#include "errors.h"
-#include "memory.h"
-#include "cardglue.h"
-#else /* GNUPG_MAJOR_VERSION != 1 */
#include "scdaemon.h"
-#endif /* GNUPG_MAJOR_VERSION != 1 */
-
#include "../common/util.h"
#include "../common/i18n.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
#include "../common/host2net.h"
#include "../common/openpgpdefs.h"
+
+/* The AID of this application. */
+static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
+
+
/* A table describing the DOs of the card. */
static struct {
int tag;
@@ -176,6 +169,7 @@ struct app_local_s {
is usually only required for cross checks
because the length of an S-expression is
implicitly available. */
+ unsigned char keygrip_str[41]; /* The keygrip, null terminated */
} pk[3];
unsigned char status_indicator; /* The card status indicator. */
@@ -348,7 +342,7 @@ get_cached_data (app_t app, int tag,
else
exmode = 0;
- err = iso7816_get_data (app->slot, exmode, tag, &p, &len);
+ err = iso7816_get_data (app_get_slot (app), exmode, tag, &p, &len);
if (err)
return err;
if (len)
@@ -479,7 +473,7 @@ get_one_do (app_t app, int tag, unsigned char **result, size_t *nbytes,
if (app->appversion > 0x0100 && data_objects[i].get_immediate_in_v11)
{
exmode = 0;
- rc = iso7816_get_data (app->slot, exmode, tag, &buffer, &buflen);
+ rc = iso7816_get_data (app_get_slot (app), exmode, tag, &buffer, &buflen);
if (rc)
{
*r_rc = rc;
@@ -821,7 +815,7 @@ store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr,
tag2 = 0xCE + keynumber;
flush_cache_item (app, 0xCD);
- rc = iso7816_put_data (app->slot, 0, tag, fpr, 20);
+ rc = iso7816_put_data (app_get_slot (app), 0, tag, fpr, 20);
if (rc)
log_error (_("failed to store the fingerprint: %s\n"),gpg_strerror (rc));
@@ -834,7 +828,7 @@ store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr,
buf[2] = timestamp >> 8;
buf[3] = timestamp;
- rc = iso7816_put_data (app->slot, 0, tag2, buf, 4);
+ rc = iso7816_put_data (app_get_slot (app), 0, tag2, buf, 4);
if (rc)
log_error (_("failed to store the creation date: %s\n"),
gpg_strerror (rc));
@@ -987,6 +981,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
{ "PRIVATE-DO-3", 0x0103 },
{ "PRIVATE-DO-4", 0x0104 },
{ "$AUTHKEYID", 0x0000, -3 },
+ { "$ENCRKEYID", 0x0000, -6 },
+ { "$SIGNKEYID", 0x0000, -7 },
{ "$DISPSERIALNO",0x0000, -4 },
{ "UIF-1", 0x00D6, 0 },
{ "UIF-2", 0x00D7, 0 },
@@ -1071,6 +1067,18 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
send_key_attr (ctrl, app, table[idx].name, i);
return 0;
}
+ if (table[idx].special == -6)
+ {
+ char const tmp[] = "OPENPGP.2";
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ return 0;
+ }
+ if (table[idx].special == -7)
+ {
+ char const tmp[] = "OPENPGP.1";
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ return 0;
+ }
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &rc);
if (relptr)
@@ -1214,7 +1222,6 @@ get_remaining_tries (app_t app, int adminpw)
the according hex representation to FPR. Caller must have provide
a buffer at FPR of least 41 bytes. Returns 0 on success or an
error code. */
-#if GNUPG_MAJOR_VERSION > 1
static gpg_error_t
retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
{
@@ -1233,7 +1240,6 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
xfree (relptr);
return err;
}
-#endif /*GNUPG_MAJOR_VERSION > 1*/
/* Retrieve the public key material for the RSA key, whose fingerprint
@@ -1242,7 +1248,6 @@ retrieve_fpr_from_card (app_t app, int keyno, char *fpr)
public exponent at E and ELEN. Returns zero on success, an error
code on failure. Caller must release the allocated buffers at M
and E if the function returns success. */
-#if GNUPG_MAJOR_VERSION > 1
static gpg_error_t
retrieve_key_material (FILE *fp, const char *hexkeyid,
const unsigned char **m, size_t *mlen,
@@ -1347,7 +1352,6 @@ retrieve_key_material (FILE *fp, const char *hexkeyid,
xfree (line);
return err;
}
-#endif /*GNUPG_MAJOR_VERSION > 1*/
static gpg_error_t
@@ -1561,6 +1565,23 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
}
+static gpg_error_t
+store_keygrip (app_t app, int keyno)
+{
+ gpg_error_t err;
+ unsigned char grip[20];
+
+ err = keygrip_from_canon_sexp (app->app_local->pk[keyno].key,
+ app->app_local->pk[keyno].keylen,
+ grip);
+ if (err)
+ return err;
+
+ bin2hex (grip, 20, app->app_local->pk[keyno].keygrip_str);
+ return 0;
+}
+
+
/* Parse tag-length-value data for public key in BUFFER of BUFLEN
length. Key of KEYNO in APP is updated with an S-expression of
public key. When CTRL is not NULL, fingerprint is computed with
@@ -1612,6 +1633,8 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
app->app_local->pk[keyno].key = keybuf;
/* Decrement for trailing '\0' */
app->app_local->pk[keyno].keylen = len - 1;
+
+ err = store_keygrip (app, keyno);
}
return err;
@@ -1628,7 +1651,6 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
consuming to send it just for the fun of it. However, given that we
use the same code in gpg 1.4, we can't use the gcry S-expression
here but need to open encode it. */
-#if GNUPG_MAJOR_VERSION > 1
static gpg_error_t
get_public_key (app_t app, int keyno)
{
@@ -1673,7 +1695,7 @@ get_public_key (app_t app, int keyno)
le_value = 256; /* Use legacy value. */
}
- err = iso7816_read_public_key (app->slot, exmode,
+ err = iso7816_read_public_key (app_get_slot (app), exmode,
(keyno == 0? "\xB6" :
keyno == 1? "\xB8" : "\xA4"),
2, le_value, &buffer, &buflen);
@@ -1713,7 +1735,8 @@ get_public_key (app_t app, int keyno)
hexkeyid = fpr + 24;
ret = gpgrt_asprintf
- (&command, "gpg --list-keys --with-colons --with-key-data '%s'", fpr);
+ (&command, "%s --list-keys --with-colons --with-key-data '%s'",
+ gnupg_module_name (GNUPG_MODULE_NAME_GPG), fpr);
if (ret < 0)
{
err = gpg_error_from_syserror ();
@@ -1759,17 +1782,17 @@ get_public_key (app_t app, int keyno)
app->app_local->pk[keyno].key = (unsigned char*)keybuf;
/* Decrement for trailing '\0' */
app->app_local->pk[keyno].keylen = len - 1;
+ err = store_keygrip (app, keyno);
}
leave:
/* Set a flag to indicate that we tried to read the key. */
- app->app_local->pk[keyno].read_done = 1;
+ if (!err)
+ app->app_local->pk[keyno].read_done = 1;
xfree (buffer);
return err;
}
-#endif /* GNUPG_MAJOR_VERSION > 1 */
-
/* Send the KEYPAIRINFO back. KEY needs to be in the range [1,3].
@@ -1779,11 +1802,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key)
{
int keyno = key - 1;
gpg_error_t err = 0;
- /* Note that GnuPG 1.x does not need this and it would be too time
- consuming to send it just for the fun of it. */
-#if GNUPG_MAJOR_VERSION > 1
- unsigned char grip[20];
- char gripstr[41];
char idbuf[50];
const char *usage;
@@ -1795,14 +1813,6 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key)
if (!app->app_local->pk[keyno].key)
goto leave; /* No such key - ignore. */
- err = keygrip_from_canon_sexp (app->app_local->pk[keyno].key,
- app->app_local->pk[keyno].keylen,
- grip);
- if (err)
- goto leave;
-
- bin2hex (grip, 20, gripstr);
-
switch (keyno)
{
case 0: usage = "sc"; break;
@@ -1813,14 +1823,12 @@ send_keypair_info (app_t app, ctrl_t ctrl, int key)
sprintf (idbuf, "OPENPGP.%d", keyno+1);
send_status_info (ctrl, "KEYPAIRINFO",
- gripstr, 40,
+ app->app_local->pk[keyno].keygrip_str, 40,
idbuf, strlen (idbuf),
usage, strlen (usage),
NULL, (size_t)0);
leave:
-#endif /* GNUPG_MAJOR_VERSION > 1 */
-
return err;
}
@@ -1875,7 +1883,8 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
buffer. On error PK and PKLEN are not changed and an error code is
returned. */
static gpg_error_t
-do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
+do_readkey (app_t app, ctrl_t ctrl, const char *keyid, unsigned int flags,
+ unsigned char **pk, size_t *pklen)
{
gpg_error_t err;
int keyno;
@@ -1898,15 +1907,25 @@ do_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
if (!buf)
return gpg_error (GPG_ERR_NO_PUBKEY);
- *pklen = app->app_local->pk[keyno].keylen;
- *pk = xtrymalloc (*pklen);
- if (!*pk)
+ if ((flags & APP_READKEY_FLAG_INFO))
{
- err = gpg_error_from_syserror ();
- *pklen = 0;
- return err;
+ err = send_keypair_info (app, ctrl, keyno+1);
+ if (err)
+ return err;
+ }
+
+ if (pk && pklen)
+ {
+ *pklen = app->app_local->pk[keyno].keylen;
+ *pk = xtrymalloc (*pklen);
+ if (!*pk)
+ {
+ err = gpg_error_from_syserror ();
+ *pklen = 0;
+ return err;
+ }
+ memcpy (*pk, buf, *pklen);
}
- memcpy (*pk, buf, *pklen);
return 0;
}
@@ -1919,7 +1938,6 @@ static gpg_error_t
do_readcert (app_t app, const char *certid,
unsigned char **cert, size_t *certlen)
{
-#if GNUPG_MAJOR_VERSION > 1
gpg_error_t err;
unsigned char *buffer;
size_t buflen;
@@ -1948,9 +1966,6 @@ do_readcert (app_t app, const char *certid,
}
xfree (relptr);
return err;
-#else
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-#endif
}
@@ -2150,7 +2165,7 @@ verify_a_chv (app_t app,
/* Special case for def_chv2 mechanism. */
if (opt.verbose)
log_info (_("using default PIN as %s\n"), "CHV2");
- rc = iso7816_verify (app->slot, 0x82, "123456", 6);
+ rc = iso7816_verify (app_get_slot (app), 0x82, "123456", 6);
if (rc)
{
/* Verification of CHV2 with the default PIN failed,
@@ -2183,7 +2198,7 @@ verify_a_chv (app_t app,
}
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
+ && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo)
&& !check_pinpad_request (app, &pininfo, 0))
{
/* The reader supports the verify command through the pinpad.
@@ -2199,7 +2214,7 @@ verify_a_chv (app_t app,
gpg_strerror (rc));
return rc;
}
- rc = iso7816_verify_kp (app->slot, 0x80+chvno, &pininfo);
+ rc = iso7816_verify_kp (app_get_slot (app), 0x80+chvno, &pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
@@ -2230,7 +2245,8 @@ verify_a_chv (app_t app,
rc = pin2hash_if_kdf (app, chvno, *pinvalue, pinlen);
if (!rc)
- rc = iso7816_verify (app->slot, 0x80+chvno, *pinvalue, *pinlen);
+ rc = iso7816_verify (app_get_slot (app),
+ 0x80 + chvno, *pinvalue, *pinlen);
}
if (rc)
@@ -2270,7 +2286,7 @@ verify_chv2 (app_t app,
the card is not configured to require a verification before
each CHV1 controlled operation (force_chv1) and if we are not
using the pinpad (PINVALUE == NULL). */
- rc = iso7816_verify (app->slot, 0x81, pinvalue, pinlen);
+ rc = iso7816_verify (app_get_slot (app), 0x81, pinvalue, pinlen);
if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
if (rc)
@@ -2337,13 +2353,11 @@ verify_chv3 (app_t app,
{
int rc = 0;
-#if GNUPG_MAJOR_VERSION != 1
if (!opt.allow_admin)
{
log_info (_("access to admin commands is not configured\n"));
return gpg_error (GPG_ERR_EACCES);
}
-#endif
if (!app->did_chv3)
{
@@ -2360,7 +2374,8 @@ verify_chv3 (app_t app,
return rc;
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
+ && !iso7816_check_pinpad (app_get_slot (app),
+ ISO7816_VERIFY, &pininfo)
&& !check_pinpad_request (app, &pininfo, 1))
{
/* The reader supports the verify command through the pinpad. */
@@ -2373,7 +2388,7 @@ verify_chv3 (app_t app,
gpg_strerror (rc));
return rc;
}
- rc = iso7816_verify_kp (app->slot, 0x83, &pininfo);
+ rc = iso7816_verify_kp (app_get_slot (app), 0x83, &pininfo);
/* Dismiss the prompt. */
pincb (pincb_arg, NULL, NULL);
}
@@ -2402,7 +2417,7 @@ verify_chv3 (app_t app,
rc = pin2hash_if_kdf (app, 3, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_verify (app->slot, 0x83, pinvalue, pinlen);
+ rc = iso7816_verify (app_get_slot (app), 0x83, pinvalue, pinlen);
xfree (pinvalue);
}
@@ -2501,7 +2516,8 @@ do_setattr (app_t app, const char *name,
exmode = -254; /* Command chaining with max. 254 bytes. */
else
exmode = 0;
- rc = iso7816_put_data (app->slot, exmode, table[idx].tag, value, valuelen);
+ rc = iso7816_put_data (app_get_slot (app),
+ exmode, table[idx].tag, value, valuelen);
if (rc)
log_error ("failed to set '%s': %s\n", table[idx].name, gpg_strerror (rc));
@@ -2532,7 +2548,6 @@ do_writecert (app_t app, ctrl_t ctrl,
const unsigned char *certdata, size_t certdatalen)
{
(void)ctrl;
-#if GNUPG_MAJOR_VERSION > 1
if (strcmp (certidstr, "OPENPGP.3"))
return gpg_error (GPG_ERR_INV_ID);
if (!certdata || !certdatalen)
@@ -2542,9 +2557,6 @@ do_writecert (app_t app, ctrl_t ctrl,
if (certdatalen > app->app_local->extcap.max_certlen_3)
return gpg_error (GPG_ERR_TOO_LARGE);
return do_setattr (app, "CERT-3", pincb, pincb_arg, certdata, certdatalen);
-#else
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
-#endif
}
@@ -2562,7 +2574,7 @@ clear_chv_status (app_t app, int chvno)
apdu[2] = 0xff;
apdu[3] = 0x80+chvno;
- err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL);
+ err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, NULL, NULL, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_INV_VALUE)
@@ -2573,7 +2585,8 @@ clear_chv_status (app_t app, int chvno)
if (chvno == 1)
{
apdu[3]++;
- err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL);
+ err = iso7816_apdu_direct (app_get_slot (app),
+ apdu, 4, 0, NULL, NULL, NULL);
app->did_chv1 = app->did_chv2 = 0;
}
else if (chvno == 2)
@@ -2684,7 +2697,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
/* Version 2 cards. */
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot,
+ && !iso7816_check_pinpad (app_get_slot (app),
ISO7816_CHANGE_REFERENCE_DATA, &pininfo)
&& !check_pinpad_request (app, &pininfo, chvno == 3))
use_pinpad = 1;
@@ -2827,7 +2840,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
rc = pin2hash_if_kdf (app, 0, buffer+pinlen0, &pinlen);
}
if (!rc)
- rc = iso7816_reset_retry_counter_with_rc (app->slot, 0x81,
+ rc = iso7816_reset_retry_counter_with_rc (app_get_slot (app), 0x81,
buffer, pinlen0+pinlen);
wipememory (buffer, pinlen0 + pinlen);
xfree (buffer);
@@ -2844,31 +2857,37 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
{
rc = pin2hash_if_kdf (app, 0, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_put_data (app->slot, 0, 0xD3, pinvalue, pinlen);
+ rc = iso7816_put_data (app_get_slot (app),
+ 0, 0xD3, pinvalue, pinlen);
}
}
else if (reset_mode)
{
rc = pin2hash_if_kdf (app, 1, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_reset_retry_counter (app->slot, 0x81, pinvalue, pinlen);
+ rc = iso7816_reset_retry_counter (app_get_slot (app),
+ 0x81, pinvalue, pinlen);
if (!rc && !app->app_local->extcap.is_v2)
- rc = iso7816_reset_retry_counter (app->slot, 0x82, pinvalue, pinlen);
+ rc = iso7816_reset_retry_counter (app_get_slot (app),
+ 0x82, pinvalue, pinlen);
}
else if (!app->app_local->extcap.is_v2)
{
/* Version 1 cards. */
if (chvno == 1 || chvno == 2)
{
- rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x81, NULL, 0,
pinvalue, strlen (pinvalue));
if (!rc)
- rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x82, NULL, 0,
pinvalue, strlen (pinvalue));
}
else /* CHVNO == 3 */
{
- rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x80 + chvno, NULL, 0,
pinvalue, strlen (pinvalue));
}
}
@@ -2889,7 +2908,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
gpg_strerror (rc));
goto leave;
}
- rc = iso7816_change_reference_data_kp (app->slot, 0x80 + chvno, 0,
+ rc = iso7816_change_reference_data_kp (app_get_slot (app),
+ 0x80 + chvno, 0,
&pininfo);
pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
}
@@ -2899,7 +2919,8 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
if (!rc)
rc = pin2hash_if_kdf (app, chvno, pinvalue, &pinlen);
if (!rc)
- rc = iso7816_change_reference_data (app->slot, 0x80 + chvno,
+ rc = iso7816_change_reference_data (app_get_slot (app),
+ 0x80 + chvno,
oldpinvalue, pinlen0,
pinvalue, pinlen);
}
@@ -2942,7 +2963,7 @@ does_key_exist (app_t app, int keyidx, int generating, int force)
assert (keyidx >=0 && keyidx <= 2);
- if (iso7816_get_data (app->slot, 0, 0x006E, &buffer, &buflen))
+ if (iso7816_get_data (app_get_slot (app), 0, 0x006E, &buffer, &buflen))
{
log_error (_("error reading application data\n"));
return gpg_error (GPG_ERR_GENERAL);
@@ -3256,7 +3277,7 @@ change_keyattr (app_t app, int keyno, const unsigned char *buf, size_t buflen,
return err;
/* Change the attribute. */
- err = iso7816_put_data (app->slot, 0, 0xC1+keyno, buf, buflen);
+ err = iso7816_put_data (app_get_slot (app), 0, 0xC1+keyno, buf, buflen);
if (err)
log_error ("error changing key attribute (key=%d)\n", keyno+1);
else
@@ -3648,7 +3669,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
exmode = -254;
else
exmode = 0;
- err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
+ err = iso7816_put_data_odd (app_get_slot (app), exmode, 0x3fff,
template, template_len);
}
else
@@ -3698,7 +3719,7 @@ rsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
goto leave;
/* Store the key. */
- err = iso7816_put_data (app->slot, 0,
+ err = iso7816_put_data (app_get_slot (app), 0,
(app->appversion > 0x0007? 0xE0:0xE9)+keyno,
template, template_len);
}
@@ -3970,7 +3991,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
exmode = -254;
else
exmode = 0;
- err = iso7816_put_data_odd (app->slot, exmode, 0x3fff,
+ err = iso7816_put_data_odd (app_get_slot (app), exmode, 0x3fff,
template, template_len);
xfree (template);
}
@@ -4138,7 +4159,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, const char *keytype,
log_info (_("please wait while key is being generated ...\n"));
start_at = time (NULL);
- err = iso7816_generate_keypair (app->slot, exmode, 0x80, 0,
+ err = iso7816_generate_keypair (app_get_slot (app), exmode, 0x80, 0,
(keyno == 0? "\xB6" :
keyno == 1? "\xB8" : "\xA4"),
2, le_value, &buffer, &buflen);
@@ -4269,6 +4290,74 @@ check_against_given_fingerprint (app_t app, const char *fpr, int key)
}
+/* Check KEYIDSTR, if it's valid.
+ When KEYNO is 0, it means it's for PIN check.
+ Otherwise, KEYNO corresponds to the slot (signing, decipher and auth).
+ KEYIDSTR is either:
+ (1) Serial number
+ (2) Serial number "/" fingerprint
+ (3) keygrip
+
+ When KEYNO is 0 and KEYIDSTR is for a keygrip, the keygrip should
+ be to be compared is the first one (keygrip for signing).
+ */
+static int
+check_keyidstr (app_t app, const char *keyidstr, int keyno)
+{
+ int rc;
+ const char *s;
+ int n;
+ const char *fpr = NULL;
+ unsigned char tmp_sn[20]; /* Actually 16 bytes but also for the fpr. */
+
+ if (strlen (keyidstr) < 32)
+ return gpg_error (GPG_ERR_INV_ID);
+ else
+ {
+ for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
+ ;
+
+ /* Check if it's a keygrip */
+ if (n == 40)
+ {
+ const unsigned char *keygrip_str;
+
+ keygrip_str = app->app_local->pk[keyno?keyno-1:0].keygrip_str;
+ if (!strncmp (keygrip_str, keyidstr, 40))
+ return 0;
+ else
+ return gpg_error (GPG_ERR_INV_ID);
+ }
+
+ if (n != 32 || strncmp (keyidstr, "D27600012401", 12))
+ return gpg_error (GPG_ERR_INV_ID);
+ else if (!*s)
+ ; /* no fingerprint given: we allow this for now. */
+ else if (*s == '/')
+ fpr = s + 1;
+ else
+ return gpg_error (GPG_ERR_INV_ID);
+
+ for (s=keyidstr, n=0; n < 16; s += 2, n++)
+ tmp_sn[n] = xtoi_2 (s);
+
+ if (app->card->serialnolen != 16)
+ return gpg_error (GPG_ERR_INV_CARD);
+ if (memcmp (app->card->serialno, tmp_sn, 16))
+ return gpg_error (GPG_ERR_WRONG_CARD);
+ }
+
+ /* If a fingerprint has been specified check it against the one on
+ the card. This is allows for a meaningful error message in case
+ the key on the card has been replaced but the shadow information
+ known to gpg was not updated. If there is no fingerprint, gpg
+ will detect a bogus signature anyway due to the
+ verify-after-signing feature. */
+ rc = (fpr&&keyno)? check_against_given_fingerprint (app, fpr, keyno) : 0;
+
+ return rc;
+}
+
/* Compute a digital signature on INDATA which is expected to be the
raw message digest. For this application the KEYIDSTR consists of
@@ -4314,10 +4403,6 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
int rc;
unsigned char data[19+64];
size_t datalen;
- unsigned char tmp_sn[20]; /* Actually 16 bytes but also for the fpr. */
- const char *s;
- int n;
- const char *fpr = NULL;
unsigned long sigcount;
int use_auth = 0;
int exmode, le_value;
@@ -4362,40 +4447,13 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
;
else if (!strcmp (keyidstr, "OPENPGP.3"))
use_auth = 1;
- else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
else
{
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
+ rc = check_keyidstr (app, keyidstr, 1);
+ if (rc)
+ return rc;
}
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, gpg
- will detect a bogus signature anyway due to the
- verify-after-signing feature. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0;
- if (rc)
- return rc;
-
/* Concatenate prefix and digest. */
#define X(a,b,d) \
if (hashalgo == GCRY_MD_ ## a && (d) ) \
@@ -4443,7 +4501,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
char *pinvalue;
int pinlen;
- rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount, &pinvalue, &pinlen);
+ rc = verify_a_chv (app, pincb, pincb_arg, 1, sigcount,
+ &pinvalue, &pinlen);
if (rc)
return rc;
@@ -4456,7 +4515,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
pinpad has been used. */
if (!app->did_chv2 && pinvalue && !app->app_local->extcap.is_v2)
{
- rc = iso7816_verify (app->slot, 0x82, pinvalue, pinlen);
+ rc = iso7816_verify (app_get_slot (app), 0x82, pinvalue, pinlen);
if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
if (rc)
@@ -4484,7 +4543,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
exmode = 0;
le_value = 0;
}
- rc = iso7816_compute_ds (app->slot, exmode, data, datalen, le_value,
+ rc = iso7816_compute_ds (app_get_slot (app), exmode, data, datalen, le_value,
outdata, outdatalen);
if (gpg_err_code (rc) == GPG_ERR_TIMEOUT)
clear_chv_status (app, 1);
@@ -4512,10 +4571,6 @@ do_auth (app_t app, const char *keyidstr,
unsigned char **outdata, size_t *outdatalen )
{
int rc;
- unsigned char tmp_sn[20]; /* Actually 16 but we use it also for the fpr. */
- const char *s;
- int n;
- const char *fpr = NULL;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -4543,40 +4598,13 @@ do_auth (app_t app, const char *keyidstr,
/* Check whether an OpenPGP card of any version has been requested. */
if (!strcmp (keyidstr, "OPENPGP.3"))
;
- else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
else
{
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
+ rc = check_keyidstr (app, keyidstr, 3);
+ if (rc)
+ return rc;
}
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, gpg
- will detect a bogus signature anyway due to the
- verify-after-signing feature. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0;
- if (rc)
- return rc;
-
rc = verify_chv2 (app, pincb, pincb_arg);
if (!rc)
{
@@ -4594,7 +4622,7 @@ do_auth (app_t app, const char *keyidstr,
exmode = 0;
le_value = 0;
}
- rc = iso7816_internal_authenticate (app->slot, exmode,
+ rc = iso7816_internal_authenticate (app_get_slot (app), exmode,
indata, indatalen, le_value,
outdata, outdatalen);
if (gpg_err_code (rc) == GPG_ERR_TIMEOUT)
@@ -4612,11 +4640,8 @@ do_decipher (app_t app, const char *keyidstr,
unsigned char **outdata, size_t *outdatalen,
unsigned int *r_info)
{
- int rc;
- unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */
- const char *s;
int n;
- const char *fpr = NULL;
+ int rc;
int exmode, le_value;
unsigned char *fixbuf = NULL;
int padind = 0;
@@ -4628,39 +4653,13 @@ do_decipher (app_t app, const char *keyidstr,
/* Check whether an OpenPGP card of any version has been requested. */
if (!strcmp (keyidstr, "OPENPGP.2"))
;
- else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
else
{
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
+ rc = check_keyidstr (app, keyidstr, 2);
+ if (rc)
+ return rc;
}
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, the
- decryption won't produce the right plaintext anyway. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0;
- if (rc)
- return rc;
-
rc = verify_chv2 (app, pincb, pincb_arg);
if (rc)
return rc;
@@ -4818,7 +4817,7 @@ do_decipher (app_t app, const char *keyidstr,
else
exmode = le_value = 0;
- rc = iso7816_decipher (app->slot, exmode,
+ rc = iso7816_decipher (app_get_slot (app), exmode,
indata, indatalen, le_value, padind,
outdata, outdatalen);
xfree (fixbuf);
@@ -4876,38 +4875,19 @@ do_check_pin (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
- unsigned char tmp_sn[20];
- const char *s;
- int n;
int admin_pin = 0;
+ int rc;
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
- /* Check whether an OpenPGP card of any version has been requested. */
- if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
+ rc = check_keyidstr (app, keyidstr, 0);
+ if (rc)
+ return rc;
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* No fingerprint given: we allow this for now. */
- else if (*s == '/')
- ; /* We ignore a fingerprint. */
- else if (!strcmp (s, "[CHV3]") )
+ if ((strlen (keyidstr) >= 32+6 && !strcmp (keyidstr+32, "[CHV3]"))
+ || (strlen (keyidstr) >= 40+6 && !strcmp (keyidstr+40, "[CHV3]")))
admin_pin = 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
/* Yes, there is a race conditions: The user might pull the card
right here and we won't notice that. However this is not a
@@ -4950,6 +4930,65 @@ do_check_pin (app_t app, const char *keyidstr,
return verify_chv2 (app, pincb, pincb_arg);
}
+static gpg_error_t
+do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str)
+{
+ int i;
+
+ /* Make sure we have load the public keys. */
+ for (i = 0; i < 3; i++)
+ get_public_key (app, i);
+
+ if (action == KEYGRIP_ACTION_LOOKUP)
+ {
+ if (keygrip_str == NULL)
+ return gpg_error (GPG_ERR_NOT_FOUND);
+
+ for (i = 0; i < 3; i++)
+ if (app->app_local->pk[i].read_done
+ && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str))
+ return 0; /* Found */
+ }
+ else
+ {
+ char idbuf[50];
+ char buf[65];
+ int data = (action == KEYGRIP_ACTION_SEND_DATA);
+
+ if (DIM (buf) < 2 * app->card->serialnolen + 1)
+ return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
+
+ bin2hex (app->card->serialno, app->card->serialnolen, buf);
+
+ if (keygrip_str == NULL)
+ {
+ for (i = 0; i < 3; i++)
+ if (app->app_local->pk[i].read_done)
+ {
+ sprintf (idbuf, "OPENPGP.%d", i+1);
+ send_keyinfo (ctrl, data,
+ app->app_local->pk[i].keygrip_str,buf, idbuf);
+ }
+ /* Return an error so that the dispatcher keeps on looping
+ * over the other applications. Only for clarity we use a
+ * different error code than for the not_found case. */
+ return gpg_error (GPG_ERR_TRUE);
+ }
+ else
+ {
+ for (i = 0; i < 3; i++)
+ if (app->app_local->pk[i].read_done
+ && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str))
+ {
+ sprintf (idbuf, "OPENPGP.%d", i+1);
+ send_keyinfo (ctrl, data, keygrip_str, buf, idbuf);
+ return 0;
+ }
+ }
+ }
+
+ return gpg_error (GPG_ERR_NOT_FOUND);
+}
/* Show information about card capabilities. */
static void
@@ -5170,13 +5209,36 @@ parse_algorithm_attribute (app_t app, int keyno)
xfree (relptr);
}
+
+/* Reselect the application. This is used by cards which support
+ * on-the-fly switching between applications. */
+static gpg_error_t
+do_reselect (app_t app, ctrl_t ctrl)
+{
+ gpg_error_t err;
+
+ (void)ctrl;
+
+ /* An extra check which should not be necessary because the caller
+ * should have made sure that a re-select is only called for
+ * approriate cards. */
+ if (app->card->cardtype != CARDTYPE_YUBIKEY)
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ /* Note that the card can't cope with P2=0xCO, thus we need to pass
+ * a special flag value. */
+ err = iso7816_select_application (app_get_slot (app),
+ openpgp_aid, sizeof openpgp_aid, 0x0001);
+ return err;
+}
+
+
/* Select the OpenPGP application on the card in SLOT. This function
must be used before any other OpenPGP application functions. */
gpg_error_t
app_select_openpgp (app_t app)
{
- static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
- int slot = app->slot;
+ int slot = app_get_slot (app);
int rc;
unsigned char *buffer;
size_t buflen;
@@ -5184,12 +5246,13 @@ app_select_openpgp (app_t app)
/* Note that the card can't cope with P2=0xCO, thus we need to pass a
special flag value. */
- rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001);
+ rc = iso7816_select_application (slot,
+ openpgp_aid, sizeof openpgp_aid, 0x0001);
if (!rc)
{
unsigned int manufacturer;
- app->apptype = "OPENPGP";
+ app->apptype = APPTYPE_OPENPGP;
app->did_chv1 = 0;
app->did_chv2 = 0;
@@ -5214,9 +5277,9 @@ app_select_openpgp (app_t app)
app->appversion |= buffer[7];
manufacturer = (buffer[8]<<8 | buffer[9]);
- xfree (app->serialno);
- app->serialno = buffer;
- app->serialnolen = buflen;
+ xfree (app->card->serialno);
+ app->card->serialno = buffer;
+ app->card->serialnolen = buflen;
buffer = NULL;
app->app_local = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
@@ -5319,6 +5382,7 @@ app_select_openpgp (app_t app)
dump_all_do (slot);
app->fnc.deinit = do_deinit;
+ app->fnc.reselect = do_reselect;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.readkey = do_readkey;
@@ -5332,6 +5396,7 @@ app_select_openpgp (app_t app)
app->fnc.decipher = do_decipher;
app->fnc.change_pin = do_change_pin;
app->fnc.check_pin = do_check_pin;
+ app->fnc.with_keygrip = do_with_keygrip;
}
leave:
diff --git a/scd/app-p15.c b/scd/app-p15.c
index 190292433..ce82b34a9 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -38,7 +38,6 @@
#include "scdaemon.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
#include "apdu.h" /* fixme: we should move the card detection to a
separate file */
@@ -443,7 +442,7 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
if (app->app_local->direct_path_selection)
{
- err = iso7816_select_path (app->slot, path+1, pathlen-1);
+ err = iso7816_select_path (app_get_slot (app), path+1, pathlen-1);
if (err)
{
log_error ("error selecting path ");
@@ -461,7 +460,8 @@ select_ef_by_path (app_t app, const unsigned short *path, size_t pathlen)
supported by the card. */
for (i=0; i < pathlen; i++)
{
- err = iso7816_select_file (app->slot, path[i], !(i+1 == pathlen));
+ err = iso7816_select_file (app_get_slot (app),
+ path[i], !(i+1 == pathlen));
if (err)
{
log_error ("error selecting part %d from path ", i);
@@ -612,7 +612,8 @@ read_ef_odf (app_t app, unsigned short odf_fid)
unsigned short value;
size_t offset;
- err = select_and_read_binary (app->slot, odf_fid, "ODF", &buffer, &buflen);
+ err = select_and_read_binary (app_get_slot (app), odf_fid, "ODF",
+ &buffer, &buflen);
if (err)
return err;
@@ -826,7 +827,8 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No private keys. */
- err = select_and_read_binary (app->slot, fid, "PrKDF", &buffer, &buflen);
+ err = select_and_read_binary (app_get_slot (app), fid, "PrKDF",
+ &buffer, &buflen);
if (err)
return err;
@@ -1282,7 +1284,8 @@ read_ef_cdf (app_t app, unsigned short fid, cdf_object_t *result)
if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No certificates. */
- err = select_and_read_binary (app->slot, fid, "CDF", &buffer, &buflen);
+ err = select_and_read_binary (app_get_slot (app), fid, "CDF",
+ &buffer, &buflen);
if (err)
return err;
@@ -1555,7 +1558,8 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No authentication objects. */
- err = select_and_read_binary (app->slot, fid, "AODF", &buffer, &buflen);
+ err = select_and_read_binary (app_get_slot (app), fid, "AODF",
+ &buffer, &buflen);
if (err)
return err;
@@ -2216,7 +2220,7 @@ read_ef_tokeninfo (app_t app)
int class, tag, constructed, ndef;
unsigned long ul;
- err = select_and_read_binary (app->slot, 0x5032, "TokenInfo",
+ err = select_and_read_binary (app_get_slot (app), 0x5032, "TokenInfo",
&buffer, &buflen);
if (err)
return err;
@@ -2294,13 +2298,13 @@ read_p15_info (app_t app)
{
/* If we don't have a serial number yet but the TokenInfo provides
one, use that. */
- if (!app->serialno && app->app_local->serialno)
+ if (!app->card->serialno && app->app_local->serialno)
{
- app->serialno = app->app_local->serialno;
- app->serialnolen = app->app_local->serialnolen;
+ app->card->serialno = app->app_local->serialno;
+ app->card->serialnolen = app->app_local->serialnolen;
app->app_local->serialno = NULL;
app->app_local->serialnolen = 0;
- err = app_munge_serialno (app);
+ err = app_munge_serialno (app->card);
if (err)
return err;
}
@@ -2553,7 +2557,8 @@ readcert_by_cdf (app_t app, cdf_object_t cdf,
if (err)
goto leave;
- err = iso7816_read_binary (app->slot, cdf->off, cdf->len, &buffer, &buflen);
+ err = iso7816_read_binary (app_get_slot (app), cdf->off, cdf->len,
+ &buffer, &buflen);
if (!err && (!buflen || *buffer == 0xff))
err = gpg_error (GPG_ERR_NOT_FOUND);
if (err)
@@ -2713,7 +2718,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
err = select_ef_by_path (app, path, DIM(path) );
if (!err)
- err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
+ err = iso7816_read_binary (app_get_slot (app), 0, 0,
+ &buffer, &buflen);
if (err)
{
log_error ("error accessing EF(ID): %s\n", gpg_strerror (err));
@@ -2758,7 +2764,7 @@ micardo_mse (app_t app, unsigned short fid)
unsigned char msebuf[10];
/* Read the KeyD file containing extra information on keys. */
- err = iso7816_select_file (app->slot, 0x0013, 0);
+ err = iso7816_select_file (app_get_slot (app), 0x0013, 0);
if (err)
{
log_error ("error reading EF_keyD: %s\n", gpg_strerror (err));
@@ -2772,7 +2778,8 @@ micardo_mse (app_t app, unsigned short fid)
size_t n, nn;
const unsigned char *p, *pp;
- err = iso7816_read_record (app->slot, recno, 1, 0, &buffer, &buflen);
+ err = iso7816_read_record (app_get_slot (app), recno, 1, 0,
+ &buffer, &buflen);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
break; /* ready */
if (err)
@@ -2811,7 +2818,8 @@ micardo_mse (app_t app, unsigned short fid)
/* Restore the security environment to SE_NUM if needed */
if (se_num)
{
- err = iso7816_manage_security_env (app->slot, 0xf3, se_num, NULL, 0);
+ err = iso7816_manage_security_env (app_get_slot (app),
+ 0xf3, se_num, NULL, 0);
if (err)
{
log_error ("restoring SE to %d failed: %s\n",
@@ -2826,7 +2834,7 @@ micardo_mse (app_t app, unsigned short fid)
msebuf[2] = 0x80;
msebuf[3] = (refdata >> 8);
msebuf[4] = refdata;
- err = iso7816_manage_security_env (app->slot, 0x41, 0xb6, msebuf, 5);
+ err = iso7816_manage_security_env (app_get_slot (app), 0x41, 0xb6, msebuf, 5);
if (err)
{
log_error ("setting SE to reference file %04hX failed: %s\n",
@@ -2948,7 +2956,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
mse[3] = 0x84; /* Private key reference tag. */
mse[4] = prkdf->key_reference_valid? prkdf->key_reference : 0x82;
- err = iso7816_manage_security_env (app->slot,
+ err = iso7816_manage_security_env (app_get_slot (app),
0x41, 0xB6,
mse, sizeof mse);
no_data_padding = 1;
@@ -3101,7 +3109,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
else
pinvaluelen = strlen (pinvalue);
- err = iso7816_verify (app->slot,
+ err = iso7816_verify (app_get_slot (app),
aodf->pin_reference_valid? aodf->pin_reference : 0,
pinvalue, pinvaluelen);
xfree (pinvalue);
@@ -3170,7 +3178,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
mse[1] = 1;
mse[2] = prkdf->key_reference;
- err = iso7816_manage_security_env (app->slot,
+ err = iso7816_manage_security_env (app_get_slot (app),
0x41, 0xB6,
mse, sizeof mse);
}
@@ -3181,11 +3189,14 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
}
if (hashalgo == MD_USER_TLS_MD5SHA1)
- err = iso7816_compute_ds (app->slot, 0, data, 36, 0, outdata, outdatalen);
+ err = iso7816_compute_ds (app_get_slot (app),
+ 0, data, 36, 0, outdata, outdatalen);
else if (no_data_padding)
- err = iso7816_compute_ds (app->slot, 0, data+15, 20, 0,outdata,outdatalen);
+ err = iso7816_compute_ds (app_get_slot (app),
+ 0, data+15, 20, 0,outdata,outdatalen);
else
- err = iso7816_compute_ds (app->slot, 0, data, 35, 0, outdata, outdatalen);
+ err = iso7816_compute_ds (app_get_slot (app),
+ 0, data, 35, 0, outdata, outdatalen);
return err;
}
@@ -3280,7 +3291,7 @@ read_home_df (int slot, int *r_belpic)
gpg_error_t
app_select_p15 (app_t app)
{
- int slot = app->slot;
+ int slot = app_get_slot (app);
int rc;
unsigned short def_home_df = 0;
card_type_t card_type = CARD_TYPE_UNKNOWN;
@@ -3298,7 +3309,7 @@ app_select_p15 (app_t app)
Using the 2f02 just works. */
unsigned short path[1] = { 0x2f00 };
- rc = iso7816_select_path (app->slot, path, 1);
+ rc = iso7816_select_path (app_get_slot (app), path, 1);
if (!rc)
{
direct = 1;
@@ -3306,7 +3317,7 @@ app_select_p15 (app_t app)
if (def_home_df)
{
path[0] = def_home_df;
- rc = iso7816_select_path (app->slot, path, 1);
+ rc = iso7816_select_path (app_get_slot (app), path, 1);
}
}
}
@@ -3330,7 +3341,7 @@ app_select_p15 (app_t app)
size_t atrlen;
int i;
- atr = apdu_get_atr (app->slot, &atrlen);
+ atr = apdu_get_atr (app_get_slot (app), &atrlen);
if (!atr)
rc = gpg_error (GPG_ERR_INV_CARD);
else
@@ -3348,7 +3359,7 @@ app_select_p15 (app_t app)
}
if (!rc)
{
- app->apptype = "P15";
+ app->apptype = APPTYPE_P15;
app->app_local = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
@@ -3381,8 +3392,8 @@ app_select_p15 (app_t app)
prototype card right here because we need to access to
EF(TokenInfo). We mark such a serial number by the using a
prefix of FF0100. */
- if (app->serialnolen == 12
- && !memcmp (app->serialno, "\xD2\x76\0\0\0\0\0\0\0\0\0\0", 12))
+ if (app->card->serialnolen == 12
+ && !memcmp (app->card->serialno, "\xD2\x76\0\0\0\0\0\0\0\0\0\0", 12))
{
/* This is a German card with a silly serial number. Try to get
the serial number from the EF(TokenInfo). . */
@@ -3390,20 +3401,21 @@ app_select_p15 (app_t app)
/* FIXME: actually get it from EF(TokenInfo). */
- p = xtrymalloc (3 + app->serialnolen);
+ p = xtrymalloc (3 + app->card->serialnolen);
if (!p)
rc = gpg_error (gpg_err_code_from_errno (errno));
else
{
memcpy (p, "\xff\x01", 3);
- memcpy (p+3, app->serialno, app->serialnolen);
- app->serialnolen += 3;
- xfree (app->serialno);
- app->serialno = p;
+ memcpy (p+3, app->card->serialno, app->card->serialnolen);
+ app->card->serialnolen += 3;
+ xfree (app->card->serialno);
+ app->card->serialno = p;
}
}
app->fnc.deinit = do_deinit;
+ app->fnc.reselect = NULL;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.getattr = do_getattr;
diff --git a/scd/app-piv.c b/scd/app-piv.c
index 5748c70b8..3b94a28e4 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -19,6 +19,7 @@
/* Some notes:
* - Specs for PIV are at http://dx.doi.org/10.6028/NIST.SP.800-73-4
+ * - https://developers.yubico.com/PIV/Introduction/PIV_attestation.html
*
* - Access control matrix:
* | Action | 9B | PIN | PUK | |
@@ -60,7 +61,6 @@
#include "../common/util.h"
#include "../common/i18n.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
#include "../common/host2net.h"
#include "apdu.h" /* We use apdu_send_direct. */
@@ -81,6 +81,10 @@
#define PIV_ALGORITHM_ECC_P384 0x14
+/* The AID for PIV. */
+static char const piv_aid[] = { 0xA0, 0x00, 0x00, 0x03, 0x08, /* RID=NIST */
+ 0x00, 0x00, 0x10, 0x00 /* PIX=PIV */ };
+
/* A table describing the DOs of a PIV card. */
struct data_object_s
@@ -282,7 +286,7 @@ get_cached_data (app_t app, int tag,
}
}
- err = iso7816_get_data_odd (app->slot, 0, tag, &p, &len);
+ err = iso7816_get_data_odd (app_get_slot (app), 0, tag, &p, &len);
if (err)
return err;
@@ -736,18 +740,18 @@ get_dispserialno (app_t app, int failmode)
{
char *result;
- if (app->serialno && app->serialnolen == 3+1+4
- && !memcmp (app->serialno, "\xff\x02\x00", 3))
+ if (app->card && app->card->serialno && app->card->serialnolen == 3+1+4
+ && !memcmp (app->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. */
unsigned long sn;
- sn = app->serialno[4] * 16777216;
- sn += app->serialno[5] * 65536;
- sn += app->serialno[6] * 256;
- sn += app->serialno[7];
+ sn = app->card->serialno[4] * 16777216;
+ sn += app->card->serialno[5] * 65536;
+ sn += app->card->serialno[6] * 256;
+ sn += app->card->serialno[7];
result = xtryasprintf ("yk-%lu", sn);
}
else if (failmode)
@@ -785,7 +789,7 @@ get_chv_status (app_t app, const char *keyrefstr)
apdu[1] = ISO7816_VERIFY;
apdu[2] = 0x00;
apdu[3] = keyref;
- if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
+ if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL))
result = -5; /* No need to verification. */
else if (sw == 0x6a88 || sw == 0x6a80)
result = -2; /* No such PIN. */
@@ -811,7 +815,9 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
int special;
} table[] = {
{ "SERIALNO", 0x0000, -1 },
- { "$AUTHKEYID", 0x0000, -2 }, /* Default key for ssh. */
+ { "$AUTHKEYID", 0x0000, -2 }, /* Default ssh key. */
+ { "$ENCRKEYID", 0x0000, -6 }, /* Default encryption key. */
+ { "$SIGNKEYID", 0x0000, -7 }, /* Default signing key. */
{ "$DISPSERIALNO",0x0000, -3 },
{ "CHV-STATUS", 0x0000, -4 },
{ "CHV-USAGE", 0x007E, -5 }
@@ -882,6 +888,16 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
xfree (relptr);
}
}
+ else if (table[idx].special == -6)
+ {
+ char const tmp[] = "PIV.9D"; /* Key Management. */
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ }
+ else if (table[idx].special == -7)
+ {
+ char const tmp[] = "PIV.9C"; /* Digital Signature. */
+ send_status_info (ctrl, table[idx].name, tmp, strlen (tmp), NULL, 0);
+ }
else
{
relptr = get_one_do (app, table[idx].tag, &value, &valuelen, &err);
@@ -925,7 +941,7 @@ auth_adm_key (app_t app, const unsigned char *value, size_t valuelen)
tmpl[2] = 0x80;
tmpl[3] = 0; /* (Empty witness requests a witness.) */
tmpllen = 4;
- err = iso7816_general_authenticate (app->slot, 0,
+ err = iso7816_general_authenticate (app_get_slot (app), 0,
PIV_ALGORITHM_3DES_ECB_0, 0x9B,
tmpl, tmpllen, 0,
&outdata, &outdatalen);
@@ -958,7 +974,7 @@ auth_adm_key (app_t app, const unsigned char *value, size_t valuelen)
tmpl[23] = 0;
tmpllen = 24;
xfree (outdata);
- err = iso7816_general_authenticate (app->slot, 0,
+ err = iso7816_general_authenticate (app_get_slot (app), 0,
PIV_ALGORITHM_3DES_ECB_0, 0x9B,
tmpl, tmpllen, 0,
&outdata, &outdatalen);
@@ -1032,7 +1048,8 @@ set_adm_key (app_t app, const unsigned char *value, size_t valuelen)
apdu[6] = 0x9b;
apdu[7] = 24;
memcpy (apdu+8, value, 24);
- err = iso7816_apdu_direct (app->slot, apdu, 8+24, 0, &sw, NULL, NULL);
+ err = iso7816_apdu_direct (app_get_slot (app), apdu, 8+24, 0,
+ &sw, NULL, NULL);
wipememory (apdu+8, 24);
if (err)
log_error ("piv: setting admin key failed; sw=%04x\n", sw);
@@ -1413,7 +1430,7 @@ do_readcert (app_t app, const char *certid,
apdu[1] = 0xf9; /* Yubikey: Get attestation cert. */
apdu[2] = xtoi_2 (certid+9);
apdu[3] = 0;
- err = iso7816_apdu_direct (app->slot, apdu, 4, 1,
+ err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 1,
NULL, &result, &resultlen);
if (!err)
{
@@ -1452,7 +1469,7 @@ do_readcert (app_t app, const char *certid,
* returned.
*/
static gpg_error_t
-do_readkey (app_t app, const char *keyrefstr,
+do_readkey (app_t app, ctrl_t ctrl, const char *keyrefstr, unsigned int flags,
unsigned char **r_pk, size_t *r_pklen)
{
gpg_error_t err;
@@ -1504,9 +1521,35 @@ do_readkey (app_t app, const char *keyrefstr,
goto leave;
}
- *r_pk = pk;
- pk = NULL;
- *r_pklen = pklen;
+ if ((flags & APP_READKEY_FLAG_INFO))
+ {
+ char keygripstr[KEYGRIP_LEN*2+1];
+ char idbuf[50];
+ const char *usage;
+
+ err = app_help_get_keygrip_string_pk (pk, pklen, keygripstr);
+ if (err)
+ {
+ log_error ("app_help_get_keygrip_string_pk failed: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+ usage = dobj->usage? dobj->usage : "";
+
+ snprintf (idbuf, sizeof idbuf, "PIV.%s", dobj->keyref);
+ send_status_info (ctrl, "KEYPAIRINFO",
+ keygripstr, strlen (keygripstr),
+ idbuf, strlen (idbuf),
+ usage, strlen (usage),
+ NULL, (size_t)0);
+ }
+
+ if (r_pk && r_pklen)
+ {
+ *r_pk = pk;
+ pk = NULL;
+ *r_pklen = pklen;
+ }
leave:
gcry_sexp_release (s_pkey);
@@ -1841,7 +1884,7 @@ verify_chv (app_t app, int keyref, int force,
apdu[1] = ISO7816_VERIFY;
apdu[2] = 0x00;
apdu[3] = keyref;
- if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
+ if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL))
{
if (!force) /* No need to verification. */
return 0; /* All fine. */
@@ -1857,7 +1900,7 @@ verify_chv (app_t app, int keyref, int force,
if (err)
return err;
- err = iso7816_verify (app->slot, keyref, pin, pinlen);
+ err = iso7816_verify (app_get_slot (app), keyref, pin, pinlen);
wipememory (pin, pinlen);
xfree (pin);
if (err)
@@ -1918,7 +1961,8 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
apdu[1] = ISO7816_VERIFY;
apdu[2] = 0xff;
apdu[3] = keyref;
- err = iso7816_apdu_direct (app->slot, apdu, 4, 0, NULL, NULL, NULL);
+ err = iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0,
+ NULL, NULL, NULL);
goto leave;
}
@@ -1940,7 +1984,7 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
apdu[1] = ISO7816_VERIFY;
apdu[2] = 0x00;
apdu[3] = keyref;
- if (!iso7816_apdu_direct (app->slot, apdu, 4, 0, &sw, NULL, NULL))
+ if (!iso7816_apdu_direct (app_get_slot (app), apdu, 4, 0, &sw, NULL, NULL))
remaining = -1; /* Already verified, thus full number of tries. */
else if ((sw & 0xfff0) == 0x63C0)
remaining = (sw & 0x000f); /* PIN has REMAINING tries left. */
@@ -1957,7 +2001,7 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
* old is wrong. This is not possible for the PUK, though. */
if (keyref != 0x81)
{
- err = iso7816_verify (app->slot, keyref, oldpin, oldpinlen);
+ err = iso7816_verify (app_get_slot (app), keyref, oldpin, oldpinlen);
if (err)
{
log_error ("CHV %02X verification failed: %s\n",
@@ -1982,7 +2026,8 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
}
memcpy (buf, oldpin, oldpinlen);
memcpy (buf+oldpinlen, newpin, newpinlen);
- err = iso7816_reset_retry_counter_with_rc (app->slot, targetkeyref,
+ err = iso7816_reset_retry_counter_with_rc (app_get_slot (app),
+ targetkeyref,
buf, oldpinlen+newpinlen);
xfree (buf);
if (err)
@@ -1991,7 +2036,7 @@ do_change_chv (app_t app, ctrl_t ctrl, const char *pwidstr,
}
else
{
- err = iso7816_change_reference_data (app->slot, keyref,
+ err = iso7816_change_reference_data (app_get_slot (app), keyref,
oldpin, oldpinlen,
newpin, newpinlen);
if (err)
@@ -2230,7 +2275,7 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
goto leave;
/* Note: the -1 requests command chaining. */
- err = iso7816_general_authenticate (app->slot, -1,
+ err = iso7816_general_authenticate (app_get_slot (app), -1,
mechanism, keyref,
apdudata, (int)apdudatalen, 0,
&outdata, &outdatalen);
@@ -2395,15 +2440,34 @@ do_decipher (app_t app, const char *keyidstr,
/* Check that the ciphertext has the right length; due to internal
* convey mechanism using MPIs leading zero bytes might have been
- * lost. Adjust for this. Note that for ECC this actually
- * superfluous because the first octet is always '04' to indicate an
+ * lost. Adjust for this. Unfortunately the ciphertext might have
+ * also been prefixed with a leading zero to make it a positive
+ * number; that may be a too long frame and we need to adjust for
+ * this too. Note that for ECC thoses fixes are not reqquired
+ * because the first octet is always '04' to indicate an
* uncompressed point. */
if (indatalen > framelen)
{
- err = gpg_error (GPG_ERR_INV_VALUE);
- log_error ("piv: input of %zu octets too large for mechanism %d\n",
- indatalen, mechanism);
- goto leave;
+ if (mechanism == PIV_ALGORITHM_RSA
+ && indatalen == framelen + 1 && !*indata)
+ {
+ indata_buffer = xtrycalloc (1, framelen);
+ if (!indata_buffer)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ memcpy (indata_buffer, indata+1, framelen);
+ indata = indata_buffer;
+ indatalen = framelen;
+ }
+ else
+ {
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ log_error ("piv: input of %zu octets too large for mechanism %d\n",
+ indatalen, mechanism);
+ goto leave;
+ }
}
if (indatalen < framelen)
{
@@ -2434,7 +2498,7 @@ do_decipher (app_t app, const char *keyidstr,
goto leave;
/* Note: the -1 requests command chaining. */
- err = iso7816_general_authenticate (app->slot, -1,
+ err = iso7816_general_authenticate (app_get_slot (app), -1,
mechanism, keyref,
apdudata, (int)apdudatalen, 0,
&outdata, &outdatalen);
@@ -2635,7 +2699,7 @@ writekey_rsa (app_t app, data_object_t dobj, int keyref,
if (err)
goto leave;
- err = iso7816_send_apdu (app->slot,
+ err = iso7816_send_apdu (app_get_slot (app),
-1, /* Use command chaining. */
0, /* Class */
0xfe, /* Ins: Yubikey Import Asym. Key. */
@@ -2657,7 +2721,7 @@ writekey_rsa (app_t app, data_object_t dobj, int keyref,
if (err)
goto leave;
tmpl[0] = PIV_ALGORITHM_RSA;
- err = put_data (app->slot, dobj->tag,
+ err = put_data (app_get_slot (app), dobj->tag,
(int)0x80, (size_t)1, tmpl,
(int)0x7f49, (size_t)apdudatalen, apdudata,
(int)0, (size_t)0, NULL);
@@ -2787,7 +2851,7 @@ writekey_ecc (app_t app, data_object_t dobj, int keyref,
if (err)
goto leave;
- err = iso7816_send_apdu (app->slot,
+ err = iso7816_send_apdu (app_get_slot (app),
-1, /* Use command chaining. */
0, /* Class */
0xfe, /* Ins: Yubikey Import Asym. Key. */
@@ -2808,7 +2872,7 @@ writekey_ecc (app_t app, data_object_t dobj, int keyref,
if (err)
goto leave;
tmpl[0] = mechanism;
- err = put_data (app->slot, dobj->tag,
+ err = put_data (app_get_slot (app), dobj->tag,
(int)0x80, (size_t)1, tmpl,
(int)0x7f49, (size_t)apdudatalen, apdudata,
(int)0, (size_t)0, NULL);
@@ -2894,7 +2958,7 @@ do_writekey (app_t app, ctrl_t ctrl,
/* First clear an existing key. We do this by writing an empty 7f49
* tag. This will return GPG_ERR_NO_PUBKEY on a later read. */
flush_cached_data (app, dobj->tag);
- err = put_data (app->slot, dobj->tag,
+ err = put_data (app_get_slot (app), dobj->tag,
(int)0x7f49, (size_t)0, "",
(int)0, (size_t)0, NULL);
if (err)
@@ -3122,7 +3186,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keyrefstr, const char *keytype,
tmpl[3] = 1;
tmpl[4] = mechanism;
tmpllen = 5;
- err = iso7816_generate_keypair (app->slot, 0, 0, keyref,
+ err = iso7816_generate_keypair (app_get_slot (app), 0, 0, keyref,
tmpl, tmpllen, 0, &buffer, &buflen);
if (err)
{
@@ -3152,7 +3216,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keyrefstr, const char *keytype,
tmpl[0] = mechanism;
flush_cached_data (app, dobj->tag);
- err = put_data (app->slot, dobj->tag,
+ err = put_data (app_get_slot (app), dobj->tag,
(int)0x80, (size_t)1, tmpl,
(int)0x7f49, (size_t)keydatalen, keydata,
(int)0, (size_t)0, NULL);
@@ -3205,7 +3269,7 @@ do_writecert (app_t app, ctrl_t ctrl,
* GPG_ERR_NO_PUBKEY). We enforce this because otherwise the only
* way to detect whether a key exists is by trying to use that
* key. */
- err = do_readkey (app, certrefstr, &orig_pk, &orig_pklen);
+ err = do_readkey (app, ctrl, certrefstr, 0, &orig_pk, &orig_pklen);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
@@ -3223,7 +3287,7 @@ do_writecert (app_t app, ctrl_t ctrl,
goto leave;
}
- err = put_data (app->slot, dobj->tag,
+ err = put_data (app_get_slot (app), dobj->tag,
(int)0x70, (size_t)certlen, cert,/* Certificate */
(int)0x71, (size_t)1, "", /* No compress */
(int)0xfe, (size_t)0, "", /* Empty LRC. */
@@ -3242,14 +3306,121 @@ do_writecert (app_t app, ctrl_t ctrl,
}
+/* Process the various keygrip based info requests. */
+static gpg_error_t
+do_with_keygrip (app_t app, ctrl_t ctrl, int action,
+ const char *want_keygripstr)
+{
+ gpg_error_t err;
+ char *keygripstr = NULL;
+ char *serialno = NULL;
+ char idbuf[20];
+ int data = 0;
+ int i, tag, dummy_got_cert;
+
+ /* First a quick check for valid parameters. */
+ switch (action)
+ {
+ case KEYGRIP_ACTION_LOOKUP:
+ if (!want_keygripstr)
+ {
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+ goto leave;
+ }
+ break;
+ case KEYGRIP_ACTION_SEND_DATA:
+ data = 1;
+ break;
+ case KEYGRIP_ACTION_WRITE_STATUS:
+ break;
+ default:
+ err = gpg_error (GPG_ERR_INV_ARG);
+ goto leave;
+ }
+
+ /* Allocate the s/n string if needed. */
+ if (action != KEYGRIP_ACTION_LOOKUP)
+ {
+ serialno = app_get_serialno (app);
+ if (!serialno)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ }
+
+ for (i = 0; (tag = data_objects[i].tag); i++)
+ {
+ if (!data_objects[i].keypair)
+ continue;
+
+ xfree (keygripstr);
+ if (get_keygrip_by_tag (app, tag, &keygripstr, &dummy_got_cert))
+ continue;
+
+ if (action == KEYGRIP_ACTION_LOOKUP)
+ {
+ if (!strcmp (keygripstr, want_keygripstr))
+ {
+ err = 0; /* Found */
+ goto leave;
+ }
+ }
+ else if (!want_keygripstr || !strcmp (keygripstr, want_keygripstr))
+ {
+ snprintf (idbuf, sizeof idbuf, "PIV.%s", data_objects[i].keyref);
+ send_keyinfo (ctrl, data, keygripstr, serialno, idbuf);
+ if (want_keygripstr)
+ {
+ err = 0; /* Found */
+ goto leave;
+ }
+ }
+ }
+
+ /* Return an error so that the dispatcher keeps on looping over the
+ * other applications. For clarity we use a different error code
+ * when listing all keys. Note that in lookup mode WANT_KEYGRIPSTR
+ * is not NULL. */
+ if (!want_keygripstr)
+ err = gpg_error (GPG_ERR_TRUE);
+ else
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+
+ leave:
+ xfree (keygripstr);
+ xfree (serialno);
+ return err;
+}
+
+
+/* Reselect the application. This is used by cards which support
+ * on-the-fly switching between applications. */
+static gpg_error_t
+do_reselect (app_t app, ctrl_t ctrl)
+{
+ gpg_error_t err;
+
+ (void)ctrl;
+
+ /* An extra check which should not be necessary because the caller
+ * should have made sure that a re-select is only called for
+ * approriate cards. */
+ if (!app->app_local->flags.yubikey)
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+
+ err = iso7816_select_application (app_get_slot (app),
+ piv_aid, sizeof piv_aid, 0x0001);
+ return err;
+}
+
+
/* Select the PIV application on the card in SLOT. This function must
* be used before any other PIV application functions. */
gpg_error_t
app_select_piv (app_t app)
{
- static char const aid[] = { 0xA0, 0x00, 0x00, 0x03, 0x08, /* RID=NIST */
- 0x00, 0x00, 0x10, 0x00 /* PIX=PIV */ };
- int slot = app->slot;
+ int slot = app_get_slot (app);
gpg_error_t err;
unsigned char *apt = NULL;
size_t aptlen;
@@ -3259,12 +3430,12 @@ app_select_piv (app_t app)
/* Note that we select using the AID without the 2 octet version
* number. This allows for better reporting of future specs. We
* need to use the use-zero-for-P2-flag. */
- err = iso7816_select_application_ext (slot, aid, sizeof aid, 0x0001,
+ err = iso7816_select_application_ext (slot, piv_aid, sizeof piv_aid, 0x0001,
&apt, &aptlen);
if (err)
goto leave;
- app->apptype = "PIV";
+ app->apptype = APPTYPE_PIV;
app->did_chv1 = 0;
app->did_chv2 = 0;
app->did_chv3 = 0;
@@ -3279,7 +3450,7 @@ app_select_piv (app_t app)
}
s = find_tlv (apt, aptlen, 0x4F, &n);
- if (!s || n != 6 || memcmp (s, aid+5, 4))
+ if (!s || n != 6 || memcmp (s, piv_aid+5, 4))
{
/* The PIX does not match. */
log_error ("piv: missing or invalid DO 0x4F in APT\n");
@@ -3302,7 +3473,7 @@ app_select_piv (app_t app)
goto leave;
}
s = find_tlv (s, n, 0x4F, &n);
- if (!s || n != 5 || memcmp (s, aid, 5))
+ if (!s || n != 5 || memcmp (s, piv_aid, 5))
{
/* The RID does not match. */
log_error ("piv: missing or invalid DO 0x79.4F in APT\n");
@@ -3317,7 +3488,7 @@ app_select_piv (app_t app)
goto leave;
}
- if (app->cardtype && !strcmp (app->cardtype, "yubikey"))
+ if (app->card->cardtype == CARDTYPE_YUBIKEY)
app->app_local->flags.yubikey = 1;
@@ -3327,6 +3498,7 @@ app_select_piv (app_t app)
dump_all_do (slot);
app->fnc.deinit = do_deinit;
+ app->fnc.reselect = do_reselect;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.readkey = do_readkey;
@@ -3340,6 +3512,7 @@ app_select_piv (app_t app)
app->fnc.decipher = do_decipher;
app->fnc.change_pin = do_change_chv;
app->fnc.check_pin = do_check_chv;
+ app->fnc.with_keygrip = do_with_keygrip;
leave:
diff --git a/scd/app-sc-hsm.c b/scd/app-sc-hsm.c
index 8094b2463..16d25b581 100644
--- a/scd/app-sc-hsm.c
+++ b/scd/app-sc-hsm.c
@@ -33,7 +33,6 @@
#include "scdaemon.h"
#include "iso7816.h"
-#include "app-common.h"
#include "../common/tlv.h"
#include "apdu.h"
@@ -484,7 +483,8 @@ read_ef_prkd (app_t app, unsigned short fid, prkdf_object_t *prkdresult,
if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No private keys. */
- err = select_and_read_binary (app->slot, fid, "PrKDF", &buffer, &buflen, 255);
+ err = select_and_read_binary (app_get_slot (app),
+ fid, "PrKDF", &buffer, &buflen, 255);
if (err)
return err;
@@ -832,7 +832,7 @@ read_ef_prkd (app_t app, unsigned short fid, prkdf_object_t *prkdresult,
xfree (buffer);
buffer = NULL;
buflen = 0;
- err = select_and_read_binary (app->slot,
+ err = select_and_read_binary (app_get_slot (app),
((SC_HSM_EE_PREFIX << 8) | (fid & 0xFF)),
"CertEF", &buffer, &buflen, 1);
if (!err && buffer[0] == 0x30)
@@ -953,7 +953,8 @@ read_ef_cd (app_t app, unsigned short fid, cdf_object_t *result)
if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No certificates. */
- err = select_and_read_binary (app->slot, fid, "CDF", &buffer, &buflen, 255);
+ err = select_and_read_binary (app_get_slot (app), fid, "CDF",
+ &buffer, &buflen, 255);
if (err)
return err;
@@ -1202,7 +1203,7 @@ read_serialno(app_t app)
size_t n, objlen, hdrlen, chrlen;
int class, tag, constructed, ndef;
- err = select_and_read_binary (app->slot, 0x2F02, "EF.C_DevAut",
+ err = select_and_read_binary (app_get_slot (app), 0x2F02, "EF.C_DevAut",
&buffer, &buflen, 512);
if (err)
return err;
@@ -1229,15 +1230,15 @@ read_serialno(app_t app)
}
chrlen -= 5;
- app->serialno = xtrymalloc (chrlen);
- if (!app->serialno)
+ app->card->serialno = xtrymalloc (chrlen);
+ if (!app->card->serialno)
{
err = gpg_error_from_syserror ();
goto leave;
}
- app->serialnolen = chrlen;
- memcpy (app->serialno, chr, chrlen);
+ app->card->serialnolen = chrlen;
+ memcpy (app->card->serialno, chr, chrlen);
leave:
xfree (buffer);
@@ -1260,7 +1261,7 @@ read_meta (app_t app)
if (err)
return err;
- err = list_ef (app->slot, &eflist, &eflistlen);
+ err = list_ef (app_get_slot (app), &eflist, &eflistlen);
if (err)
return err;
@@ -1454,7 +1455,7 @@ readcert_by_cdf (app_t app, cdf_object_t cdf,
return 0;
}
- err = select_and_read_binary (app->slot, cdf->fid, "CD",
+ err = select_and_read_binary (app_get_slot (app), cdf->fid, "CD",
&buffer, &buflen, 4096);
if (err)
{
@@ -1592,7 +1593,8 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
}
else if (!strcmp (name, "$DISPSERIALNO"))
{
- send_status_info (ctrl, name, app->serialno, app->serialnolen, NULL, 0);
+ send_status_info (ctrl, name,
+ app->card->serialno, app->card->serialnolen, NULL, 0);
return 0;
}
@@ -1693,8 +1695,8 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
char *prompt;
int sw;
- sw = apdu_send_simple (app->slot, 0, 0x00, ISO7816_VERIFY, 0x00, 0x81,
- -1, NULL);
+ sw = apdu_send_simple (app_get_slot (app),
+ 0, 0x00, ISO7816_VERIFY, 0x00, 0x81, -1, NULL);
if (sw == SW_SUCCESS)
return 0; /* PIN already verified */
@@ -1719,7 +1721,7 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
prompt = "||Please enter the PIN";
if (!opt.disable_pinpad
- && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo) )
+ && !iso7816_check_pinpad (app_get_slot (app), ISO7816_VERIFY, &pininfo) )
{
err = pincb (pincb_arg, prompt, NULL);
if (err)
@@ -1728,7 +1730,7 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
return err;
}
- err = iso7816_verify_kp (app->slot, 0x81, &pininfo);
+ err = iso7816_verify_kp (app_get_slot (app), 0x81, &pininfo);
pincb (pincb_arg, NULL, NULL); /* Dismiss the prompt. */
}
else
@@ -1740,7 +1742,8 @@ verify_pin (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
return err;
}
- err = iso7816_verify (app->slot, 0x81, pinvalue, strlen(pinvalue));
+ err = iso7816_verify (app_get_slot (app),
+ 0x81, pinvalue, strlen(pinvalue));
xfree (pinvalue);
}
if (err)
@@ -1883,7 +1886,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
if (err)
return err;
- sw = apdu_send_le (app->slot, 1, 0x80, 0x68, prkdf->key_reference, algoid,
+ sw = apdu_send_le (app_get_slot (app),
+ 1, 0x80, 0x68, prkdf->key_reference, algoid,
cdsblklen, cdsblk, 0, outdata, outdatalen);
return iso7816_map_sw (sw);
}
@@ -2018,7 +2022,8 @@ do_decipher (app_t app, const char *keyidstr,
if (err)
return err;
- sw = apdu_send_le (app->slot, 1, 0x80, 0x62, prkdf->key_reference, 0x21,
+ sw = apdu_send_le (app_get_slot (app),
+ 1, 0x80, 0x62, prkdf->key_reference, 0x21,
p1blklen, p1blk, 0, &rspdata, &rspdatalen);
err = iso7816_map_sw (sw);
if (err)
@@ -2044,13 +2049,13 @@ do_decipher (app_t app, const char *keyidstr,
gpg_error_t
app_select_sc_hsm (app_t app)
{
- int slot = app->slot;
+ int slot = app_get_slot (app);
int rc;
rc = iso7816_select_application (slot, sc_hsm_aid, sizeof sc_hsm_aid, 0);
if (!rc)
{
- app->apptype = "SC-HSM";
+ app->apptype = APPTYPE_SC_HSM;
app->app_local = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
@@ -2064,6 +2069,7 @@ app_select_sc_hsm (app_t app)
goto leave;
app->fnc.deinit = do_deinit;
+ app->fnc.reselect = NULL;
app->fnc.learn_status = do_learn_status;
app->fnc.readcert = do_readcert;
app->fnc.getattr = do_getattr;
diff --git a/scd/app.c b/scd/app.c
index 2ee104d9e..57c4b7743 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -26,14 +26,142 @@
#include "scdaemon.h"
#include "../common/exechelp.h"
-#include "app-common.h"
#include "iso7816.h"
#include "apdu.h"
#include "../common/tlv.h"
-static npth_mutex_t app_list_lock;
-static app_t app_top;
+/* Lock to protect the list of cards and its associated
+ * applications. */
+static npth_mutex_t card_list_lock;
+
+/* 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;
+
+
+/* The list of application names and their select function. If no
+ * specific application is selected the first available application on
+ * a card is selected. */
+struct app_priority_list_s
+{
+ apptype_t apptype;
+ char const *name;
+ gpg_error_t (*select_func)(app_t);
+};
+
+static struct app_priority_list_s app_priority_list[] =
+ {{ 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. */
+ };
+
+
+
+
+/* Map a cardtype to a string. Never returns NULL. */
+const char *
+strcardtype (cardtype_t t)
+{
+ switch (t)
+ {
+ case CARDTYPE_GENERIC: return "generic";
+ case CARDTYPE_YUBIKEY: return "yubikey";
+ }
+ 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";
+}
+
+
+/* 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;
+}
+
+
+/* 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);
+}
+
+
static void
print_progress_line (void *opaque, const char *what, int pc, int cur, int tot)
{
@@ -48,59 +176,69 @@ print_progress_line (void *opaque, const char *what, int pc, int cur, int tot)
}
-/* Lock the reader SLOT. 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 reader is not
- actually used. This allows an actual connection to assume that it
- never shares a reader (while performing one command). Returns 0 on
- success; only then the unlock_reader function must be called after
- returning from the handler. */
+/* 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. */
static gpg_error_t
-lock_app (app_t app, ctrl_t ctrl)
+lock_card (card_t card, ctrl_t ctrl)
{
- if (npth_mutex_lock (&app->lock))
+ if (npth_mutex_lock (&card->lock))
{
gpg_error_t err = gpg_error_from_syserror ();
- log_error ("failed to acquire APP lock for %p: %s\n",
- app, gpg_strerror (err));
+ log_error ("failed to acquire CARD lock for %p: %s\n",
+ card, gpg_strerror (err));
return err;
}
- apdu_set_progress_cb (app->slot, print_progress_line, ctrl);
- apdu_set_prompt_cb (app->slot, popup_prompt, ctrl);
+ apdu_set_progress_cb (card->slot, print_progress_line, ctrl);
+ apdu_set_prompt_cb (card->slot, popup_prompt, ctrl);
return 0;
}
-/* Release a lock on the reader. See lock_reader(). */
+
+/* Release a lock on a card. See lock_reader(). */
static void
-unlock_app (app_t app)
+unlock_card (card_t card)
{
- apdu_set_progress_cb (app->slot, NULL, NULL);
- apdu_set_prompt_cb (app->slot, NULL, NULL);
+ apdu_set_progress_cb (card->slot, NULL, NULL);
+ apdu_set_prompt_cb (card->slot, NULL, NULL);
- if (npth_mutex_unlock (&app->lock))
+ if (npth_mutex_unlock (&card->lock))
{
gpg_error_t err = gpg_error_from_syserror ();
- log_error ("failed to release APP lock for %p: %s\n",
- app, gpg_strerror (err));
+ log_error ("failed to release CARD lock for %p: %s\n",
+ card, gpg_strerror (err));
}
}
/* This function may be called to print information pertaining to the
- current state of this module to the log. */
+ * current state of this module to the log. */
void
app_dump_state (void)
{
+ card_t c;
app_t a;
- npth_mutex_lock (&app_list_lock);
- for (a = app_top; a; a = a->next)
- log_info ("app_dump_state: app=%p type='%s'\n", a, a->apptype);
- npth_mutex_unlock (&app_list_lock);
+ npth_mutex_lock (&card_list_lock);
+ for (c = card_top; c; c = c->next)
+ {
+ log_info ("app_dump_state: card=%p slot=%d type=%s\n",
+ c, c->slot, strcardtype (c->cardtype));
+ for (a=c->app; a; a = a->next)
+ log_info ("app_dump_state: app=%p type='%s'\n",
+ a, strapptype (a->apptype));
+ }
+ npth_mutex_unlock (&card_list_lock);
}
+
/* Check whether the application NAME is allowed. This does not mean
we have support for it though. */
static int
@@ -115,34 +253,71 @@ is_app_allowed (const char *name)
}
-static gpg_error_t
-check_conflict (app_t app, const char *name)
+/* 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.
+ * Other code - Switching is not possible.
+ *
+ * If SERIALNO_BIN is not NULL a coflict is onl asserted if the
+ * serialno of the card matches.
+ */
+gpg_error_t
+check_application_conflict (card_t card, const char *name,
+ const unsigned char *serialno_bin,
+ size_t serialno_bin_len)
{
- if (!app || !name || (app->apptype && !ascii_strcasecmp (app->apptype, name)))
+ app_t app;
+
+ if (!card || !name)
return 0;
+ if (!card->app)
+ return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */
- if (app->apptype && !strcmp (app->apptype, "UNDEFINED"))
+ if (serialno_bin && card->serialno)
+ {
+ if (serialno_bin_len != card->serialnolen
+ || memcmp (serialno_bin, card->serialno, card->serialnolen))
+ return 0; /* The card does not match the requested S/N. */
+ }
+
+ /* Check whether the requested NAME matches any already selected
+ * application. */
+ for (app = card->app; app; app = app->next)
+ if (!ascii_strcasecmp (strapptype (app->apptype), name))
+ return 0;
+
+ if (card->app->apptype == APPTYPE_UNDEFINED)
return 0;
+ 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. */
+ }
+ }
+
log_info ("application '%s' in use - can't switch\n",
- app->apptype? app->apptype : "<null>");
+ strapptype (card->app->apptype));
return gpg_error (GPG_ERR_CONFLICT);
}
-/* This function is 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. */
-gpg_error_t
-check_application_conflict (const char *name, app_t app)
-{
- return check_conflict (app, name);
-}
-
gpg_error_t
-app_reset (app_t app, ctrl_t ctrl, int send_reset)
+card_reset (card_t card, ctrl_t ctrl, int send_reset)
{
gpg_error_t err = 0;
@@ -150,21 +325,21 @@ app_reset (app_t app, ctrl_t ctrl, int send_reset)
{
int sw;
- lock_app (app, ctrl);
- sw = apdu_reset (app->slot);
+ lock_card (card, ctrl);
+ sw = apdu_reset (card->slot);
if (sw)
err = gpg_error (GPG_ERR_CARD_RESET);
- app->reset_requested = 1;
- unlock_app (app);
+ card->reset_requested = 1;
+ unlock_card (card);
scd_kick_the_loop ();
gnupg_sleep (1);
}
else
{
- ctrl->app_ctx = NULL;
- release_application (app, 0);
+ ctrl->card_ctx = NULL;
+ card_unref (card);
}
return err;
@@ -175,35 +350,37 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
int periodical_check_needed)
{
gpg_error_t err = 0;
+ card_t card = NULL;
app_t app = NULL;
unsigned char *result = NULL;
size_t resultlen;
int want_undefined;
+ int i;
- /* Need to allocate a new one. */
- app = xtrycalloc (1, sizeof *app);
- if (!app)
+ /* Need to allocate a new card object */
+ card = xtrycalloc (1, sizeof *card);
+ if (!card)
{
err = gpg_error_from_syserror ();
log_info ("error allocating context: %s\n", gpg_strerror (err));
return err;
}
- app->slot = slot;
- app->card_status = (unsigned int)-1;
+ card->slot = slot;
+ card->card_status = (unsigned int)-1;
- if (npth_mutex_init (&app->lock, NULL))
+ if (npth_mutex_init (&card->lock, NULL))
{
err = gpg_error_from_syserror ();
log_error ("error initializing mutex: %s\n", gpg_strerror (err));
- xfree (app);
+ xfree (card);
return err;
}
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
{
- xfree (app);
+ xfree (card);
return err;
}
@@ -221,9 +398,12 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
* config. */
static char const yk_aid[] =
{ 0xA0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17 }; /*MGR*/
+ static char const otp_aid[] =
+ { 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01 }; /*OTP*/
unsigned char *buf;
size_t buflen;
- const unsigned char *s0, *s1;
+ const unsigned char *s0;
+ unsigned char formfactor;
size_t n;
if (!iso7816_select_application (slot, yk_aid, sizeof yk_aid,
@@ -231,7 +411,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
&& !iso7816_apdu_direct (slot, "\x00\x1d\x00\x00\x00", 5, 0,
NULL, &buf, &buflen))
{
- app->cardtype = "yubikey";
+ card->cardtype = CARDTYPE_YUBIKEY;
if (opt.verbose)
{
log_info ("Yubico: config=");
@@ -243,29 +423,43 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
if (buflen > 1)
{
s0 = find_tlv (buf+1, buflen-1, 0x04, &n); /* Form factor */
- if (s0 && n == 1)
+ formfactor = (s0 && n == 1)? *s0 : 0;
+
+ s0 = find_tlv (buf+1, buflen-1, 0x02, &n); /* Serial */
+ if (s0 && n >= 4)
{
- s1 = find_tlv (buf+1, buflen-1, 0x02, &n); /* Serial */
- if (s1 && n >= 4)
+ card->serialno = xtrymalloc (3 + 1 + n);
+ if (card->serialno)
{
- app->serialno = xtrymalloc (3 + 1 + n);
- if (app->serialno)
- {
- app->serialnolen = 3 + 1 + n;
- app->serialno[0] = 0xff;
- app->serialno[1] = 0x02;
- app->serialno[2] = 0x0;
- app->serialno[3] = *s0;
- memcpy (app->serialno + 4, s1, n);
- /* Note that we do not clear the error
- * so that no further serial number
- * testing is done. After all we just
- * set the serial number. */
- }
+ 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);
+ /* Note that we do not clear the error
+ * so that no further serial number
+ * testing is done. After all we just
+ * set the serial number. */
}
- s1 = find_tlv (buf+1, buflen-1, 0x05, &n); /* version */
- if (s1 && n == 3)
- app->cardversion = ((s1[0]<<16)|(s1[1]<<8)|s1[2]);
+ }
+
+ s0 = find_tlv (buf+1, buflen-1, 0x05, &n); /* version */
+ if (s0 && n == 3)
+ card->cardversion = ((s0[0]<<16)|(s0[1]<<8)|s0[2]);
+ else if (!s0)
+ {
+ /* No version - this is not a Yubikey 5. We now
+ * switch to the OTP app and take the first
+ * three bytes of the reponse as version
+ * number. */
+ xfree (buf);
+ buf = NULL;
+ if (!iso7816_select_application_ext (slot,
+ otp_aid, sizeof otp_aid,
+ 1, &buf, &buflen)
+ && buflen > 3)
+ card->cardversion = ((buf[0]<<16)|(buf[1]<<8)|buf[2]);
}
}
xfree (buf);
@@ -286,7 +480,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
resultlen -= (p-result);
if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
{
- /* The object it does not fit into the buffer. This is an
+ /* The object does not fit into the buffer. This is an
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
@@ -300,9 +494,9 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
/* The GDO file is pretty short, thus we simply reuse it for
storing the serial number. */
memmove (result, p, n);
- app->serialno = result;
- app->serialnolen = n;
- err = app_munge_serialno (app);
+ card->serialno = result;
+ card->serialnolen = n;
+ err = app_munge_serialno (card);
if (err)
goto leave;
}
@@ -312,12 +506,23 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
}
}
+ /* 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;
+
/* Figure out the application to use. */
if (want_undefined)
{
/* We switch to the "undefined" application only if explicitly
requested. */
- app->apptype = "UNDEFINED";
+ app->apptype = APPTYPE_UNDEFINED;
/* Clear the error so that we don't run through the application
* selection chain. */
err = 0;
@@ -330,26 +535,18 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
goto leave;
/* Set a default error so that we run through the application
- * selecion chain. */
+ * selection chain. */
err = gpg_error (GPG_ERR_NOT_FOUND);
}
- if (err && is_app_allowed ("openpgp")
- && (!name || !strcmp (name, "openpgp")))
- err = app_select_openpgp (app);
- if (err && is_app_allowed ("piv") && (!name || !strcmp (name, "piv")))
- err = app_select_piv (app);
- if (err && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
- err = app_select_nks (app);
- if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
- err = app_select_p15 (app);
- if (err && is_app_allowed ("geldkarte")
- && (!name || !strcmp (name, "geldkarte")))
- err = app_select_geldkarte (app);
- if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
- err = app_select_dinsig (app);
- if (err && is_app_allowed ("sc-hsm") && (!name || !strcmp (name, "sc-hsm")))
- err = app_select_sc_hsm (app);
+ /* Find the first available app if NAME is NULL or the matching
+ * 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);
+ }
if (err && name && gpg_err_code (err) != GPG_ERR_OBJ_TERM_STATE)
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
@@ -362,44 +559,47 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
else
log_info ("no supported card application found: %s\n",
gpg_strerror (err));
- unlock_app (app);
+ unlock_card (card);
xfree (app);
+ xfree (card);
return err;
}
- app->periodical_check_needed = periodical_check_needed;
- app->next = app_top;
- app_top = app;
- unlock_app (app);
+ card->periodical_check_needed = periodical_check_needed;
+ card->next = card_top;
+ card_top = card;
+
+ unlock_card (card);
return 0;
}
+
/* If called with NAME as NULL, select the best fitting application
- and return a context; otherwise select the application with NAME
- and return a context. Returns an error code and stores NULL at
- R_APP if no application was found or no card is present. */
+ * 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. */
gpg_error_t
-select_application (ctrl_t ctrl, const char *name, app_t *r_app,
+select_application (ctrl_t ctrl, const char *name, card_t *r_card,
int scan, const unsigned char *serialno_bin,
size_t serialno_bin_len)
{
gpg_error_t err = 0;
- app_t a, a_prev = NULL;
+ card_t card, card_prev = NULL;
- *r_app = NULL;
+ *r_card = NULL;
- npth_mutex_lock (&app_list_lock);
+ npth_mutex_lock (&card_list_lock);
- if (scan || !app_top)
+ if (scan || !card_top)
{
struct dev_list *l;
- int new_app = 0;
+ int new_card = 0;
/* Scan the devices to find new device(s). */
err = apdu_dev_list_start (opt.reader_port, &l);
if (err)
{
- npth_mutex_unlock (&app_list_lock);
+ npth_mutex_unlock (&card_list_lock);
return err;
}
@@ -408,7 +608,7 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app,
int slot;
int periodical_check_needed_this;
- slot = apdu_open_reader (l, !app_top);
+ slot = apdu_open_reader (l, !card_top);
if (slot < 0)
break;
@@ -422,7 +622,7 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app,
{
err = app_new_register (slot, ctrl, name,
periodical_check_needed_this);
- new_app++;
+ new_card++;
}
if (err)
@@ -432,76 +632,144 @@ select_application (ctrl_t ctrl, const char *name, app_t *r_app,
apdu_dev_list_finish (l);
/* If new device(s), kick the scdaemon loop. */
- if (new_app)
+ if (new_card)
scd_kick_the_loop ();
}
- for (a = app_top; a; a = a->next)
+ for (card = card_top; card; card = card->next)
{
- lock_app (a, ctrl);
+ lock_card (card, ctrl);
if (serialno_bin == NULL)
break;
- if (a->serialnolen == serialno_bin_len
- && !memcmp (a->serialno, serialno_bin, a->serialnolen))
+ if (card->serialnolen == serialno_bin_len
+ && !memcmp (card->serialno, serialno_bin, card->serialnolen))
break;
- unlock_app (a);
- a_prev = a;
+ unlock_card (card);
+ card_prev = card;
}
- if (a)
+ if (card)
{
- err = check_conflict (a, name);
+ err = check_application_conflict (card, name, NULL, 0);
if (!err)
{
- a->ref_count++;
- *r_app = a;
- if (a_prev)
+ /* Note: We do not use card_ref as we are already locked. */
+ card->ref_count++;
+ *r_card = card;
+ if (card_prev)
{
- a_prev->next = a->next;
- a->next = app_top;
- app_top = a;
+ card_prev->next = card->next;
+ card->next = card_top;
+ card_top = card;
}
- }
- unlock_app (a);
+
+ ctrl->current_apptype = card->app ? card->app->apptype : 0;
+ }
+ unlock_card (card);
}
else
err = gpg_error (GPG_ERR_ENODEV);
- npth_mutex_unlock (&app_list_lock);
+ npth_mutex_unlock (&card_list_lock);
return err;
}
+/* This function needs to be called with the NAME of the new
+ * application to be selected on CARD. On success the application is
+ * added to the list of the card's active applications as currently
+ * 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;
+ app_t app = NULL;
+ int i;
+
+ req_apptype = apptype_from_name (name);
+ if (!req_apptype)
+ err = gpg_error (GPG_ERR_NOT_FOUND);
+
+ card = ctrl->card_ctx;
+ if (!card)
+ return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
+
+ err = lock_card (card, ctrl);
+ if (err)
+ return err;
+
+ /* 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;
+ }
+ app = NULL;
+
+ /* 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;
+ }
+
+ /* 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))
+ err = app_priority_list[i].select_func (app);
+ }
+ 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;
+ ctrl->current_apptype = app->apptype;
+ log_error ("added app '%s' to the card context\n", strapptype(app->apptype));
+
+ leave:
+ unlock_card (card);
+ xfree (app);
+ return err;
+}
+
+
char *
get_supported_applications (void)
{
- const char *list[] = {
- "openpgp",
- "piv",
- "nks",
- "p15",
- "geldkarte",
- "dinsig",
- "sc-hsm",
- /* Note: "undefined" is not listed here because it needs special
- treatment by the client. */
- NULL
- };
int idx;
size_t nbytes;
char *buffer, *p;
+ const char *s;
- for (nbytes=1, idx=0; list[idx]; idx++)
- nbytes += strlen (list[idx]) + 1 + 1;
+ for (nbytes=1, idx=0; (s=app_priority_list[idx].name); idx++)
+ nbytes += strlen (s) + 1 + 1;
buffer = xtrymalloc (nbytes);
if (!buffer)
return NULL;
- for (p=buffer, idx=0; list[idx]; idx++)
- if (is_app_allowed (list[idx]))
- p = stpcpy (stpcpy (p, list[idx]), ":\n");
+ for (p=buffer, idx=0; (s=app_priority_list[idx].name); idx++)
+ if (is_app_allowed (s))
+ p = stpcpy (stpcpy (p, s), ":\n");
*p = 0;
return buffer;
@@ -510,62 +778,89 @@ get_supported_applications (void)
/* Deallocate the application. */
static void
-deallocate_app (app_t app)
+deallocate_card (card_t card)
{
- app_t a, a_prev = NULL;
+ card_t c, c_prev = NULL;
+ app_t a, anext;
- for (a = app_top; a; a = a->next)
- if (a == app)
+ for (c = card_top; c; c = c->next)
+ if (c == card)
{
- if (a_prev == NULL)
- app_top = a->next;
+ if (c_prev == NULL)
+ card_top = c->next;
else
- a_prev->next = a->next;
+ c_prev->next = c->next;
break;
}
else
- a_prev = a;
+ c_prev = c;
- if (app->ref_count)
- log_error ("trying to release context used yet (%d)\n", app->ref_count);
+ if (card->ref_count)
+ log_error ("releasing still used card context (%d)\n", card->ref_count);
- if (app->fnc.deinit)
+ for (a = card->app; a; a = anext)
{
- app->fnc.deinit (app);
- app->fnc.deinit = NULL;
+ if (a->fnc.deinit)
+ {
+ a->fnc.deinit (a);
+ a->fnc.deinit = NULL;
+ }
+ anext = a->next;
+ xfree (a);
}
- xfree (app->serialno);
+ scd_clear_current_app (card);
- unlock_app (app);
- xfree (app);
+ xfree (card->serialno);
+ unlock_card (card);
+ xfree (card);
+}
+
+
+/* Increment the reference counter of CARD. Returns CARD. */
+card_t
+card_ref (card_t card)
+{
+ lock_card (card, NULL);
+ ++card->ref_count;
+ unlock_card (card);
+ return card;
}
-/* Free the resources associated with the application APP. APP is
- allowed to be NULL in which case this is a no-op. Note that we are
- using reference counting to track the users of the application and
- actually deferring the deallocation to allow for a later reuse by
- a new connection. */
+
+/* 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. */
void
-release_application (app_t app, int locked_already)
+card_unref (card_t card)
{
- if (!app)
+ if (!card)
return;
- /* We don't deallocate app here. Instead, we keep it. This is
+ /* We don't deallocate CARD here. Instead, we keep it. This is
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. */
- if (!locked_already)
- lock_app (app, NULL);
+ lock_card (card, NULL);
+ card_unref_locked (card);
+ unlock_card (card);
+}
+
+
+/* This is the same as card_unref but assumes that CARD is already
+ * locked. */
+void
+card_unref_locked (card_t card)
+{
+ if (!card)
+ return;
- if (!app->ref_count)
- log_bug ("trying to release an already released context\n");
+ if (!card->ref_count)
+ log_bug ("tried to release an already released card context\n");
- --app->ref_count;
- if (!locked_already)
- unlock_app (app);
+ --card->ref_count;
}
@@ -585,30 +880,30 @@ release_application (app_t app, int locked_already)
All other serial number not starting with FF are used as they are.
*/
gpg_error_t
-app_munge_serialno (app_t app)
+app_munge_serialno (card_t card)
{
- if (app->serialnolen && app->serialno[0] == 0xff)
+ if (card->serialnolen && card->serialno[0] == 0xff)
{
/* The serial number starts with our special prefix. This
requires that we put our default prefix "FF0000" in front. */
- unsigned char *p = xtrymalloc (app->serialnolen + 3);
+ unsigned char *p = xtrymalloc (card->serialnolen + 3);
if (!p)
return gpg_error_from_syserror ();
memcpy (p, "\xff\0", 3);
- memcpy (p+3, app->serialno, app->serialnolen);
- app->serialnolen += 3;
- xfree (app->serialno);
- app->serialno = p;
+ memcpy (p+3, card->serialno, card->serialnolen);
+ card->serialnolen += 3;
+ xfree (card->serialno);
+ card->serialno = p;
}
- else if (!app->serialnolen)
+ else if (!card->serialnolen)
{
unsigned char *p = xtrymalloc (3);
if (!p)
return gpg_error_from_syserror ();
memcpy (p, "\xff\x7f", 3);
- app->serialnolen = 3;
- xfree (app->serialno);
- app->serialno = p;
+ card->serialnolen = 3;
+ xfree (card->serialno);
+ card->serialno = p;
}
return 0;
}
@@ -619,52 +914,129 @@ app_munge_serialno (app_t app)
returned as a malloced string (hex encoded) in SERIAL. Caller must
free SERIAL unless the function returns an error. */
char *
-app_get_serialno (app_t app)
+card_get_serialno (card_t card)
{
char *serial;
- if (!app)
+ if (!card)
return NULL;
- if (!app->serialnolen)
+ if (!card->serialnolen)
serial = xtrystrdup ("FF7F00");
else
- serial = bin2hex (app->serialno, app->serialnolen, NULL);
+ serial = bin2hex (card->serialno, card->serialnolen, NULL);
return serial;
}
+/* Same as card_get_serialno but takes an APP object. */
+char *
+app_get_serialno (app_t app)
+{
+ if (!app || !app->card)
+ return NULL;
+ return card_get_serialno (app->card);
+}
+
+
+/* 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
+ * CARD->app. Thus function must be called with the card lock held. */
+static gpg_error_t
+maybe_switch_app (ctrl_t ctrl, card_t card)
+{
+ gpg_error_t err;
+ app_t app, app_prev;
+
+ 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. */
+ ctrl->current_apptype = card->app->apptype;
+ return 0;
+ }
+ log_debug ("card=%p want=%s card->app=%s\n",
+ card, strapptype (ctrl->current_apptype),
+ strapptype (card->app->apptype));
+ app_dump_state ();
+ 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;
+ if (!app)
+ return gpg_error (GPG_ERR_WRONG_CARD);
+
+ if (!app->fnc.reselect)
+ {
+ log_error ("oops: reselect function missing for '%s'\n",
+ strapptype(app->apptype));
+ return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
+ }
+ err = app->fnc.reselect (app, ctrl);
+ if (err)
+ {
+ log_error ("error re-selecting '%s': %s\n",
+ strapptype(app->apptype), gpg_strerror (err));
+ return err;
+ }
+ /* Swap APP with the head of the app list. Note that APP is not the
+ * head of the list. */
+ app_prev->next = app->next;
+ app->next = card->app;
+ card->app = app;
+ ctrl->current_apptype = app->apptype;
+ log_error ("switched to '%s'\n", strapptype(app->apptype));
+
+ return 0;
+}
+
/* Write out the application specific status lines for the LEARN
command. */
gpg_error_t
-app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
+app_write_learn_status (card_t card, ctrl_t ctrl, unsigned int flags)
{
gpg_error_t err;
+ app_t app;
- if (!app)
+ if (!card)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->fnc.learn_status)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- /* We do not send CARD and APPTYPE if only keypairinfo is requested. */
- if (!(flags &1))
+ err = lock_card (card, ctrl);
+ if (err)
+ return err;
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.learn_status)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
{
- if (app->cardtype)
- send_status_direct (ctrl, "CARDTYPE", app->cardtype);
- if (app->cardversion)
- send_status_printf (ctrl, "CARDVERSION", "%X", app->cardversion);
- if (app->apptype)
- send_status_direct (ctrl, "APPTYPE", app->apptype);
- if (app->appversion)
- send_status_printf (ctrl, "APPVERSION", "%X", app->appversion);
+ app = card->app;
+
+ /* We do not send CARD and APPTYPE if only keypairinfo is requested. */
+ if (!(flags &1))
+ {
+ if (card->cardtype)
+ send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
+ if (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);
+ /* FIXME: Send info for the other active apps of the card? */
+ }
+
+ err = app->fnc.learn_status (app, ctrl, flags);
}
- err = lock_app (app, ctrl);
- if (err)
- return err;
- err = app->fnc.learn_status (app, ctrl, flags);
- unlock_app (app);
+ unlock_card (card);
return err;
}
@@ -674,35 +1046,39 @@ app_write_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
buffer put into CERT and the length of the certificate put into
CERTLEN. */
gpg_error_t
-app_readcert (app_t app, ctrl_t ctrl, const char *certid,
+app_readcert (card_t card, ctrl_t ctrl, const char *certid,
unsigned char **cert, size_t *certlen)
{
gpg_error_t err;
- if (!app)
+ if (!card)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.readcert)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.readcert (app, certid, cert, certlen);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.readcert)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.readcert (card->app, certid, cert, certlen);
+
+ unlock_card (card);
return err;
}
/* Read the key with ID KEYID. On success a canonical encoded
- 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.
-
- This function might not be supported by all applications. */
+ * 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
+ * PK; this makse send if the APP_READKEY_FLAG_INFO has also been set.
+ *
+ * This function might not be supported by all applications. */
gpg_error_t
-app_readkey (app_t app, ctrl_t ctrl, const char *keyid,
+app_readkey (card_t card, ctrl_t ctrl, const char *keyid, unsigned int flags,
unsigned char **pk, size_t *pklen)
{
gpg_error_t err;
@@ -712,93 +1088,102 @@ app_readkey (app_t app, ctrl_t ctrl, const char *keyid,
if (pklen)
*pklen = 0;
- if (!app || !keyid || !pk || !pklen)
+ if (!card || !keyid)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.readkey)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err= app->fnc.readkey (app, keyid, pk, pklen);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.readkey)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.readkey (card->app, ctrl, keyid, flags, pk, pklen);
+
+ unlock_card (card);
return err;
}
/* Perform a GETATTR operation. */
gpg_error_t
-app_getattr (app_t app, ctrl_t ctrl, const char *name)
+app_getattr (card_t card, ctrl_t ctrl, const char *name)
{
gpg_error_t err;
- if (!app || !name || !*name)
+ if (!card || !name || !*name)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
+ err = lock_card (card, ctrl);
+ if (err)
+ return err;
- if (app->cardtype && name && !strcmp (name, "CARDTYPE"))
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (name && !strcmp (name, "CARDTYPE"))
{
- send_status_direct (ctrl, "CARDTYPE", app->cardtype);
- return 0;
+ send_status_direct (ctrl, "CARDTYPE", strcardtype (card->cardtype));
}
- if (app->apptype && name && !strcmp (name, "APPTYPE"))
+ else if (name && !strcmp (name, "APPTYPE"))
{
- send_status_direct (ctrl, "APPTYPE", app->apptype);
- return 0;
+ send_status_direct (ctrl, "APPTYPE", strapptype (card->app->apptype));
}
- if (name && !strcmp (name, "SERIALNO"))
+ else if (name && !strcmp (name, "SERIALNO"))
{
char *serial;
- serial = app_get_serialno (app);
+ serial = card_get_serialno (card);
if (!serial)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- send_status_direct (ctrl, "SERIALNO", serial);
- xfree (serial);
- return 0;
+ err = gpg_error (GPG_ERR_INV_VALUE);
+ else
+ {
+ send_status_direct (ctrl, "SERIALNO", serial);
+ xfree (serial);
+ }
}
+ else if (!card->app->fnc.getattr)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.getattr (card->app, ctrl, name);
- if (!app->fnc.getattr)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
- if (err)
- return err;
- err = app->fnc.getattr (app, ctrl, name);
- unlock_app (app);
+ unlock_card (card);
return err;
}
+
/* Perform a SETATTR operation. */
gpg_error_t
-app_setattr (app_t app, ctrl_t ctrl, const char *name,
+app_setattr (card_t card, ctrl_t ctrl, const char *name,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *value, size_t valuelen)
{
gpg_error_t err;
- if (!app || !name || !*name || !value)
+ if (!card || !name || !*name || !value)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.setattr)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.setattr)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.setattr (card->app, name, pincb, pincb_arg,
+ value, valuelen);
+
+ unlock_card (card);
return err;
}
+
/* 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. */
gpg_error_t
-app_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
+app_sign (card_t card, ctrl_t ctrl, const char *keyidstr, int hashalgo,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
@@ -806,31 +1191,35 @@ app_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
{
gpg_error_t err;
- if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
+ if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.sign)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.sign (app, keyidstr, hashalgo,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.sign)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.sign (card->app, keyidstr, hashalgo,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation sign result: %s\n", gpg_strerror (err));
return err;
}
+
/* 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. */
gpg_error_t
-app_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
+app_auth (card_t card, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
@@ -838,20 +1227,23 @@ app_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
{
gpg_error_t err;
- if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
+ if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.auth)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.auth (app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.auth)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.auth (card->app, keyidstr,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation auth result: %s\n", gpg_strerror (err));
return err;
@@ -862,7 +1254,7 @@ app_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
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. */
gpg_error_t
-app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
+app_decipher (card_t card, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const void *indata, size_t indatalen,
@@ -873,21 +1265,24 @@ app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
*r_info = 0;
- if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
+ if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.decipher)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.decipher (app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen,
- r_info);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.decipher)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.decipher (card->app, keyidstr,
+ pincb, pincb_arg,
+ indata, indatalen,
+ outdata, outdatalen,
+ r_info);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation decipher result: %s\n", gpg_strerror (err));
return err;
@@ -896,26 +1291,29 @@ app_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
/* Perform the WRITECERT operation. */
gpg_error_t
-app_writecert (app_t app, ctrl_t ctrl,
- const char *certidstr,
- gpg_error_t (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *data, size_t datalen)
+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)
{
gpg_error_t err;
- if (!app || !certidstr || !*certidstr || !pincb)
+ if (!card || !certidstr || !*certidstr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.writecert)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.writecert (app, ctrl, certidstr,
- pincb, pincb_arg, data, datalen);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.writecert)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.writecert (card->app, ctrl, certidstr,
+ pincb, pincb_arg, data, datalen);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation writecert result: %s\n", gpg_strerror (err));
return err;
@@ -924,7 +1322,7 @@ app_writecert (app_t app, ctrl_t ctrl,
/* Perform the WRITEKEY operation. */
gpg_error_t
-app_writekey (app_t app, ctrl_t ctrl,
+app_writekey (card_t card, ctrl_t ctrl,
const char *keyidstr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
@@ -932,45 +1330,51 @@ app_writekey (app_t app, ctrl_t ctrl,
{
gpg_error_t err;
- if (!app || !keyidstr || !*keyidstr || !pincb)
+ if (!card || !keyidstr || !*keyidstr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.writekey)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.writekey (app, ctrl, keyidstr, flags,
- pincb, pincb_arg, keydata, keydatalen);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.writekey)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.writekey (card->app, ctrl, keyidstr, flags,
+ pincb, pincb_arg, keydata, keydatalen);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation writekey result: %s\n", gpg_strerror (err));
return err;
}
-/* Perform a SETATTR operation. */
+/* Perform a GENKEY operation. */
gpg_error_t
-app_genkey (app_t app, ctrl_t ctrl, const char *keynostr,
+app_genkey (card_t card, ctrl_t ctrl, const char *keynostr,
const char *keytype, unsigned int flags, time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
gpg_error_t err;
- if (!app || !keynostr || !*keynostr || !pincb)
+ if (!card || !keynostr || !*keynostr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.genkey)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.genkey (app, ctrl, keynostr, keytype, flags,
- createtime, pincb, pincb_arg);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.genkey)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.genkey (card->app, ctrl, keynostr, keytype, flags,
+ createtime, pincb, pincb_arg);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation genkey result: %s\n", gpg_strerror (err));
return err;
@@ -981,44 +1385,51 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr,
directly accesses the card without any application specific
wrapper. */
gpg_error_t
-app_get_challenge (app_t app, ctrl_t ctrl, size_t nbytes, unsigned char *buffer)
+app_get_challenge (card_t card, ctrl_t ctrl,
+ size_t nbytes, unsigned char *buffer)
{
gpg_error_t err;
- if (!app || !nbytes || !buffer)
+ if (!card || !nbytes || !buffer)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = iso7816_get_challenge (app->slot, nbytes, buffer);
- unlock_app (app);
+
+ if (!card->ref_count)
+ err = gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
+ else
+ err = iso7816_get_challenge (card->slot, nbytes, buffer);
+
+ unlock_card (card);
return err;
}
-
/* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */
gpg_error_t
-app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
+app_change_pin (card_t card, ctrl_t ctrl, const char *chvnostr,
unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
gpg_error_t err;
- if (!app || !chvnostr || !*chvnostr || !pincb)
+ if (!card || !chvnostr || !*chvnostr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.change_pin)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.change_pin (app, ctrl, chvnostr, flags, pincb, pincb_arg);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.change_pin)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.change_pin (card->app, ctrl,
+ chvnostr, flags, pincb, pincb_arg);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation change_pin result: %s\n", gpg_strerror (err));
return err;
@@ -1029,28 +1440,32 @@ app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
be used to initialize a the PIN cache for long lasting other
operations. Its use is highly application dependent. */
gpg_error_t
-app_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr,
+app_check_pin (card_t card, ctrl_t ctrl, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg)
{
gpg_error_t err;
- if (!app || !keyidstr || !*keyidstr || !pincb)
+ if (!card || !keyidstr || !*keyidstr || !pincb)
return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->ref_count)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.check_pin)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- err = lock_app (app, ctrl);
+ err = lock_card (card, ctrl);
if (err)
return err;
- err = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg);
- unlock_app (app);
+
+ if ((err = maybe_switch_app (ctrl, card)))
+ ;
+ else if (!card->app->fnc.check_pin)
+ err = gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+ else
+ err = card->app->fnc.check_pin (card->app, keyidstr, pincb, pincb_arg);
+
+ unlock_card (card);
if (opt.verbose)
log_info ("operation check_pin result: %s\n", gpg_strerror (err));
return err;
}
+
static void
report_change (int slot, int old_status, int cur_status)
{
@@ -1110,26 +1525,27 @@ report_change (int slot, int old_status, int cur_status)
xfree (homestr);
}
+
int
scd_update_reader_status_file (void)
{
- app_t a, app_next;
+ card_t card, card_next;
int periodical_check_needed = 0;
- npth_mutex_lock (&app_list_lock);
- for (a = app_top; a; a = app_next)
+ npth_mutex_lock (&card_list_lock);
+ for (card = card_top; card; card = card_next)
{
int sw;
unsigned int status;
- lock_app (a, NULL);
- app_next = a->next;
+ lock_card (card, NULL);
+ card_next = card->next;
- if (a->reset_requested)
+ if (card->reset_requested)
status = 0;
else
{
- sw = apdu_get_status (a->slot, 0, &status);
+ sw = apdu_get_status (card->slot, 0, &status);
if (sw == SW_HOST_NO_READER)
{
/* Most likely the _reader_ has been unplugged. */
@@ -1138,40 +1554,41 @@ scd_update_reader_status_file (void)
else if (sw)
{
/* Get status failed. Ignore that. */
- if (a->periodical_check_needed)
+ if (card->periodical_check_needed)
periodical_check_needed = 1;
- unlock_app (a);
+ unlock_card (card);
continue;
}
}
- if (a->card_status != status)
+ if (card->card_status != status)
{
- report_change (a->slot, a->card_status, status);
- send_client_notifications (a, status == 0);
+ report_change (card->slot, card->card_status, status);
+ send_client_notifications (card, status == 0);
if (status == 0)
{
- log_debug ("Removal of a card: %d\n", a->slot);
- apdu_close_reader (a->slot);
- deallocate_app (a);
+ log_debug ("Removal of a card: %d\n", card->slot);
+ apdu_close_reader (card->slot);
+ deallocate_card (card);
}
else
{
- a->card_status = status;
- if (a->periodical_check_needed)
+ card->card_status = status;
+ if (card->periodical_check_needed)
periodical_check_needed = 1;
- unlock_app (a);
+ unlock_card (card);
}
}
else
{
- if (a->periodical_check_needed)
+ if (card->periodical_check_needed)
periodical_check_needed = 1;
- unlock_app (a);
+ unlock_card (card);
}
}
- npth_mutex_unlock (&app_list_lock);
+
+ npth_mutex_unlock (&card_list_lock);
return periodical_check_needed;
}
@@ -1185,7 +1602,7 @@ initialize_module_command (void)
{
gpg_error_t err;
- if (npth_mutex_init (&app_list_lock, NULL))
+ if (npth_mutex_init (&card_list_lock, NULL))
{
err = gpg_error_from_syserror ();
log_error ("app: error initializing mutex: %s\n", gpg_strerror (err));
@@ -1195,20 +1612,115 @@ initialize_module_command (void)
return apdu_init ();
}
-void
+
+/* 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;
+}
+
+
+/* Send status lines with the serialno of all inserted cards. */
+gpg_error_t
app_send_card_list (ctrl_t ctrl)
{
- app_t a;
+ gpg_error_t err;
+ card_t c;
char buf[65];
+ card_t *cardlist = NULL;
+ int n, ncardlist;
+
+ npth_mutex_lock (&card_list_lock);
+ for (n=0, c = card_top; c; c = c->next)
+ n++;
+ cardlist = xtrycalloc (n, sizeof *cardlist);
+ if (!cardlist)
+ {
+ 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);
- npth_mutex_lock (&app_list_lock);
- for (a = app_top; a; a = a->next)
+ for (n=0; n < ncardlist; n++)
{
- if (DIM (buf) < 2 * a->serialnolen + 1)
+ if (DIM (buf) < 2 * cardlist[n]->serialnolen + 1)
continue;
- bin2hex (a->serialno, a->serialnolen, buf);
+ bin2hex (cardlist[n]->serialno, cardlist[n]->serialnolen, buf);
send_status_direct (ctrl, "SERIALNO", buf);
}
- npth_mutex_unlock (&app_list_lock);
+
+ err = 0;
+
+ leave:
+ npth_mutex_unlock (&card_list_lock);
+ xfree (cardlist);
+ return err;
+}
+
+
+/* Execute an action for each app. ACTION can be one of:
+ *
+ * - 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
+ * keys will be send and the return value is NULL.
+ *
+ * - 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
+ * keygrip is available or KEYGRIP_STR is NULL, NULL is returned.
+ */
+card_t
+app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str)
+{
+ gpg_error_t err;
+ card_t c;
+ app_t a;
+
+ npth_mutex_lock (&card_list_lock);
+
+ for (c = card_top; c; c = c->next)
+ for (a = c->app; a; a = a->next)
+ if (a->fnc.with_keygrip)
+ {
+ if (!lock_card (c, ctrl))
+ {
+ err = a->fnc.with_keygrip (a, ctrl, action, keygrip_str);
+ unlock_card (c);
+ if (!err)
+ goto leave_the_loop;
+ }
+ }
+
+ leave_the_loop:
+
+ /* FIXME: Add app switching logic. The above code assumes that the
+ * actions can be performend without switching. This needs to be
+ * checked. */
+
+ /* Force switching of the app if the selected one is not the current
+ * one. Changing the current apptype is sufficient to do this. */
+ if (c && c->app && c->app->apptype != a->apptype)
+ ctrl->current_apptype = a->apptype;
+
+ npth_mutex_unlock (&card_list_lock);
+ return c;
}
diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c
index 69df17355..d762490c8 100644
--- a/scd/ccid-driver.c
+++ b/scd/ccid-driver.c
@@ -110,26 +110,12 @@
/* CCID command timeout. */
#define CCID_CMD_TIMEOUT (5*1000)
-/* OpenPGPcard v2.1 requires huge timeout for key generation. */
-#define CCID_CMD_TIMEOUT_LONGER (60*1000)
/* Depending on how this source is used we either define our error
- output to go to stderr or to the GnuPG based logging functions. We
- use the latter when GNUPG_MAJOR_VERSION or GNUPG_SCD_MAIN_HEADER
- are defined. */
-#if defined(GNUPG_MAJOR_VERSION) || defined(GNUPG_SCD_MAIN_HEADER)
-
-#if defined(GNUPG_SCD_MAIN_HEADER)
-# include GNUPG_SCD_MAIN_HEADER
-#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */
-# include "options.h"
-# include "util.h"
-# include "memory.h"
-# include "cardglue.h"
-# else /* This is the modularized GnuPG 1.9 or later. */
+ * output to go to stderr or to the GnuPG based logging functions. We
+ * use the latter when GNUPG_MAJOR_VERSION is defined. */
+#if defined(GNUPG_MAJOR_VERSION)
# include "scdaemon.h"
-#endif
-
# define DEBUGOUT(t) do { if (debug_level) \
log_debug (DRVNAME t); } while (0)
@@ -175,7 +161,7 @@
# define DEBUGOUT_LF() do { if (debug_level) \
putc ('\n', stderr); } while (0)
-#endif /* This source not used by scdaemon. */
+#endif /* This source is not used by scdaemon. */
#ifndef EAGAIN
@@ -960,7 +946,7 @@ get_escaped_usb_string (libusb_device_handle *idev, int idx,
rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN,
LIBUSB_REQUEST_GET_DESCRIPTOR,
(LIBUSB_DT_STRING << 8), 0,
- (char*)buf, sizeof buf, 1000 /* ms timeout */);
+ buf, sizeof buf, 1000 /* ms timeout */);
#ifdef USE_NPTH
npth_protect ();
#endif
@@ -975,7 +961,7 @@ get_escaped_usb_string (libusb_device_handle *idev, int idx,
rc = libusb_control_transfer (idev, LIBUSB_ENDPOINT_IN,
LIBUSB_REQUEST_GET_DESCRIPTOR,
(LIBUSB_DT_STRING << 8) + idx, langid,
- (char*)buf, sizeof buf, 1000 /* ms timeout */);
+ buf, sizeof buf, 1000 /* ms timeout */);
#ifdef USE_NPTH
npth_protect ();
#endif
@@ -1490,7 +1476,9 @@ intr_cb (struct libusb_transfer *transfer)
{
DEBUGOUT ("CCID: card removed\n");
handle->powered_off = 1;
+#if defined(GNUPG_MAJOR_VERSION)
scd_kick_the_loop ();
+#endif
}
else
{
@@ -1505,7 +1493,9 @@ intr_cb (struct libusb_transfer *transfer)
device_removed:
DEBUGOUT ("CCID: device removed\n");
handle->powered_off = 1;
+#if defined(GNUPG_MAJOR_VERSION)
scd_kick_the_loop ();
+#endif
}
}
@@ -1731,31 +1721,37 @@ ccid_require_get_status (ccid_driver_t handle)
return 1;
}
-
-static void
-do_close_reader (ccid_driver_t handle)
+static int
+send_power_off (ccid_driver_t handle)
{
int rc;
unsigned char msg[100];
size_t msglen;
unsigned char seqno;
- if (!handle->powered_off)
- {
- msg[0] = PC_to_RDR_IccPowerOff;
- msg[5] = 0; /* slot */
- msg[6] = seqno = handle->seqno++;
- msg[7] = 0; /* RFU */
- msg[8] = 0; /* RFU */
- msg[9] = 0; /* RFU */
- set_msg_len (msg, 0);
- msglen = 10;
+ msg[0] = PC_to_RDR_IccPowerOff;
+ msg[5] = 0; /* slot */
+ msg[6] = seqno = handle->seqno++;
+ msg[7] = 0; /* RFU */
+ msg[8] = 0; /* RFU */
+ msg[9] = 0; /* RFU */
+ set_msg_len (msg, 0);
+ msglen = 10;
- rc = bulk_out (handle, msg, msglen, 0);
- if (!rc)
- bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
- seqno, 2000, 0);
- }
+ rc = bulk_out (handle, msg, msglen, 0);
+ if (!rc)
+ bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+ seqno, 2000, 0);
+ return rc;
+}
+
+static void
+do_close_reader (ccid_driver_t handle)
+{
+ int rc;
+
+ if (!handle->powered_off)
+ send_power_off (handle);
if (handle->transfer)
{
@@ -1907,7 +1903,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen,
npth_unprotect ();
#endif
rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out,
- (char*)msg, msglen, &transferred,
+ msg, msglen, &transferred,
5000 /* ms timeout */);
#ifdef USE_NPTH
npth_protect ();
@@ -1954,7 +1950,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
npth_unprotect ();
#endif
rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in,
- (char*)buffer, length, &msglen, timeout);
+ buffer, length, &msglen, timeout);
#ifdef USE_NPTH
npth_protect ();
#endif
@@ -2074,7 +2070,9 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
{
DEBUGOUT ("CCID: card inactive/removed\n");
handle->powered_off = 1;
+#if defined(GNUPG_MAJOR_VERSION)
scd_kick_the_loop ();
+#endif
}
}
@@ -2088,7 +2086,7 @@ static int
abort_cmd (ccid_driver_t handle, int seqno)
{
int rc;
- char dummybuf[8];
+ unsigned char dummybuf[8];
unsigned char msg[100];
int msglen;
@@ -2139,7 +2137,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
npth_unprotect ();
#endif
rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_out,
- (char*)msg, msglen, &transferred,
+ msg, msglen, &transferred,
5000 /* ms timeout */);
#ifdef USE_NPTH
npth_protect ();
@@ -2157,7 +2155,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
npth_unprotect ();
#endif
rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in,
- (char*)msg, sizeof msg, &msglen,
+ msg, sizeof msg, &msglen,
5000 /*ms timeout*/);
#ifdef USE_NPTH
npth_protect ();
@@ -2278,7 +2276,7 @@ ccid_poll (ccid_driver_t handle)
int i, j;
rc = libusb_interrupt_transfer (handle->idev, handle->ep_intr,
- (char*)msg, sizeof msg, &msglen,
+ msg, sizeof msg, &msglen,
0 /* ms timeout */ );
if (rc == LIBUSB_ERROR_TIMEOUT)
return 0;
@@ -2611,6 +2609,21 @@ ccid_get_atr (ccid_driver_t handle,
NULL, 0, NULL))
goto again;
}
+ else if (statusbits == 0 && CCID_COMMAND_FAILED (msg))
+ {
+ /* Card was active already, and something went wrong with
+ PC_to_RDR_IccPowerOn command. It may be baud-rate mismatch
+ between the card and the reader. To recover from this state,
+ send PC_to_RDR_IccPowerOff command to reset the card and try
+ again.
+ */
+ rc = send_power_off (handle);
+ if (rc)
+ return rc;
+
+ statusbits = 1;
+ goto again;
+ }
else if (CCID_COMMAND_FAILED (msg))
return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -2977,7 +2990,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
bit 7 1
bit 6 1
bit 5 clear=request,set=response
- bit 4..0 0 = resyncronisation request
+ bit 4..0 0 = resynchronization request
1 = information field size request
2 = abort request
3 = extension of BWT request
@@ -3094,7 +3107,7 @@ ccid_transceive (ccid_driver_t handle,
msg[0] = PC_to_RDR_XfrBlock;
msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++;
- msg[7] = 4; /* bBWI */
+ msg[7] = (wait_more ? wait_more : 1); /* bBWI */
msg[8] = 0; /* RFU */
msg[9] = 0; /* RFU */
set_msg_len (msg, tpdulen);
@@ -3120,7 +3133,7 @@ ccid_transceive (ccid_driver_t handle,
msg = recv_buffer;
rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
via_escape? RDR_to_PC_Escape : RDR_to_PC_DataBlock, seqno,
- wait_more? CCID_CMD_TIMEOUT_LONGER: CCID_CMD_TIMEOUT, 0);
+ (wait_more ? wait_more : 1) * CCID_CMD_TIMEOUT, 0);
if (rc)
return rc;
@@ -3150,6 +3163,7 @@ ccid_transceive (ccid_driver_t handle,
(!(msg[pcboff] & 0x80) && (msg[pcboff] & 0x20)?
" [more]":""));
+ wait_more = 0;
if (!(tpdu[1] & 0x80))
{ /* This is an I-block. */
retries = 0;
@@ -3295,9 +3309,7 @@ ccid_transceive (ccid_driver_t handle,
/* Wait time extension request. */
unsigned char bwi = tpdu[3];
- /* Check if it's unusual value which can't be expressed in ATR. */
- if (bwi > 15)
- wait_more = 1;
+ wait_more = bwi;
msg = send_buffer;
tpdu = msg + hdrlen;
@@ -3726,7 +3738,7 @@ print_result (int rc, const unsigned char *data, size_t length)
int
main (int argc, char **argv)
{
- int rc;
+ gpg_error_t err;
ccid_driver_t ccid;
int slotstat;
unsigned char result[512];
@@ -3735,6 +3747,8 @@ main (int argc, char **argv)
int verify_123456 = 0;
int did_verify = 0;
int no_poll = 0;
+ int idx_max;
+ struct ccid_dev_table *ccid_table;
if (argc)
{
@@ -3778,27 +3792,36 @@ main (int argc, char **argv)
break;
}
- rc = ccid_open_reader (&ccid, argc? *argv:NULL, NULL);
- if (rc)
+ err = ccid_dev_scan (&idx_max, &ccid_table);
+ if (err)
+ return 1;
+
+ if (idx_max == 0)
+ return 1;
+
+ err = ccid_open_reader (argc? *argv:NULL, 0, ccid_table, &ccid, NULL);
+ if (err)
return 1;
+ ccid_dev_scan_finish (ccid_table, idx_max);
+
if (!no_poll)
ccid_poll (ccid);
fputs ("getting ATR ...\n", stderr);
- rc = ccid_get_atr (ccid, NULL, 0, NULL);
- if (rc)
+ err = ccid_get_atr (ccid, NULL, 0, NULL);
+ if (err)
{
- print_error (rc);
+ print_error (err);
return 1;
}
if (!no_poll)
ccid_poll (ccid);
fputs ("getting slot status ...\n", stderr);
- rc = ccid_slot_status (ccid, &slotstat, 1);
- if (rc)
+ err = ccid_slot_status (ccid, &slotstat, 1);
+ if (err)
{
- print_error (rc);
+ print_error (err);
return 1;
}
@@ -3809,10 +3832,10 @@ main (int argc, char **argv)
{
static unsigned char apdu[] = {
0, 0xA4, 4, 0, 6, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01};
- rc = ccid_transceive (ccid,
- apdu, sizeof apdu,
- result, sizeof result, &resultlen);
- print_result (rc, result, resultlen);
+ err = ccid_transceive (ccid,
+ apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (err, result, resultlen);
}
@@ -3822,9 +3845,9 @@ main (int argc, char **argv)
fputs ("getting OpenPGP DO 0x65 ....\n", stderr);
{
static unsigned char apdu[] = { 0, 0xCA, 0, 0x65, 254 };
- rc = ccid_transceive (ccid, apdu, sizeof apdu,
- result, sizeof result, &resultlen);
- print_result (rc, result, resultlen);
+ err = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (err, result, resultlen);
}
if (!no_pinpad)
@@ -3834,22 +3857,18 @@ main (int argc, char **argv)
if (!no_pinpad)
{
static unsigned char apdu[] = { 0, 0x20, 0, 0x81 };
+ pininfo_t pininfo = { 0, 0, 0 };
-
- if (ccid_transceive_secure (ccid,
- apdu, sizeof apdu,
- 1, 0, 0, 0,
+ if (ccid_transceive_secure (ccid, apdu, sizeof apdu, &pininfo,
NULL, 0, NULL))
fputs ("can't verify using a PIN-Pad reader\n", stderr);
else
{
- fputs ("verifying CHV1 using the PINPad ....\n", stderr);
+ fputs ("verifying CHV1 using the PINPad ....\n", stderr);
- rc = ccid_transceive_secure (ccid,
- apdu, sizeof apdu,
- 1, 0, 0, 0,
- result, sizeof result, &resultlen);
- print_result (rc, result, resultlen);
+ err = ccid_transceive_secure (ccid, apdu, sizeof apdu, &pininfo,
+ result, sizeof result, &resultlen);
+ print_result (err, result, resultlen);
did_verify = 1;
}
}
@@ -3860,20 +3879,20 @@ main (int argc, char **argv)
{
static unsigned char apdu[] = {0, 0x20, 0, 0x81,
6, '1','2','3','4','5','6'};
- rc = ccid_transceive (ccid, apdu, sizeof apdu,
- result, sizeof result, &resultlen);
- print_result (rc, result, resultlen);
+ err = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (err, result, resultlen);
}
}
- if (!rc)
+ if (!err)
{
fputs ("getting OpenPGP DO 0x5E ....\n", stderr);
{
static unsigned char apdu[] = { 0, 0xCA, 0, 0x5E, 254 };
- rc = ccid_transceive (ccid, apdu, sizeof apdu,
- result, sizeof result, &resultlen);
- print_result (rc, result, resultlen);
+ err = ccid_transceive (ccid, apdu, sizeof apdu,
+ result, sizeof result, &resultlen);
+ print_result (err, result, resultlen);
}
}
@@ -3884,7 +3903,7 @@ main (int argc, char **argv)
/*
* Local Variables:
- * compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c"
+ * compile-command: "gcc -DTEST -DGPGRT_ENABLE_ES_MACROS -DHAVE_NPTH -DUSE_NPTH -Wall -I/usr/include/libusb-1.0 -I/usr/local/include -lusb-1.0 -g ccid-driver.c -lnpth -lgpg-error"
* End:
*/
#endif /*TEST*/
diff --git a/scd/command.c b/scd/command.c
index 0d1a5cd3f..0096ca96d 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -33,7 +33,6 @@
#include "scdaemon.h"
#include <assuan.h>
#include <ksba.h>
-#include "app-common.h"
#include "iso7816.h"
#include "apdu.h" /* Required for apdu_*_reader (). */
#include "atr.h"
@@ -145,10 +144,10 @@ hex_to_buffer (const char *string, size_t *r_length)
static void
do_reset (ctrl_t ctrl, int send_reset)
{
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
- if (app)
- app_reset (app, ctrl, IS_LOCKED (ctrl)? 0: send_reset);
+ if (card)
+ card_reset (card, ctrl, IS_LOCKED (ctrl)? 0: send_reset);
/* If we hold a lock, unlock now. */
if (locked_session && ctrl->server_local == locked_session)
@@ -157,6 +156,8 @@ do_reset (ctrl_t ctrl, int send_reset)
log_info ("implicitly unlocking due to RESET\n");
}
}
+
+
static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
@@ -211,38 +212,50 @@ open_card (ctrl_t ctrl)
if ( IS_LOCKED (ctrl) )
return gpg_error (GPG_ERR_LOCKED);
- if (ctrl->app_ctx)
+ if (ctrl->card_ctx)
return 0;
- return select_application (ctrl, NULL, &ctrl->app_ctx, 0, NULL, 0);
+ return select_application (ctrl, NULL, &ctrl->card_ctx, 0, NULL, 0);
}
/* Explicitly open a card for a specific use of APPTYPE or SERIALNO. */
static gpg_error_t
-open_card_with_request (ctrl_t ctrl, const char *apptype, const char *serialno)
+open_card_with_request (ctrl_t ctrl,
+ const char *apptypestr, const char *serialno)
{
gpg_error_t err;
unsigned char *serialno_bin = NULL;
size_t serialno_bin_len = 0;
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
+
+ if (serialno)
+ serialno_bin = hex_to_buffer (serialno, &serialno_bin_len);
/* If we are already initialized for one specific application we
need to check that the client didn't requested a specific
application different from the one in use before we continue. */
- if (apptype && ctrl->app_ctx)
- return check_application_conflict (apptype, ctrl->app_ctx);
-
- /* Re-scan USB devices. Release APP, before the scan. */
- ctrl->app_ctx = NULL;
- release_application (app, 0);
+ if (apptypestr && ctrl->card_ctx)
+ {
+ err = check_application_conflict (ctrl->card_ctx, apptypestr,
+ serialno_bin, serialno_bin_len);
+ if (gpg_err_code (err) == GPG_ERR_FALSE)
+ {
+ /* Different application but switching is supported. */
+ err = select_additional_application (ctrl, apptypestr);
+ }
+ goto leave;
+ }
- if (serialno)
- serialno_bin = hex_to_buffer (serialno, &serialno_bin_len);
+ /* Re-scan USB devices. Release CARD, before the scan. */
+ /* FIXME: Is a card_unref sufficient or do we need to deallocate? */
+ ctrl->card_ctx = NULL;
+ card_unref (card);
- err = select_application (ctrl, apptype, &ctrl->app_ctx, 1,
+ err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1,
serialno_bin, serialno_bin_len);
- xfree (serialno_bin);
+ leave:
+ xfree (serialno_bin);
return err;
}
@@ -313,7 +326,7 @@ cmd_serialno (assuan_context_t ctx, char *line)
c->server_local->card_removed = 0;
}
- serial = app_get_serialno (ctrl->app_ctx);
+ serial = card_get_serialno (ctrl->card_ctx);
if (!serial)
return gpg_error (GPG_ERR_INV_VALUE);
@@ -411,20 +424,20 @@ cmd_learn (assuan_context_t ctx, char *line)
{
const char *reader;
char *serial;
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
- if (!app)
+ if (!card)
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
- reader = apdu_get_reader_name (app->slot);
+ reader = apdu_get_reader_name (card->slot);
if (!reader)
return out_of_core ();
send_status_direct (ctrl, "READER", reader);
/* No need to free the string of READER. */
- serial = app_get_serialno (ctrl->app_ctx);
+ serial = card_get_serialno (ctrl->card_ctx);
if (!serial)
- return gpg_error (GPG_ERR_INV_VALUE);
+ return gpg_error (GPG_ERR_INV_VALUE);
rc = assuan_write_status (ctx, "SERIALNO", serial);
if (rc < 0)
@@ -461,7 +474,7 @@ cmd_learn (assuan_context_t ctx, char *line)
/* Let the application print out its collection of useful status
information. */
if (!rc)
- rc = app_write_learn_status (ctrl->app_ctx, ctrl, only_keypairinfo);
+ rc = app_write_learn_status (ctrl->card_ctx, ctrl, only_keypairinfo);
return rc;
}
@@ -484,7 +497,7 @@ cmd_readcert (assuan_context_t ctx, char *line)
return rc;
line = xstrdup (line); /* Need a copy of the line. */
- rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
+ rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert);
if (rc)
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
xfree (line);
@@ -502,19 +515,20 @@ cmd_readcert (assuan_context_t ctx, char *line)
static const char hlp_readkey[] =
- "READKEY [--advanced] <keyid>|<oid>\n"
+ "READKEY [--advanced] [--info[-only]] <keyid>|<oid>\n"
"\n"
"Return the public key for the given cert or key ID as a standard\n"
- "S-expression.\n"
- "In --advanced mode it returns the S-expression in advanced format.\n"
- "\n"
- "Note that this function may even be used on a locked card.";
+ "S-expression. With --advanced the S-expression is returned in\n"
+ "advanced format. With --info a KEYPAIRINFO status line is also\n"
+ "emitted; with --info-only the regular output is suppressed.";
static gpg_error_t
cmd_readkey (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
int advanced = 0;
+ int opt_info = 0;
+ int opt_nokey = 0;
unsigned char *cert = NULL;
unsigned char *pk = NULL;
size_t ncert, pklen;
@@ -524,6 +538,10 @@ cmd_readkey (assuan_context_t ctx, char *line)
if (has_option (line, "--advanced"))
advanced = 1;
+ if (has_option (line, "--info"))
+ opt_info = 1;
+ if (has_option (line, "--info-only"))
+ opt_info = opt_nokey = 1;
line = skip_options (line);
line = xstrdup (line); /* Need a copy of the line. */
@@ -531,14 +549,16 @@ cmd_readkey (assuan_context_t ctx, char *line)
/* If the application supports the READKEY function we use that.
Otherwise we use the old way by extracting it from the
certificate. */
- rc = app_readkey (ctrl->app_ctx, ctrl, line, &pk, &pklen);
+ rc = app_readkey (ctrl->card_ctx, ctrl, line,
+ opt_info? APP_READKEY_FLAG_INFO : 0,
+ opt_nokey? NULL : &pk, &pklen);
if (!rc)
; /* Okay, got that key. */
else if (gpg_err_code (rc) == GPG_ERR_UNSUPPORTED_OPERATION
|| gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
{
/* Fall back to certificate reading. */
- rc = app_readcert (ctrl->app_ctx, ctrl, line, &cert, &ncert);
+ rc = app_readcert (ctrl->card_ctx, ctrl, line, &cert, &ncert);
if (rc)
{
log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
@@ -551,6 +571,26 @@ cmd_readkey (assuan_context_t ctx, char *line)
gpg_strerror (rc));
goto leave;
}
+
+ if (opt_info)
+ {
+ char keygripstr[KEYGRIP_LEN*2+1];
+
+ rc = app_help_get_keygrip_string_pk (pk, pklen, keygripstr);
+ if (rc)
+ {
+ log_error ("app_help_get_keygrip_string failed: %s\n",
+ gpg_strerror (rc));
+ goto leave;
+ }
+
+ /* FIXME: Using LINE is not correct because it might be an
+ * OID and has not been canonicalized (i.e. uppercased). */
+ send_status_info (ctrl, "KEYPAIRINFO",
+ keygripstr, strlen (keygripstr),
+ line, strlen (line),
+ NULL, (size_t)0);
+ }
}
else
{
@@ -558,7 +598,9 @@ cmd_readkey (assuan_context_t ctx, char *line)
goto leave;
}
- if (advanced)
+ if (opt_nokey)
+ ;
+ else if (advanced)
{
gcry_sexp_t s_key;
unsigned char *pkadv;
@@ -728,6 +770,8 @@ cmd_pksign (assuan_context_t ctx, char *line)
size_t outdatalen;
char *keyidstr;
int hash_algo;
+ card_t card;
+ int direct = 0;
if (has_option (line, "--hash=rmd160"))
hash_algo = GCRY_MD_RMD160;
@@ -760,11 +804,30 @@ cmd_pksign (assuan_context_t ctx, char *line)
if (!keyidstr)
return out_of_core ();
- rc = app_sign (ctrl->app_ctx, ctrl,
- keyidstr, hash_algo,
- pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
+ /* When it's a keygrip, we directly use the card, with no change of
+ ctrl->card_ctx. */
+ if (strlen (keyidstr) == 40)
+ {
+ card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr);
+ direct = 1;
+ }
+ else
+ card = ctrl->card_ctx;
+
+ if (card)
+ {
+ if (direct)
+ card_ref (card);
+ rc = app_sign (card, ctrl,
+ keyidstr, hash_algo,
+ pin_cb, ctx,
+ ctrl->in_data.value, ctrl->in_data.valuelen,
+ &outdata, &outdatalen);
+ if (direct)
+ card_unref (card);
+ }
+ else
+ rc = gpg_error (GPG_ERR_NO_SECKEY);
xfree (keyidstr);
if (rc)
@@ -793,11 +856,13 @@ cmd_pkauth (assuan_context_t ctx, char *line)
unsigned char *outdata;
size_t outdatalen;
char *keyidstr;
+ card_t card;
+ int direct = 0;
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
/* We have to use a copy of the key ID because the function may use
@@ -807,9 +872,29 @@ cmd_pkauth (assuan_context_t ctx, char *line)
if (!keyidstr)
return out_of_core ();
- rc = app_auth (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
+ /* When it's a keygrip, we directly use CARD, with no change of
+ ctrl->card_ctx. */
+ if (strlen (keyidstr) == 40)
+ {
+ card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr);
+ direct = 1;
+ }
+ else
+ card = ctrl->card_ctx;
+
+ if (card)
+ {
+ if (direct)
+ card_ref (card);
+ rc = app_auth (card, ctrl, keyidstr, pin_cb, ctx,
+ ctrl->in_data.value, ctrl->in_data.valuelen,
+ &outdata, &outdatalen);
+ if (direct)
+ card_unref (card);
+ }
+ else
+ rc = gpg_error (GPG_ERR_NO_SECKEY);
+
xfree (keyidstr);
if (rc)
{
@@ -838,6 +923,8 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
size_t outdatalen;
char *keyidstr;
unsigned int infoflags;
+ card_t card;
+ int direct = 0;
if ((rc = open_card (ctrl)))
return rc;
@@ -845,9 +932,29 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
keyidstr = xtrystrdup (line);
if (!keyidstr)
return out_of_core ();
- rc = app_decipher (ctrl->app_ctx, ctrl, keyidstr, pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen, &infoflags);
+
+ /* When it's a keygrip, we directly use CARD, with no change of
+ ctrl->card_ctx. */
+ if (strlen (keyidstr) == 40)
+ {
+ card = app_do_with_keygrip (ctrl, KEYGRIP_ACTION_LOOKUP, keyidstr);
+ direct = 1;
+ }
+ else
+ card = ctrl->card_ctx;
+
+ if (card)
+ {
+ if (direct)
+ card_ref (card);
+ rc = app_decipher (card, ctrl, keyidstr, pin_cb, ctx,
+ ctrl->in_data.value, ctrl->in_data.valuelen,
+ &outdata, &outdatalen, &infoflags);
+ if (direct)
+ card_unref (card);
+ }
+ else
+ rc = gpg_error (GPG_ERR_NO_SECKEY);
xfree (keyidstr);
if (rc)
@@ -905,7 +1012,7 @@ cmd_getattr (assuan_context_t ctx, char *line)
/* FIXME: Applications should not return sensitive data if the card
is locked. */
- rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
+ rc = app_getattr (ctrl->card_ctx, ctrl, keyword);
return rc;
}
@@ -967,7 +1074,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
assuan_end_confidential (ctx);
if (!err)
{
- err = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx,
+ err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx,
value, nbytes);
wipememory (value, nbytes);
xfree (value);
@@ -977,7 +1084,7 @@ cmd_setattr (assuan_context_t ctx, char *orig_line)
else
{
nbytes = percent_plus_unescape_inplace (line, 0);
- err = app_setattr (ctrl->app_ctx, ctrl, keyword, pin_cb, ctx,
+ err = app_setattr (ctrl->card_ctx, ctrl, keyword, pin_cb, ctx,
(const unsigned char*)line, nbytes);
}
@@ -1018,7 +1125,7 @@ cmd_writecert (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
certid = xtrystrdup (certid);
@@ -1035,7 +1142,7 @@ cmd_writecert (assuan_context_t ctx, char *line)
}
/* Write the certificate to the card. */
- rc = app_writecert (ctrl->app_ctx, ctrl, certid,
+ rc = app_writecert (ctrl->card_ctx, ctrl, certid,
pin_cb, ctx, certdata, certdatalen);
xfree (certid);
xfree (certdata);
@@ -1080,7 +1187,7 @@ cmd_writekey (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
keyid = xtrystrdup (keyid);
@@ -1098,7 +1205,7 @@ cmd_writekey (assuan_context_t ctx, char *line)
}
/* Write the key to the card. */
- rc = app_writekey (ctrl->app_ctx, ctrl, keyid, force? 1:0,
+ rc = app_writekey (ctrl->card_ctx, ctrl, keyid, force? 1:0,
pin_cb, ctx, keydata, keydatalen);
xfree (keyid);
xfree (keydata);
@@ -1172,7 +1279,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
if ((err = open_card (ctrl)))
goto leave;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
keyref = keyref_buffer = xtrystrdup (keyref);
@@ -1181,7 +1288,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
err = gpg_error_from_syserror ();
goto leave;
}
- err = app_genkey (ctrl->app_ctx, ctrl, keyref, opt_algo,
+ err = app_genkey (ctrl->card_ctx, ctrl, keyref, opt_algo,
force? APP_GENKEY_FLAG_FORCE : 0,
timestamp, pin_cb, ctx);
@@ -1216,14 +1323,14 @@ cmd_random (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
buffer = xtrymalloc (nbytes);
if (!buffer)
return out_of_core ();
- rc = app_get_challenge (ctrl->app_ctx, ctrl, nbytes, buffer);
+ rc = app_get_challenge (ctrl->card_ctx, ctrl, nbytes, buffer);
if (!rc)
{
rc = assuan_send_data (ctx, buffer, nbytes);
@@ -1277,13 +1384,13 @@ cmd_passwd (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
chvnostr = xtrystrdup (chvnostr);
if (!chvnostr)
return out_of_core ();
- rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
+ rc = app_change_pin (ctrl->card_ctx, ctrl, chvnostr, flags, pin_cb, ctx);
if (rc)
log_error ("command passwd failed: %s\n", gpg_strerror (rc));
xfree (chvnostr);
@@ -1334,7 +1441,7 @@ cmd_checkpin (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
/* We have to use a copy of the key ID because the function may use
@@ -1344,7 +1451,7 @@ cmd_checkpin (assuan_context_t ctx, char *line)
if (!idstr)
return out_of_core ();
- rc = app_check_pin (ctrl->app_ctx, ctrl, idstr, pin_cb, ctx);
+ rc = app_check_pin (ctrl->card_ctx, ctrl, idstr, pin_cb, ctx);
xfree (idstr);
if (rc)
log_error ("app_check_pin failed: %s\n", gpg_strerror (rc));
@@ -1525,7 +1632,7 @@ cmd_getinfo (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- app_send_card_list (ctrl);
+ rc = app_send_card_list (ctrl);
}
else
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
@@ -1547,14 +1654,14 @@ static gpg_error_t
cmd_restart (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- app_t app = ctrl->app_ctx;
+ card_t card = ctrl->card_ctx;
(void)line;
- if (app)
+ if (card)
{
- ctrl->app_ctx = NULL;
- release_application (app, 0);
+ ctrl->card_ctx = NULL;
+ card_unref (card);
}
if (locked_session && ctrl->server_local == locked_session)
{
@@ -1576,10 +1683,10 @@ cmd_disconnect (assuan_context_t ctx, char *line)
(void)line;
- if (!ctrl->app_ctx)
+ if (!ctrl->card_ctx)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- apdu_disconnect (ctrl->app_ctx->slot);
+ apdu_disconnect (ctrl->card_ctx->slot);
return 0;
}
@@ -1608,7 +1715,7 @@ static gpg_error_t
cmd_apdu (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- app_t app;
+ card_t card;
int rc;
unsigned char *apdu;
size_t apdulen;
@@ -1638,8 +1745,8 @@ cmd_apdu (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl)))
return rc;
- app = ctrl->app_ctx;
- if (!app)
+ card = ctrl->card_ctx;
+ if (!card)
return gpg_error (GPG_ERR_CARD_NOT_PRESENT);
if (with_atr)
@@ -1648,7 +1755,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
size_t atrlen;
char hexbuf[400];
- atr = apdu_get_atr (app->slot, &atrlen);
+ atr = apdu_get_atr (card->slot, &atrlen);
if (!atr || atrlen > sizeof hexbuf - 2 )
{
rc = gpg_error (GPG_ERR_INV_CARD);
@@ -1693,7 +1800,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
unsigned char *result = NULL;
size_t resultlen;
- rc = apdu_send_direct (app->slot, exlen,
+ rc = apdu_send_direct (card->slot, exlen,
apdu, apdulen, handle_more,
NULL, &result, &resultlen);
if (rc)
@@ -1728,6 +1835,87 @@ cmd_killscd (assuan_context_t ctx, char *line)
}
+static const char hlp_keyinfo[] =
+ "KEYINFO [--list] [--data] <keygrip>\n"
+ "\n"
+ "Return information about the key specified by the KEYGRIP. If the\n"
+ "key is not available GPG_ERR_NOT_FOUND is returned. If the option\n"
+ "--list is given the keygrip is ignored and information about all\n"
+ "available keys are returned. Unless --data is given, the\n"
+ "information is returned as a status line using the format:\n"
+ "\n"
+ " KEYINFO <keygrip> T <serialno> <idstr>\n"
+ "\n"
+ "KEYGRIP is the keygrip.\n"
+ "\n"
+ "SERIALNO is an ASCII string with the serial number of the\n"
+ " smartcard. If the serial number is not known a single\n"
+ " dash '-' is used instead.\n"
+ "\n"
+ "IDSTR is the IDSTR used to distinguish keys on a smartcard. If it\n"
+ " is not known a dash is used instead.\n"
+ "\n"
+ "More information may be added in the future.";
+static gpg_error_t
+cmd_keyinfo (assuan_context_t ctx, char *line)
+{
+ int list_mode;
+ int opt_data;
+ int action;
+ char *keygrip_str;
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ card_t card;
+
+ list_mode = has_option (line, "--list");
+ opt_data = has_option (line, "--data");
+ line = skip_options (line);
+
+ if (list_mode)
+ keygrip_str = NULL;
+ else
+ keygrip_str = line;
+
+ if (opt_data)
+ action = KEYGRIP_ACTION_SEND_DATA;
+ else
+ action = KEYGRIP_ACTION_WRITE_STATUS;
+
+ card = app_do_with_keygrip (ctrl, action, keygrip_str);
+
+ if (!list_mode && !card)
+ return gpg_error (GPG_ERR_NOT_FOUND);
+ return 0;
+}
+
+
+/* Send a keyinfo string as used by the KEYGRIP_ACTION_SEND_DATA. If
+ * DATA is true the string is emitted as a data line, else as a status
+ * line. */
+void
+send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
+ const char *serialno, const char *idstr)
+{
+ char *string;
+ assuan_context_t ctx = ctrl->server_local->assuan_ctx;
+
+ string = xtryasprintf ("%s T %s %s%s", keygrip_str,
+ serialno? serialno : "-",
+ idstr? idstr : "-",
+ data? "\n" : "");
+
+ if (!string)
+ return;
+
+ if (!data)
+ assuan_write_status (ctx, "KEYINFO", string);
+ else
+ assuan_send_data (ctx, string, strlen (string));
+
+ xfree (string);
+ return;
+}
+
+
/* Tell the assuan library about our commands */
static int
@@ -1763,6 +1951,7 @@ register_commands (assuan_context_t ctx)
{ "DISCONNECT", cmd_disconnect,hlp_disconnect },
{ "APDU", cmd_apdu, hlp_apdu },
{ "KILLSCD", cmd_killscd, hlp_killscd },
+ { "KEYINFO", cmd_keyinfo, hlp_keyinfo },
{ NULL }
};
int i, rc;
@@ -1890,6 +2079,20 @@ scd_command_handler (ctrl_t ctrl, int fd)
}
+/* Clear the current application info for CARD from all sessions.
+ * This is used while deallocating a card. */
+void
+scd_clear_current_app (card_t card)
+{
+ struct server_local_s *sl;
+
+ for (sl=session_list; sl; sl = sl->next_session)
+ {
+ if (sl->ctrl_backlink->card_ctx == card)
+ sl->ctrl_backlink->current_apptype = APPTYPE_NONE;
+ }
+}
+
/* Send a line with status information via assuan and escape all given
buffers. The variable elements are pairs of (char *, size_t),
terminated with a (NULL, 0). */
@@ -2001,9 +2204,10 @@ popup_prompt (void *opaque, int on)
}
-/* Helper to send the clients a status change notification. */
+/* Helper to send the clients a status change notification. Note that
+ * this function assumes that APP is already locked. */
void
-send_client_notifications (app_t app, int removal)
+send_client_notifications (card_t card, int removal)
{
struct {
pid_t pid;
@@ -2018,7 +2222,7 @@ send_client_notifications (app_t app, int removal)
struct server_local_s *sl;
for (sl=session_list; sl; sl = sl->next_session)
- if (sl->ctrl_backlink && sl->ctrl_backlink->app_ctx == app)
+ if (sl->ctrl_backlink && sl->ctrl_backlink->card_ctx == card)
{
pid_t pid;
#ifdef HAVE_W32_SYSTEM
@@ -2029,9 +2233,9 @@ send_client_notifications (app_t app, int removal)
if (removal)
{
- sl->ctrl_backlink->app_ctx = NULL;
+ sl->ctrl_backlink->card_ctx = NULL;
sl->card_removed = 1;
- release_application (app, 1);
+ card_unref_locked (card);
}
if (!sl->event_signal || !sl->assuan_ctx)
diff --git a/scd/iso7816.c b/scd/iso7816.c
index d9f3336c7..954aa3d4a 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -23,20 +23,9 @@
#include <stdlib.h>
#include <string.h>
-#if defined(GNUPG_SCD_MAIN_HEADER)
-#include GNUPG_SCD_MAIN_HEADER
-#elif GNUPG_MAJOR_VERSION == 1
-/* This is used with GnuPG version < 1.9. The code has been source
- copied from the current GnuPG >= 1.9 and is maintained over
- there. */
-#include "options.h"
-#include "errors.h"
-#include "memory.h"
-#include "../common/util.h"
-#include "../common/i18n.h"
-#else /* GNUPG_MAJOR_VERSION != 1 */
-#include "scdaemon.h"
-#endif /* GNUPG_MAJOR_VERSION != 1 */
+#if defined(GNUPG_MAJOR_VERSION)
+# include "scdaemon.h"
+#endif /*GNUPG_MAJOR_VERSION*/
#include "iso7816.h"
#include "apdu.h"
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 507108db0..e89569e5d 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -46,7 +46,6 @@
#include "../common/i18n.h"
#include "../common/sysutils.h"
-#include "app-common.h"
#include "iso7816.h"
#include "apdu.h"
#include "ccid-driver.h"
@@ -98,6 +97,7 @@ enum cmd_and_opt_values
oAllowAdmin,
oDenyAdmin,
oDisableApplication,
+ oApplicationPriority,
oEnablePinpadVarlen,
oListenBacklog
};
@@ -154,6 +154,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oDenyAdmin, "deny-admin",
N_("deny the use of admin card commands")),
ARGPARSE_s_s (oDisableApplication, "disable-application", "@"),
+ ARGPARSE_s_s (oApplicationPriority, "application-priority",
+ N_("|LIST|Change the application priority to LIST")),
ARGPARSE_s_n (oEnablePinpadVarlen, "enable-pinpad-varlen",
N_("use variable length input for pinpad")),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
@@ -436,6 +438,7 @@ main (int argc, char **argv )
struct assuan_malloc_hooks malloc_hooks;
int res;
npth_t pipecon_handler;
+ const char *application_priority = NULL;
early_system_init ();
set_strusage (my_strusage);
@@ -616,6 +619,10 @@ main (int argc, char **argv )
add_to_strlist (&opt.disabled_applications, pargs.r.ret_str);
break;
+ case oApplicationPriority:
+ application_priority = pargs.r.ret_str;
+ break;
+
case oEnablePinpadVarlen: opt.enable_pinpad_varlen = 1; break;
case oListenBacklog:
@@ -720,6 +727,7 @@ main (int argc, char **argv )
es_printf ("disable-pinpad:%lu:\n", GC_OPT_FLAG_NONE );
es_printf ("card-timeout:%lu:%d:\n", GC_OPT_FLAG_DEFAULT, 0);
es_printf ("enable-pinpad-varlen:%lu:\n", GC_OPT_FLAG_NONE );
+ es_printf ("application-priority:%lu:\n", GC_OPT_FLAG_NONE );
scd_exit (0);
}
@@ -739,6 +747,9 @@ main (int argc, char **argv )
log_debug ("... okay\n");
}
+ if (application_priority)
+ app_update_priority_list (application_priority);
+
if (pipe_server)
{
/* This is the simple pipe based server */
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index 73589ade8..b709b1cbc 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -30,6 +30,8 @@
#include <gcrypt.h>
#include "../common/util.h"
#include "../common/sysutils.h"
+#include "app-common.h"
+
/* To convey some special hash algorithms we use algorithm numbers
reserved for application use. */
@@ -84,6 +86,7 @@ struct
#define DBG_READER (opt.debug & DBG_READER_VALUE)
struct server_local_s;
+struct card_ctx_s;
struct app_ctx_s;
struct server_control_s
@@ -101,7 +104,12 @@ struct server_control_s
associated. Note that this is shared with the other connections:
All connections accessing the same reader are using the same
application context. */
- struct app_ctx_s *app_ctx;
+ struct card_ctx_s *card_ctx;
+
+ /* The currently active application for this context. We need to
+ * know this for cards which are able to switch on the fly between
+ * apps. */
+ apptype_t current_apptype;
/* Helper to store the value we are going to sign */
struct
@@ -111,7 +119,6 @@ struct server_control_s
} in_data;
};
-typedef struct app_ctx_s *app_t;
/*-- scdaemon.c --*/
void scd_exit (int rc);
@@ -120,14 +127,20 @@ const char *scd_get_socket_name (void);
/*-- command.c --*/
gpg_error_t initialize_module_command (void);
int scd_command_handler (ctrl_t, int);
+void scd_clear_current_app (card_t card);
void send_status_info (ctrl_t ctrl, const char *keyword, ...)
GPGRT_ATTR_SENTINEL(1);
void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args);
gpg_error_t send_status_printf (ctrl_t ctrl, const char *keyword,
const char *format, ...) GPGRT_ATTR_PRINTF(3,4);
+void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str,
+ const char *serialno, const char *idstr);
void popup_prompt (void *opaque, int on);
-void send_client_notifications (app_t app, int removal);
+
+/* Take care: this function assumes that CARD is locked. */
+void send_client_notifications (card_t card, int removal);
+
void scd_kick_the_loop (void);
int get_active_connection_count (void);