diff --git a/scd/ChangeLog b/scd/ChangeLog index 80b244ef1..a527b5da5 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,10 @@ +2004-08-20 Werner Koch + + * app.c (select_application): Fixed serial number extraction and + added the BMI card workaround. + (app_munge_serialno): New. + * app-openpgp.c (app_select_openpgp): Try munging serialno. + 2004-08-05 Werner Koch * scdaemon.c (main): New option --disable-application. diff --git a/scd/app-common.h b/scd/app-common.h index c61bcca60..c15f174bf 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -95,6 +95,7 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); /*-- app.c --*/ app_t select_application (ctrl_t ctrl, int slot, const char *name); void release_application (app_t app); +int app_munge_serialno (app_t app); int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp); int app_write_learn_status (app_t app, ctrl_t ctrl); int app_readcert (app_t app, const char *certid, @@ -159,6 +160,9 @@ int app_select_nks (app_t app); /*-- app-dinsig.c --*/ int app_select_dinsig (app_t app); +/*-- app-p15.c --*/ +int app_select_p15 (app_t app); + #endif diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 3dc015baa..67bc336ec 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -1394,6 +1394,13 @@ app_select_openpgp (APP app) log_info ("got AID: "); log_printhex ("", buffer, buflen); } +#if GNUPG_MAJOR_VERSION != 1 + /* A valid OpenPGP card should never need this but well the test + is cheap. */ + rc = app_number_serialno (app); + if (rc) + goto leave; +#endif app->card_version = buffer[6] << 8; app->card_version |= buffer[7]; diff --git a/scd/app.c b/scd/app.c index b3a13f19a..55fb5861e 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1,5 +1,5 @@ /* app.c - Application selection. - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -45,6 +45,7 @@ is_app_allowed (const char *name) return 1; /* yes */ } + /* 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 @@ -81,31 +82,50 @@ select_application (ctrl_t ctrl, int slot, const char *name) const unsigned char *p; p = find_tlv (result, resultlen, 0x5A, &n); - if (p && n && n >= (resultlen - (p - result))) + if (p) + resultlen -= (p-result); + if (p && n > resultlen && n == 0x0d && resultlen+1 == n) + { + /* The object it 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 + I can further experiment with. */ + log_debug ("enabling BMI testcard workaround\n"); + n--; + } + + if (p && n <= resultlen) { /* The GDO file is pretty short, thus we simply reuse it for storing the serial number. */ memmove (result, p, n); app->serialno = result; app->serialnolen = n; + rc = app_munge_serialno (app); + if (rc) + goto leave; } else xfree (result); result = NULL; } - + rc = gpg_error (GPG_ERR_NOT_FOUND); if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp"))) rc = app_select_openpgp (app); if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks"))) rc = app_select_nks (app); +/* if (rc && is_app_allowed ("p12") && (!name || !strcmp (name, "p12"))) */ +/* rc = app_select_p12 (app); */ if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig"))) rc = app_select_dinsig (app); if (rc && name) rc = gpg_error (GPG_ERR_NOT_SUPPORTED); + leave: if (rc) { if (name) @@ -141,6 +161,39 @@ release_application (app_t app) +/* The serial number may need some cosmetics. Do it here. This + function shall only be called once after a new serial number has + been put into APP->serialno. + + Prefixes we use: + + FF 00 00 = For serial numbers starting with an FF + FF 01 00 = Some german p15 cards return an empty serial number so the + serial number from the EF(TokeInfo is used instead. + + All other serial number not starting with FF are used as they are. +*/ +int +app_munge_serialno (app_t app) +{ + if (app->serialnolen && app->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); + if (!p) + return gpg_error (gpg_err_code_from_errno (errno)); + memcpy (p, "\xff\0", 3); + memcpy (p+3, app->serialno, app->serialnolen); + app->serialnolen += 3; + xfree (app->serialno); + app->serialno = p; + } + return 0; +} + + + /* 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