[810] | 1 | #ifdef HAVE_PCSC
|
---|
| 2 |
|
---|
| 3 | #include "reader-pcsc.h"
|
---|
| 4 | int pcsc_reader_init(struct s_reader *pcsc_reader, char *device)
|
---|
| 5 | {
|
---|
[817] | 6 | ULONG rv;
|
---|
| 7 | DWORD dwReaders;
|
---|
| 8 | LPSTR mszReaders = NULL;
|
---|
| 9 | char *ptr, **readers = NULL;
|
---|
| 10 | int nbReaders;
|
---|
| 11 | int reader_nb;
|
---|
| 12 |
|
---|
| 13 | cs_debug("PCSC establish context for PCSC reader %s", device);
|
---|
| 14 | rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &pcsc_reader->hContext);
|
---|
| 15 | if ( rv == SCARD_S_SUCCESS ) {
|
---|
| 16 | // here we need to list the pcsc readers and get the name from there,
|
---|
| 17 | // the pcsc_reader->device should contain the reader number
|
---|
| 18 | // and after the actual device name is copied in pcsc_reader->pcsc_name .
|
---|
| 19 | rv = SCardListReaders(pcsc_reader->hContext, NULL, NULL, &dwReaders);
|
---|
| 20 | if( rv != SCARD_S_SUCCESS ) {
|
---|
| 21 | cs_debug("PCSC failed listing readers [1] : (%lx)", rv);
|
---|
| 22 | return 0;
|
---|
| 23 | }
|
---|
| 24 | mszReaders = malloc(sizeof(char)*dwReaders);
|
---|
| 25 | if (mszReaders == NULL) {
|
---|
| 26 | cs_debug("PCSC failed malloc");
|
---|
| 27 | return 0;
|
---|
| 28 | }
|
---|
| 29 | rv = SCardListReaders(pcsc_reader->hContext, NULL, mszReaders, &dwReaders);
|
---|
| 30 | if( rv != SCARD_S_SUCCESS ) {
|
---|
| 31 | cs_debug("PCSC failed listing readers [2]: (%lx)", rv);
|
---|
| 32 | return 0;
|
---|
| 33 | }
|
---|
| 34 | /* Extract readers from the null separated string and get the total
|
---|
| 35 | * number of readers */
|
---|
| 36 | nbReaders = 0;
|
---|
| 37 | ptr = mszReaders;
|
---|
| 38 | while (*ptr != '\0') {
|
---|
| 39 | ptr += strlen(ptr)+1;
|
---|
| 40 | nbReaders++;
|
---|
| 41 | }
|
---|
| 42 |
|
---|
| 43 | if (nbReaders == 0) {
|
---|
| 44 | cs_debug("PCSC : no reader found");
|
---|
| 45 | return 0;
|
---|
| 46 | }
|
---|
[810] | 47 |
|
---|
[817] | 48 | readers = calloc(nbReaders, sizeof(char *));
|
---|
| 49 | if (readers == NULL) {
|
---|
| 50 | cs_debug("PCSC failed malloc");
|
---|
| 51 | return 0;
|
---|
| 52 | }
|
---|
[810] | 53 |
|
---|
[817] | 54 | /* fill the readers table */
|
---|
| 55 | nbReaders = 0;
|
---|
| 56 | ptr = mszReaders;
|
---|
| 57 | while (*ptr != '\0') {
|
---|
| 58 | cs_debug("PCSC reader %d: %s", nbReaders, ptr);
|
---|
| 59 | readers[nbReaders] = ptr;
|
---|
| 60 | ptr += strlen(ptr)+1;
|
---|
| 61 | nbReaders++;
|
---|
| 62 | }
|
---|
[810] | 63 |
|
---|
[817] | 64 | reader_nb=atoi((const char *)&pcsc_reader->device);
|
---|
| 65 | if (reader_nb < 0 || reader_nb >= nbReaders) {
|
---|
| 66 | cs_debug("Wrong reader index: %d\n", reader_nb);
|
---|
| 67 | return 0;
|
---|
| 68 | }
|
---|
| 69 |
|
---|
| 70 | snprintf(pcsc_reader->pcsc_name,sizeof(pcsc_reader->pcsc_name),"%s",readers[reader_nb]);
|
---|
[849] | 71 | pcsc_reader->pcsc_has_card=0;
|
---|
| 72 | pcsc_reader->hCard=0;
|
---|
[817] | 73 | }
|
---|
| 74 | else {
|
---|
| 75 | cs_debug("PCSC failed establish context (%lx)", rv);
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | return 0;
|
---|
[810] | 79 | }
|
---|
| 80 |
|
---|
[821] | 81 | int pcsc_reader_do_api(struct s_reader *pcsc_reader, uchar *buf, uchar *cta_res, ushort *cta_lr, int l, int dbg)
|
---|
[810] | 82 | {
|
---|
| 83 | ULONG rv;
|
---|
| 84 | SCARD_IO_REQUEST pioRecvPci;
|
---|
| 85 | DWORD dwSendLength, dwRecvLength;
|
---|
| 86 |
|
---|
[1010] | 87 |
|
---|
[849] | 88 | dwRecvLength = CTA_RES_LEN;
|
---|
[810] | 89 |
|
---|
[1002] | 90 | if(pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0) {
|
---|
[1010] | 91 | // explanantion as to why we do the test on buf[4] :
|
---|
| 92 | // Issuing a command without exchanging data :
|
---|
| 93 | //To issue a command to the card that does not involve the exchange of data (either sent or received), the send and receive buffers must be formatted as follows.
|
---|
| 94 | //The pbSendBuffer buffer must contain the CLA, INS, P1, and P2 values for the T=0 operation. The P3 value is not sent. (This is to differentiate the header from the case where 256 bytes are expected to be returned.)
|
---|
| 95 | //The cbSendLength parameter must be set to four, the size of the T=0 header information (CLA, INS, P1, and P2).
|
---|
| 96 | //The pbRecvBuffer will receive the SW1 and SW2 status codes from the operation.
|
---|
| 97 | //The pcbRecvLength should be at least two and will be set to two upon return.
|
---|
| 98 | if(buf[4])
|
---|
| 99 | dwSendLength = l;
|
---|
| 100 | else
|
---|
| 101 | dwSendLength = l-1;
|
---|
[1012] | 102 | cs_debug("sending %d bytes to PCSC", dwSendLength);
|
---|
[1005] | 103 | rv = SCardTransmit(pcsc_reader->hCard, SCARD_PCI_T0, buf, dwSendLength, &pioRecvPci, cta_res, &dwRecvLength);
|
---|
[1002] | 104 | }
|
---|
| 105 | else if(pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T1) {
|
---|
[1010] | 106 | dwSendLength = l;
|
---|
[1012] | 107 | cs_debug("sending %d bytes to PCSC", dwSendLength);
|
---|
[1005] | 108 | rv = SCardTransmit(pcsc_reader->hCard, SCARD_PCI_T1, buf, dwSendLength, &pioRecvPci, cta_res, &dwRecvLength);
|
---|
[1002] | 109 | }
|
---|
| 110 | else {
|
---|
| 111 | cs_debug("PCSC invalid protocol (T=%d)", pcsc_reader->dwActiveProtocol);
|
---|
| 112 | return ERR_INVALID;
|
---|
| 113 | }
|
---|
[810] | 114 |
|
---|
| 115 | *cta_lr=dwRecvLength;
|
---|
[849] | 116 | cs_debug("received %d bytes from PCSC with rv=%lx", *cta_lr, rv);
|
---|
[810] | 117 |
|
---|
[821] | 118 | cs_debug("PCSC doapi (%lx ) (T=%d), %d", rv, ( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1), dwRecvLength );
|
---|
[810] | 119 | if ( rv == SCARD_S_SUCCESS ){
|
---|
| 120 | return OK;
|
---|
| 121 | }
|
---|
| 122 | else {
|
---|
| 123 | return ERR_INVALID;
|
---|
| 124 | }
|
---|
| 125 |
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | int pcsc_activate_card(struct s_reader *pcsc_reader, uchar *atr, ushort *atr_size)
|
---|
| 129 | {
|
---|
| 130 | ULONG rv;
|
---|
| 131 | DWORD dwState, dwAtrLen, dwReaderLen;
|
---|
| 132 | BYTE pbAtr[64];
|
---|
| 133 |
|
---|
| 134 | cs_debug("PCSC initializing card in (%s)", pcsc_reader->pcsc_name);
|
---|
| 135 | dwAtrLen = sizeof(pbAtr);
|
---|
[849] | 136 | dwReaderLen=0;
|
---|
[810] | 137 |
|
---|
| 138 | cs_debug("PCSC resetting card in (%s)", pcsc_reader->pcsc_name);
|
---|
[849] | 139 | rv = SCardReconnect(pcsc_reader->hCard, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &pcsc_reader->dwActiveProtocol);
|
---|
[810] | 140 | cs_debug("PCSC resetting done on card in (%s)", pcsc_reader->pcsc_name);
|
---|
[815] | 141 | cs_debug("PCSC Protocol (T=%d)",( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
|
---|
[810] | 142 |
|
---|
| 143 | if ( rv != SCARD_S_SUCCESS ) {
|
---|
| 144 | cs_debug("Error PCSC failed to reset card (%lx)", rv);
|
---|
| 145 | return(0);
|
---|
| 146 | }
|
---|
[849] | 147 |
|
---|
| 148 |
|
---|
[817] | 149 | cs_debug("PCSC getting ATR for card in (%s)", pcsc_reader->pcsc_name);
|
---|
[849] | 150 | rv = SCardStatus(pcsc_reader->hCard,NULL, &dwReaderLen, &dwState, &pcsc_reader->dwActiveProtocol, pbAtr, &dwAtrLen);
|
---|
[817] | 151 | if ( rv == SCARD_S_SUCCESS ) {
|
---|
| 152 | cs_debug("PCSC Protocol (T=%d)",( pcsc_reader->dwActiveProtocol == SCARD_PROTOCOL_T0 ? 0 : 1));
|
---|
| 153 | memcpy(atr, pbAtr, dwAtrLen);
|
---|
| 154 | *atr_size=dwAtrLen;
|
---|
| 155 | #ifdef CS_RDR_INIT_HIST
|
---|
| 156 | pcsc_reader->init_history_pos=0;
|
---|
| 157 | memset(pcsc_reader->init_history, 0, sizeof(pcsc_reader->init_history));
|
---|
| 158 | #endif
|
---|
| 159 | cs_ri_log("ATR: %s", cs_hexdump(1, (uchar *)pbAtr, dwAtrLen));
|
---|
| 160 | return(1);
|
---|
| 161 | }
|
---|
| 162 | else {
|
---|
| 163 | cs_debug("Error PCSC failed to get ATR for card (%lx)", rv);
|
---|
| 164 | }
|
---|
[810] | 165 |
|
---|
[817] | 166 | return(0);
|
---|
[810] | 167 | }
|
---|
| 168 |
|
---|
| 169 |
|
---|
| 170 | int pcsc_check_card_inserted(struct s_reader *pcsc_reader)
|
---|
| 171 | {
|
---|
[817] | 172 | DWORD dwState, dwAtrLen, dwReaderLen;
|
---|
| 173 | BYTE pbAtr[64];
|
---|
| 174 | ULONG rv;
|
---|
| 175 |
|
---|
| 176 | dwAtrLen = sizeof(pbAtr);
|
---|
[849] | 177 | rv=0;
|
---|
| 178 | dwState=0;
|
---|
| 179 | dwReaderLen=0;
|
---|
| 180 |
|
---|
| 181 | // Do we have a card ?
|
---|
| 182 | if (!pcsc_reader->pcsc_has_card && !pcsc_reader->hCard) {
|
---|
| 183 | // try connecting to the card
|
---|
| 184 | rv = SCardConnect(pcsc_reader->hContext, pcsc_reader->pcsc_name, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &pcsc_reader->hCard, &pcsc_reader->dwActiveProtocol);
|
---|
[817] | 185 | if (rv==SCARD_E_NO_SMARTCARD) {
|
---|
[849] | 186 | // no card in reader
|
---|
[817] | 187 | pcsc_reader->pcsc_has_card=0;
|
---|
[849] | 188 | if(pcsc_reader->hCard) {
|
---|
| 189 | SCardDisconnect(pcsc_reader->hCard,SCARD_RESET_CARD);
|
---|
| 190 | pcsc_reader->hCard=0;
|
---|
| 191 | }
|
---|
[817] | 192 | cs_debug("PCSC card in %s removed / absent [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
|
---|
| 193 | return 0;
|
---|
| 194 | }
|
---|
[849] | 195 | else if( rv == SCARD_W_UNRESPONSIVE_CARD ) {
|
---|
| 196 | // there is a problem with the card in the reader
|
---|
| 197 | pcsc_reader->pcsc_has_card=0;
|
---|
| 198 | pcsc_reader->hCard=0;
|
---|
| 199 | cs_log("PCSC card in %s is unresponsive. Eject and re-insert please.", pcsc_reader->pcsc_name);
|
---|
| 200 | return 0;
|
---|
| 201 | }
|
---|
[817] | 202 | else if( rv == SCARD_S_SUCCESS ) {
|
---|
[849] | 203 | // we have a card
|
---|
[817] | 204 | pcsc_reader->pcsc_has_card=1;
|
---|
| 205 | }
|
---|
[849] | 206 | else {
|
---|
| 207 | // if we get here we have a bigger problem -> display status and debug
|
---|
| 208 | cs_debug("PCSC reader %s status [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
|
---|
| 209 | return 0;
|
---|
| 210 | }
|
---|
[810] | 211 |
|
---|
[817] | 212 | }
|
---|
[810] | 213 |
|
---|
[849] | 214 | // if we get there the card is ready, check its status
|
---|
[817] | 215 | rv = SCardStatus(pcsc_reader->hCard, NULL, &dwReaderLen, &dwState, &pcsc_reader->dwActiveProtocol, pbAtr, &dwAtrLen);
|
---|
[810] | 216 |
|
---|
[849] | 217 | if (rv == SCARD_S_SUCCESS && (dwState & (SCARD_PRESENT | SCARD_NEGOTIABLE | SCARD_POWERED ) )) {
|
---|
[817] | 218 | cs_debug("PCSC card IS inserted in %s card state [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState,rv);
|
---|
[849] | 219 | return CARD_INSERTED;
|
---|
[817] | 220 | }
|
---|
| 221 | else {
|
---|
[849] | 222 | SCardDisconnect(pcsc_reader->hCard,SCARD_RESET_CARD);
|
---|
| 223 | pcsc_reader->hCard=0;
|
---|
| 224 | pcsc_reader->pcsc_has_card=0;
|
---|
| 225 | cs_debug("PCSC card in %s removed / absent [dwstate=%lx rv=(%lx)]", pcsc_reader->pcsc_name, dwState, rv );
|
---|
[817] | 226 | }
|
---|
| 227 |
|
---|
| 228 | return 0;
|
---|
[810] | 229 | }
|
---|
| 230 | #endif
|
---|
| 231 |
|
---|