1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-22 14:57:02 +01:00

scd: Skip S/N reading for the "undefined" application.

* scd/app.c (select_application): Skip serial number reading.
--
(cherry picked from commit 792e137ec7997a0ff5c54ff970611238d28d4ba8)

Resolved conflicts:

	scd/app.c: Take care of already changed geldkarte/dinsig
	order.
This commit is contained in:
Werner Koch 2011-12-14 18:56:10 +01:00
parent 3ae90ff28c
commit dc941bdaec

141
scd/app.c
View File

@ -69,7 +69,7 @@ print_progress_line (void *opaque, const char *what, int pc, int cur, int tot)
never shares a reader (while performing one command). Returns 0 on never shares a reader (while performing one command). Returns 0 on
success; only then the unlock_reader function must be called after success; only then the unlock_reader function must be called after
returning from the handler. */ returning from the handler. */
static gpg_error_t static gpg_error_t
lock_reader (int slot, ctrl_t ctrl) lock_reader (int slot, ctrl_t ctrl)
{ {
gpg_error_t err; gpg_error_t err;
@ -89,7 +89,7 @@ lock_reader (int slot, ctrl_t ctrl)
lock_table[slot].app = NULL; lock_table[slot].app = NULL;
lock_table[slot].last_app = NULL; lock_table[slot].last_app = NULL;
} }
if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL)) if (!pth_mutex_acquire (&lock_table[slot].lock, 0, NULL))
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();
@ -188,7 +188,7 @@ application_notify_card_reset (int slot)
return; return;
/* FIXME: We are ignoring any error value here. */ /* FIXME: We are ignoring any error value here. */
lock_reader (slot, NULL); lock_reader (slot, NULL);
/* Mark application as non-reusable. */ /* Mark application as non-reusable. */
if (lock_table[slot].app) if (lock_table[slot].app)
@ -204,10 +204,10 @@ application_notify_card_reset (int slot)
lock_table[slot].last_app = NULL; lock_table[slot].last_app = NULL;
deallocate_app (app); deallocate_app (app);
} }
unlock_reader (slot); unlock_reader (slot);
} }
/* This function is used by the serialno command to check for an /* This function is used by the serialno command to check for an
application conflict which may appear if the serialno command is application conflict which may appear if the serialno command is
used to request a specific application and the connection has used to request a specific application and the connection has
@ -241,11 +241,14 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
app_t app = NULL; app_t app = NULL;
unsigned char *result = NULL; unsigned char *result = NULL;
size_t resultlen; size_t resultlen;
int want_undefined;
(void)ctrl; (void)ctrl;
*r_app = NULL; *r_app = NULL;
want_undefined = (name && !strcmp (name, "undefined"));
err = lock_reader (slot, ctrl); err = lock_reader (slot, ctrl);
if (err) if (err)
return err; return err;
@ -287,7 +290,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
lock_table[slot].app = app; lock_table[slot].app = app;
lock_table[slot].last_app = NULL; lock_table[slot].last_app = NULL;
} }
else else
{ {
/* No, this saved application can't be used - deallocate it. */ /* No, this saved application can't be used - deallocate it. */
lock_table[slot].last_app = NULL; lock_table[slot].last_app = NULL;
@ -309,7 +312,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
unlock_reader (slot); unlock_reader (slot);
return 0; /* Okay: We share that one. */ return 0; /* Okay: We share that one. */
} }
/* Need to allocate a new one. */ /* Need to allocate a new one. */
app = xtrycalloc (1, sizeof *app); app = xtrycalloc (1, sizeof *app);
if (!app) if (!app)
@ -325,54 +328,66 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
/* Fixme: We should now first check whether a card is at all /* Fixme: We should now first check whether a card is at all
present. */ present. */
/* Try to read the GDO file first to get a default serial number. */ /* Try to read the GDO file first to get a default serial number.
err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); We skip this if the undefined application has been requested. */
if (!err) if (!want_undefined)
err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
if (!err)
err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
if (!err)
{ {
size_t n; err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
const unsigned char *p; if (!err)
err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
p = find_tlv_unchecked (result, resultlen, 0x5A, &n); if (!err)
if (p) err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
resultlen -= (p-result); if (!err)
if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
{ {
/* The object it does not fit into the buffer. This is an size_t n;
invalid encoding (or the buffer is too short. However, I const unsigned char *p;
have some test cards with such an invalid encoding and
therefore I use this ugly workaround to return something
I can further experiment with. */
log_info ("enabling BMI testcard workaround\n");
n--;
}
if (p && n <= resultlen) p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
{ if (p)
/* The GDO file is pretty short, thus we simply reuse it for resultlen -= (p-result);
storing the serial number. */ if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
memmove (result, p, n); {
app->serialno = result; /* The object it does not fit into the buffer. This is an
app->serialnolen = n; invalid encoding (or the buffer is too short. However, I
err = app_munge_serialno (app); have some test cards with such an invalid encoding and
if (err) therefore I use this ugly workaround to return something
goto leave; I can further experiment with. */
log_info ("enabling BMI testcard workaround\n");
n--;
}
if (p && n <= resultlen)
{
/* The GDO file is pretty short, thus we simply reuse it for
storing the serial number. */
memmove (result, p, n);
app->serialno = result;
app->serialnolen = n;
err = app_munge_serialno (app);
if (err)
goto leave;
}
else
xfree (result);
result = NULL;
} }
else
xfree (result);
result = NULL;
} }
/* For certain error codes, there is no need to try more. */ /* For certain error codes, there is no need to try more. */
if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT
|| gpg_err_code (err) == GPG_ERR_ENODEV) || gpg_err_code (err) == GPG_ERR_ENODEV)
goto leave; goto leave;
/* Figure out the application to use. */ /* Figure out the application to use. */
err = gpg_error (GPG_ERR_NOT_FOUND); if (want_undefined)
{
/* We switch to the "undefined" application only if explicitly
requested. */
app->apptype = "UNDEFINED";
err = 0;
}
else
err = gpg_error (GPG_ERR_NOT_FOUND);
if (err && is_app_allowed ("openpgp") if (err && is_app_allowed ("openpgp")
&& (!name || !strcmp (name, "openpgp"))) && (!name || !strcmp (name, "openpgp")))
@ -428,10 +443,10 @@ get_supported_applications (void)
int idx; int idx;
size_t nbytes; size_t nbytes;
char *buffer, *p; char *buffer, *p;
for (nbytes=1, idx=0; list[idx]; idx++) for (nbytes=1, idx=0; list[idx]; idx++)
nbytes += strlen (list[idx]) + 1 + 1; nbytes += strlen (list[idx]) + 1 + 1;
buffer = xtrymalloc (nbytes); buffer = xtrymalloc (nbytes);
if (!buffer) if (!buffer)
return NULL; return NULL;
@ -508,22 +523,22 @@ release_application (app_t app)
/* The serial number may need some cosmetics. Do it here. This /* The serial number may need some cosmetics. Do it here. This
function shall only be called once after a new serial number has function shall only be called once after a new serial number has
been put into APP->serialno. been put into APP->serialno.
Prefixes we use: Prefixes we use:
FF 00 00 = For serial numbers starting with an FF FF 00 00 = For serial numbers starting with an FF
FF 01 00 = Some german p15 cards return an empty serial number so the FF 01 00 = Some german p15 cards return an empty serial number so the
serial number from the EF(TokenInfo) is used instead. serial number from the EF(TokenInfo) is used instead.
FF 7F 00 = No serialno. FF 7F 00 = No serialno.
All other serial number not starting with FF are used as they are. All other serial number not starting with FF are used as they are.
*/ */
gpg_error_t gpg_error_t
app_munge_serialno (app_t app) app_munge_serialno (app_t app)
{ {
if (app->serialnolen && app->serialno[0] == 0xff) if (app->serialnolen && app->serialno[0] == 0xff)
{ {
/* The serial number starts with our special prefix. This /* The serial number starts with our special prefix. This
requires that we put our default prefix "FF0000" in front. */ requires that we put our default prefix "FF0000" in front. */
unsigned char *p = xtrymalloc (app->serialnolen + 3); unsigned char *p = xtrymalloc (app->serialnolen + 3);
@ -536,7 +551,7 @@ app_munge_serialno (app_t app)
app->serialno = p; app->serialno = p;
} }
else if (!app->serialnolen) else if (!app->serialnolen)
{ {
unsigned char *p = xtrymalloc (3); unsigned char *p = xtrymalloc (3);
if (!p) if (!p)
return gpg_error_from_syserror (); return gpg_error_from_syserror ();
@ -556,7 +571,7 @@ app_munge_serialno (app_t app)
no update time is available the returned value is 0. Caller must no update time is available the returned value is 0. Caller must
free SERIAL unless the function returns an error. If STAMP is not free SERIAL unless the function returns an error. If STAMP is not
of interest, NULL may be passed. */ of interest, NULL may be passed. */
gpg_error_t gpg_error_t
app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp) app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
{ {
char *buf; char *buf;
@ -639,7 +654,7 @@ app_readcert (app_t app, const char *certid,
code returned. code returned.
This function might not be supported by all applications. */ This function might not be supported by all applications. */
gpg_error_t gpg_error_t
app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen) app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
{ {
gpg_error_t err; gpg_error_t err;
@ -665,7 +680,7 @@ app_readkey (app_t app, const char *keyid, unsigned char **pk, size_t *pklen)
/* Perform a GETATTR operation. */ /* Perform a GETATTR operation. */
gpg_error_t gpg_error_t
app_getattr (app_t app, ctrl_t ctrl, const char *name) app_getattr (app_t app, ctrl_t ctrl, const char *name)
{ {
gpg_error_t err; gpg_error_t err;
@ -686,7 +701,7 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name)
char *serial; char *serial;
time_t stamp; time_t stamp;
int rc; int rc;
rc = app_get_serial_and_stamp (app, &serial, &stamp); rc = app_get_serial_and_stamp (app, &serial, &stamp);
if (rc) if (rc)
return rc; return rc;
@ -706,7 +721,7 @@ app_getattr (app_t app, ctrl_t ctrl, const char *name)
} }
/* Perform a SETATTR operation. */ /* Perform a SETATTR operation. */
gpg_error_t gpg_error_t
app_setattr (app_t app, const char *name, app_setattr (app_t app, const char *name,
gpg_error_t (*pincb)(void*, const char *, char **), gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg, void *pincb_arg,
@ -731,7 +746,7 @@ app_setattr (app_t app, const char *name,
/* Create the signature and return the allocated result in OUTDATA. /* 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 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. */ should return the PIN in an allocated buffer and put it into PIN. */
gpg_error_t gpg_error_t
app_sign (app_t app, const char *keyidstr, int hashalgo, app_sign (app_t app, const char *keyidstr, int hashalgo,
gpg_error_t (*pincb)(void*, const char *, char **), gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg, void *pincb_arg,
@ -763,7 +778,7 @@ app_sign (app_t app, const char *keyidstr, int hashalgo,
return the allocated result in OUTDATA. If a PIN is required the 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 PINCB will be used to ask for the PIN; it should return the PIN in
an allocated buffer and put it into PIN. */ an allocated buffer and put it into PIN. */
gpg_error_t gpg_error_t
app_auth (app_t app, const char *keyidstr, app_auth (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **), gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg, void *pincb_arg,
@ -795,7 +810,7 @@ app_auth (app_t app, const char *keyidstr,
/* Decrypt the data in INDATA and return the allocated result in OUTDATA. /* Decrypt the data in INDATA and return the allocated result in OUTDATA.
If a PIN is required the PINCB will be used to ask for the PIN; it 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. */ should return the PIN in an allocated buffer and put it into PIN. */
gpg_error_t gpg_error_t
app_decipher (app_t app, const char *keyidstr, app_decipher (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **), gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg, void *pincb_arg,
@ -881,7 +896,7 @@ app_writekey (app_t app, ctrl_t ctrl,
/* Perform a SETATTR operation. */ /* Perform a SETATTR operation. */
gpg_error_t gpg_error_t
app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags, app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
time_t createtime, time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **), gpg_error_t (*pincb)(void*, const char *, char **),
@ -898,7 +913,7 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
err = lock_reader (app->slot, ctrl); err = lock_reader (app->slot, ctrl);
if (err) if (err)
return err; return err;
err = app->fnc.genkey (app, ctrl, keynostr, flags, err = app->fnc.genkey (app, ctrl, keynostr, flags,
createtime, pincb, pincb_arg); createtime, pincb, pincb_arg);
unlock_reader (app->slot); unlock_reader (app->slot);
if (opt.verbose) if (opt.verbose)
@ -930,7 +945,7 @@ app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer)
/* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */ /* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */
gpg_error_t gpg_error_t
app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode, app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
gpg_error_t (*pincb)(void*, const char *, char **), gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg) void *pincb_arg)
@ -958,7 +973,7 @@ app_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
/* Perform a VERIFY operation without doing anything lese. This may /* Perform a VERIFY operation without doing anything lese. This may
be used to initialze a the PIN cache for long lasting other be used to initialze a the PIN cache for long lasting other
operations. Its use is highly application dependent. */ operations. Its use is highly application dependent. */
gpg_error_t gpg_error_t
app_check_pin (app_t app, const char *keyidstr, app_check_pin (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **), gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg) void *pincb_arg)