aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--scd/app.c131
1 files changed, 96 insertions, 35 deletions
diff --git a/scd/app.c b/scd/app.c
index 1f142ea32..6ac18272b 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -29,49 +29,78 @@
#include "app-common.h"
#include "apdu.h"
#include "iso7816.h"
-#include "dynload.h"
+#include "tlv.h"
-static char *default_reader_port;
-void
-app_set_default_reader_port (const char *portstr)
-{
- xfree (default_reader_port);
- default_reader_port = portstr? xstrdup (portstr): NULL;
-}
-
-
-/* The select the best fitting application and return a context.
- Returns NULL if no application was found or no card is present. */
+/* 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. SLOT identifies the reader device. Returns
+ NULL if no application was found or no card is present. */
APP
-select_application (void)
+select_application (ctrl_t ctrl, int slot, const char *name)
{
- int slot;
int rc;
APP app;
-
- slot = apdu_open_reader (default_reader_port);
- if (slot == -1)
- {
- log_error ("card reader not available\n");
- return NULL;
- }
+ unsigned char *result = NULL;
+ size_t resultlen;
app = xtrycalloc (1, sizeof *app);
if (!app)
{
rc = out_of_core ();
log_info ("error allocating context: %s\n", gpg_strerror (rc));
- /*apdu_close_reader (slot);*/
return NULL;
}
-
app->slot = slot;
- rc = app_select_openpgp (app, &app->serialno, &app->serialnolen);
+
+ /* Fixme: We should now first check whether a card is at all
+ present. */
+
+ /* Try to read the GDO file first to get a default serial number. */
+ rc = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
+ if (!rc)
+ rc = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
+ if (!rc)
+ rc = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
+ if (!rc)
+ {
+ size_t n;
+ const unsigned char *p;
+
+ p = find_tlv (result, resultlen, 0x5A, &n);
+ if (p && n && n >= (resultlen - (p - result)))
+ {
+ /* 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;
+ }
+ else
+ xfree (result);
+ result = NULL;
+ }
+
+
+ rc = gpg_error (GPG_ERR_NOT_FOUND);
+
+ if (!name || !strcmp (name, "openpgp"))
+ rc = app_select_openpgp (app);
+ if (rc && (!name || !strcmp (name, "nks")))
+ rc = app_select_nks (app);
+ if (rc && (!name || !strcmp (name, "dinsig")))
+ rc = app_select_dinsig (app);
+ if (rc && name)
+ rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
+
if (rc)
{
-/* apdu_close_reader (slot); */
- log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
+ if (name)
+ log_info ("can't select application `%s': %s\n",
+ name, gpg_strerror (rc));
+ else
+ log_info ("no supported card application found: %s\n",
+ gpg_strerror (rc));
xfree (app);
return NULL;
}
@@ -81,23 +110,36 @@ select_application (void)
}
+void
+release_application (app_t app)
+{
+ if (!app)
+ return;
+
+ xfree (app->serialno);
+ xfree (app);
+}
+
+
/* Retrieve the serial number and the time of the last update of the
card. The serial number is returned as a malloced string (hex
encoded) in SERIAL and the time of update is returned in STAMP. If
no update time is available the returned value is 0. Caller must
- free SERIAL unless the function returns an error. */
+ free SERIAL unless the function returns an error. If STAMP is not
+ of interest, NULL may be passed. */
int
-app_get_serial_and_stamp (APP app, char **serial, time_t *stamp)
+app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
{
unsigned char *buf, *p;
int i;
- if (!app || !serial || !stamp)
+ if (!app || !serial)
return gpg_error (GPG_ERR_INV_VALUE);
*serial = NULL;
- *stamp = 0; /* not available */
+ if (stamp)
+ *stamp = 0; /* not available */
buf = xtrymalloc (app->serialnolen * 2 + 1);
if (!buf)
@@ -121,10 +163,34 @@ app_write_learn_status (APP app, CTRL ctrl)
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
if (!app->fnc.learn_status)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+
+ if (app->apptype)
+ send_status_info (ctrl, "APPTYPE",
+ app->apptype, strlen (app->apptype), NULL, 0);
+
return app->fnc.learn_status (app, ctrl);
}
+/* Read the certificate with id CERTID (as returned by learn_status in
+ the CERTINFO status lines) and return it in the freshly allocated
+ buffer put into CERT and the length of the certificate put into
+ CERTLEN. */
+int
+app_readcert (app_t app, const char *certid,
+ unsigned char **cert, size_t *certlen)
+{
+ if (!app)
+ return gpg_error (GPG_ERR_INV_VALUE);
+ if (!app->initialized)
+ return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
+ if (!app->fnc.readcert)
+ return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+
+ return app->fnc.readcert (app, certid, cert, certlen);
+}
+
+
/* Perform a GETATTR operation. */
int
app_getattr (APP app, CTRL ctrl, const char *name)
@@ -317,8 +383,3 @@ app_check_pin (APP app, const char *keyidstr,
return rc;
}
-
-
-
-
-