aboutsummaryrefslogtreecommitdiffstats
path: root/scd/apdu.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <[email protected]>2012-01-03 17:13:19 +0000
committerMarcus Brinkmann <[email protected]>2012-01-03 17:13:19 +0000
commit0868997e186cd847663668f9d7a29806a12da2d2 (patch)
tree73645f778a2d16213723121a76d2b38ca90edfcc /scd/apdu.c
parentAdd lost ChangeLog entry. (diff)
parentSilence gcc warning. (diff)
downloadgnupg-npth.tar.gz
gnupg-npth.zip
Merge branch 'master' into npthnpth
Conflicts: ChangeLog-2011 Makefile.am agent/ChangeLog-2011 agent/gpg-agent.c dirmngr/ChangeLog-2011 dirmngr/dirmngr.c doc/HACKING g13/g13.c po/de.po scd/ChangeLog-2011 scd/apdu.c scd/command.c scd/scdaemon.c scripts/gitlog-to-changelog tools/ChangeLog-2011
Diffstat (limited to 'scd/apdu.c')
-rw-r--r--scd/apdu.c252
1 files changed, 180 insertions, 72 deletions
diff --git a/scd/apdu.c b/scd/apdu.c
index e4ebc3586..e914f7b24 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -465,8 +465,11 @@ apdu_strerror (int rc)
case SW_FILE_NOT_FOUND : return "file not found";
case SW_RECORD_NOT_FOUND:return "record not found";
case SW_REF_NOT_FOUND : return "reference not found";
- case SW_BAD_LC : return "bad Lc";
- case SW_BAD_P0_P1 : return "bad P0 or P1";
+ case SW_NOT_ENOUGH_MEMORY: return "not enough memory space in the file";
+ case SW_INCONSISTENT_LC: return "Lc inconsistent with TLV structure.";
+ case SW_INCORRECT_P0_P1: return "incorrect parameters P0,P1";
+ case SW_BAD_LC : return "Lc inconsistent with P0,P1";
+ case SW_BAD_P0_P1 : return "bad P0,P1";
case SW_INS_NOT_SUP : return "instruction not supported";
case SW_CLA_NOT_SUP : return "class not supported";
case SW_SUCCESS : return "success";
@@ -2052,7 +2055,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
{
int sw;
unsigned char *pin_verify;
- unsigned long len = PIN_VERIFY_STRUCTURE_SIZE;
+ int len = PIN_VERIFY_STRUCTURE_SIZE;
unsigned char result[2];
size_t resultlen = 2;
@@ -2108,12 +2111,23 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
pin_verify[22] = p1; /* abData[3] */
pin_verify[23] = 0x00; /* abData[4] */
+ if (DBG_CARD_IO)
+ log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
+ class, ins, p0, p1, len, pininfo->maxlen);
+
sw = control_pcsc (slot, reader_table[slot].pcsc.verify_ioctl,
pin_verify, len, result, &resultlen);
xfree (pin_verify);
if (sw || resultlen < 2)
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
sw = (result[resultlen-2] << 8) | result[resultlen-1];
+ {
+ log_error ("control_pcsc failed: %d\n", sw);
+ return sw? sw: SW_HOST_INCOMPLETE_CARD_RESPONSE;
+ }
+ sw = (result[resultlen-2] << 8) | result[resultlen-1];
+ if (DBG_CARD_IO)
+ log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen);
return sw;
}
@@ -2125,7 +2139,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
{
int sw;
unsigned char *pin_modify;
- unsigned long len = PIN_MODIFY_STRUCTURE_SIZE;
+ int len = PIN_MODIFY_STRUCTURE_SIZE;
unsigned char result[2];
size_t resultlen = 2;
@@ -2192,12 +2206,21 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
pin_modify[27] = p1; /* abData[3] */
pin_modify[28] = 0x00; /* abData[4] */
+ if (DBG_CARD_IO)
+ log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
+ class, ins, p0, p1, len, (int)pininfo->maxlen);
+
sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
pin_modify, len, result, &resultlen);
xfree (pin_modify);
if (sw || resultlen < 2)
- return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
+ {
+ log_error ("control_pcsc failed: %d\n", sw);
+ return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
+ }
sw = (result[resultlen-2] << 8) | result[resultlen-1];
+ if (DBG_CARD_IO)
+ log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen);
return sw;
}
@@ -2783,6 +2806,9 @@ apdu_open_reader (const char *portstr, int *r_no_service)
static int pcsc_api_loaded, ct_api_loaded;
int slot;
+ if (DBG_READER)
+ log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
+
if (r_no_service)
*r_no_service = 0;
@@ -2797,6 +2823,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
if (slot != -1)
{
once_available = 1;
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=%d [ccid]\n", slot);
return slot; /* got one */
}
@@ -2807,14 +2835,22 @@ apdu_open_reader (const char *portstr, int *r_no_service)
and over again. To reset this flag "gpgconf --kill scdaemon"
can be used. */
if (once_available)
- return -1;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=-1 (once_avail)\n");
+ return -1;
+ }
/* If a CCID reader specification has been given, the user does
not want a fallback to other drivers. */
if (portstr)
for (s=portstr, i=0; *s; s++)
if (*s == ':' && (++i == 3))
- return -1;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
+ return -1;
+ }
}
#endif /* HAVE_LIBUSB */
@@ -2939,6 +2975,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
if (slot == -1 && r_no_service && pcsc_no_service)
*r_no_service = 1;
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot);
return slot;
}
@@ -2993,13 +3031,31 @@ apdu_close_reader (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_close_reader: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
sw = apdu_disconnect (slot);
if (sw)
- return sw;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
+ return sw;
+ }
if (reader_table[slot].close_reader)
- return reader_table[slot].close_reader (slot);
+ {
+ sw = reader_table[slot].close_reader (slot);
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => 0x%x (close_reader)\n", sw);
+ return sw;
+ }
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => SW_HOST_NOT_SUPPORTED\n");
return SW_HOST_NOT_SUPPORTED;
}
@@ -3038,13 +3094,32 @@ apdu_shutdown_reader (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_shutdown_reader: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
sw = apdu_disconnect (slot);
if (sw)
- return sw;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => 0x%x (apdu_disconnect)\n",
+ sw);
+ return sw;
+ }
if (reader_table[slot].shutdown_reader)
- return reader_table[slot].shutdown_reader (slot);
+ {
+ sw = reader_table[slot].shutdown_reader (slot);
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => 0x%x (close_reader)\n", sw);
+ return sw;
+ }
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => SW_HOST_NOT_SUPPORTED\n");
return SW_HOST_NOT_SUPPORTED;
}
@@ -3062,14 +3137,24 @@ apdu_enum_reader (int slot, int *used)
/* Connect a card. This is used to power up the card and make sure
- that an ATR is available. */
+ that an ATR is available. Depending on the reader backend it may
+ return an error for an inactive card or if no card is
+ available. */
int
apdu_connect (int slot)
{
int sw;
+ unsigned int status;
+
+ if (DBG_READER)
+ log_debug ("enter: apdu_connect: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_connect => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
/* Only if the access method provides a connect function we use it.
If not, we expect that the card has been implicitly connected by
@@ -3091,7 +3176,16 @@ apdu_connect (int slot)
scdaemon is fired up and apdu_get_status has not yet been called.
Without that we would force a reset of the card with the next
call to apdu_get_status. */
- apdu_get_status_internal (slot, 1, 1, NULL, NULL);
+ apdu_get_status_internal (slot, 1, 1, &status, NULL);
+ if (sw)
+ ;
+ else if (!(status & APDU_CARD_PRESENT))
+ sw = SW_HOST_NO_CARD;
+ else if ((status & APDU_CARD_PRESENT) && !(status & APDU_CARD_ACTIVE))
+ sw = SW_HOST_CARD_INACTIVE;
+
+ if (DBG_READER)
+ log_debug ("leave: apdu_connect => sw=0x%x\n", sw);
return sw;
}
@@ -3102,8 +3196,15 @@ apdu_disconnect (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_disconnect: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_disconnect => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
if (reader_table[slot].disconnect_card)
{
@@ -3116,6 +3217,9 @@ apdu_disconnect (int slot)
}
else
sw = 0;
+
+ if (DBG_READER)
+ log_debug ("leave: apdu_disconnect => sw=0x%x\n", sw);
return sw;
}
@@ -3151,11 +3255,22 @@ apdu_reset (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_reset: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_reset => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
if ((sw = lock_slot (slot)))
- return sw;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_reset => sw=0x%x (lock_slot)\n", sw);
+ return sw;
+ }
reader_table[slot].last_status = 0;
if (reader_table[slot].reset_reader)
@@ -3171,73 +3286,47 @@ apdu_reset (int slot)
}
unlock_slot (slot);
+ if (DBG_READER)
+ log_debug ("leave: apdu_reset => sw=0x%x\n", sw);
return sw;
}
-/* Activate a card if it has not yet been done. This is a kind of
- reset-if-required. It is useful to test for presence of a card
- before issuing a bunch of apdu commands. It does not wait on a
- locked card. */
-int
-apdu_activate (int slot)
-{
- int sw;
- unsigned int s;
-
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
-
- if ((sw = trylock_slot (slot)))
- return sw;
-
- if (reader_table[slot].get_status_reader)
- sw = reader_table[slot].get_status_reader (slot, &s);
-
- if (!sw)
- {
- if (!(s & 2)) /* Card not present. */
- sw = SW_HOST_NO_CARD;
- else if ( ((s & 2) && !(s & 4))
- || !reader_table[slot].atrlen )
- {
- /* We don't have an ATR or a card is present though inactive:
- do a reset now. */
- if (reader_table[slot].reset_reader)
- {
- reader_table[slot].last_status = 0;
- sw = reader_table[slot].reset_reader (slot);
- if (!sw)
- {
- /* If we got to here we know that a card is present
- and usable. Thus remember this. */
- reader_table[slot].last_status = (APDU_CARD_USABLE
- | APDU_CARD_PRESENT
- | APDU_CARD_ACTIVE);
- }
- }
- }
- }
-
- unlock_slot (slot);
- return sw;
-}
-
-
+/* Return the ATR or NULL if none is available. On success the length
+ of the ATR is stored at ATRLEN. The caller must free the returned
+ value. */
unsigned char *
apdu_get_atr (int slot, size_t *atrlen)
{
unsigned char *buf;
+ if (DBG_READER)
+ log_debug ("enter: apdu_get_atr: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return NULL;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => NULL (bad slot)\n");
+ return NULL;
+ }
if (!reader_table[slot].atrlen)
- return NULL;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => NULL (no ATR)\n");
+ return NULL;
+ }
+
buf = xtrymalloc (reader_table[slot].atrlen);
if (!buf)
- return NULL;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => NULL (out of core)\n");
+ return NULL;
+ }
memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen);
*atrlen = reader_table[slot].atrlen;
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => atrlen=%zu\n", *atrlen);
return buf;
}
@@ -3308,7 +3397,26 @@ int
apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed)
{
- return apdu_get_status_internal (slot, hang, 0, status, changed);
+ int sw;
+
+ if (DBG_READER)
+ log_debug ("enter: apdu_get_status: slot=%d hang=%d\n", slot, hang);
+ sw = apdu_get_status_internal (slot, hang, 0, status, changed);
+ if (DBG_READER)
+ {
+ if (status && changed)
+ log_debug ("leave: apdu_get_status => sw=0x%x status=%u changecnt=%u\n",
+ sw, *status, *changed);
+ else if (status)
+ log_debug ("leave: apdu_get_status => sw=0x%x status=%u\n",
+ sw, *status);
+ else if (changed)
+ log_debug ("leave: apdu_get_status => sw=0x%x changed=%u\n",
+ sw, *changed);
+ else
+ log_debug ("leave: apdu_get_status => sw=0x%x\n", sw);
+ }
+ return sw;
}