Two weeks ago, I reported problems with using pin pad readers on big
endian machines. During the mail exchanges it was pointed out that the
PCSC standards have changed and are not clear on how the uint16_t and
uint32_t values in the PIN_VERIFY_STRUCTURE and PIN_MODIFY_STRUCTURE
should be passed.

In addition the OpenSC defined its own version of the reader.h and did
not define the HOST_TO_CCID_16 and HOST_TO_CCID_32 correctly.

Attached is a patch against ccid-1.3.13 src/command.c that will test
the ulDataLength to see if it is big endian, on a big endian machine.
If so, it will swap the bytes in the 3 fields to be little endian.

Thus if the fields are passed in in either little or big endian
the fields will be converted to little endian, ready for the pin pad
reader, and the code will work on any machine.

This was tested on a Solaris 10 sparc system with an Omnikey 3821
reader, using ccid-1.3.3 and pcsc-lite-1.6.1, and OpenSC-svn.

I can't test against ccid-1.4 as it is now using libusb-1.0, and this
is not supported on Solaris. It looks like the code change should
still work with ccid-1.4.



 Douglas E. Engert  <[email protected]>
 Argonne National Laboratory
 9700 South Cass Avenue
 Argonne, Illinois  60439
 (630) 252-5444
--- ./src/,commands.c   Fri Jun  4 07:31:15 2010
+++ ./src/commands.c    Fri Aug 13 10:38:24 2010
@@ -51,6 +51,12 @@
 #define max( a, b )   ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
 
+#ifndef BSWAP_16
+#define BSWAP_8(x)  ((x) & 0xff)
+#define BSWAP_16(x) ((BSWAP_8(x) << 8) | BSWAP_8((x) >> 8))
+#define BSWAP_32(x) ((BSWAP_16(x) << 16) | BSWAP_16((x) >> 16))
+#endif
+
 /* internal functions */
 static RESPONSECODE CmdXfrBlockAPDU_extended(unsigned int reader_index,
        unsigned int tx_length, unsigned char tx_buffer[], unsigned int 
*rx_length,
@@ -69,6 +75,7 @@
        unsigned char rx_buffer[]);
 
 static void i2dw(int value, unsigned char *buffer);
+static unsigned int bei2i(unsigned char *buffer);
 
 
 /*****************************************************************************
@@ -281,10 +288,12 @@
 {
        unsigned char cmd[11+14+CMD_BUF_SIZE];
        unsigned int a, b;
+       PIN_VERIFY_STRUCTURE *pvs;
        _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
        int old_read_timeout;
        RESPONSECODE ret;
 
+       pvs = (PIN_VERIFY_STRUCTURE *)TxBuffer;
        cmd[0] = 0x69;  /* Secure */
        cmd[5] = ccid_descriptor->bCurrentSlotIndex;    /* slot number */
        cmd[6] = (*ccid_descriptor->pbSeq)++;
@@ -307,6 +316,21 @@
                return IFD_NOT_SUPPORTED;
        }
 
+       /* On little endian machines we are all set. */
+       /* If on big endian machine and caller is using host byte order */ 
+
+       if (pvs->ulDataLength + 19  == TxLength && 
+               bei2i((unsigned char*)(&pvs->ulDataLength)) == 
pvs->ulDataLength)
+       {
+               DEBUG_INFO("Reversing order from big to little endian\n");
+               /* If ulDataLength is big endian, assume others are too */
+               /* reverse the byte order for 3 fields */
+               pvs->wPINMaxExtraDigit = BSWAP_16(pvs->wPINMaxExtraDigit);
+               pvs->wLangId = BSWAP_16(pvs->wLangId);
+               pvs->ulDataLength = BSWAP_32(pvs->ulDataLength);
+       }
+       /* At this point we now have the above 3 variables in little endian */ 
+       
        if (dw2i(TxBuffer, 15) + 19 != TxLength) /* ulDataLength field 
coherency */
        {
                DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 15) + 19, 
TxLength);
@@ -496,6 +520,7 @@
 {
        unsigned char cmd[11+19+CMD_BUF_SIZE];
        unsigned int a, b;
+       PIN_MODIFY_STRUCTURE *pms;
        _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
        int old_read_timeout;
        RESPONSECODE ret;
@@ -503,6 +528,7 @@
        int bNumberMessages = 0; /* for GemPC Pinpad */
 #endif
 
+       pms = (PIN_MODIFY_STRUCTURE *)TxBuffer;
        cmd[0] = 0x69;  /* Secure */
        cmd[5] = ccid_descriptor->bCurrentSlotIndex;    /* slot number */
        cmd[6] = (*ccid_descriptor->pbSeq)++;
@@ -525,6 +551,22 @@
                return IFD_NOT_SUPPORTED;
        }
 
+       /* On little endian machines we are all set. */
+       /* If on big endian machine and caller is using host byte order */ 
+
+       if (pms->ulDataLength + 24  == TxLength && 
+               bei2i((unsigned char*)(&pms->ulDataLength)) == 
pms->ulDataLength)
+       {
+               DEBUG_INFO("Reversing order from big to little endian\n");
+               /* If ulDataLength is big endian, assume others are too */
+               /* reverse the byte order for 3 fields */
+               pms->wPINMaxExtraDigit = BSWAP_16(pms->wPINMaxExtraDigit);
+               pms->wLangId = BSWAP_16(pms->wLangId);
+               pms->ulDataLength = BSWAP_32(pms->ulDataLength);
+       }
+       /* At this point we now have the above 3 variables in little endian */ 
+
+
        if (dw2i(TxBuffer, 20) + 24 != TxLength) /* ulDataLength field 
coherency */
        {
                DEBUG_INFO3("Wrong lengths: %d %d", dw2i(TxBuffer, 20) + 24, 
TxLength);
@@ -2113,3 +2155,13 @@
        buffer[3] = (value >> 24) & 0xFF;
 } /* i2dw */
 
+/*****************************************************************************
+*
+*                  bei2i
+*
+****************************************************************************/
+
+static unsigned int bei2i(unsigned char buffer[])
+{
+       return (buffer[0]<<24) + (buffer[1]<<16) + (buffer[2]<<8) + buffer[3];
+}
_______________________________________________
Muscle mailing list
[email protected]
http://lists.drizzle.com/mailman/listinfo/muscle

Reply via email to