Last active
October 9, 2018 15:30
-
-
Save yoe/cefe152fcc560002aefd82f235b486ea to your computer and use it in GitHub Desktop.
tool to quickly send some APDUs to a smartcard using PC/SC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <PCSC/winscard.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <getopt.h> | |
const struct option options[] = { | |
{"reader", required_argument, 0, 'r'}, | |
{"apdu", required_argument, 0, 'a'}, | |
{NULL, 0, 0, 0}, | |
}; | |
static LPCSCARD_IO_REQUEST ioreq; | |
SCARDHANDLE openReader(SCARDCONTEXT ctx, int which, SCARDHANDLE oldhandle) { | |
static LPSTR readers = NULL; | |
LPSTR ptr; | |
DWORD readerlen = SCARD_AUTOALLOCATE; | |
int counter = 0; | |
LONG r; | |
SCARDHANDLE handle; | |
DWORD active; | |
if(!readers) { | |
SCardListReaders(ctx, NULL, (LPSTR)&readers, &readerlen); | |
} | |
if(oldhandle) { | |
SCardDisconnect(oldhandle, SCARD_LEAVE_CARD); | |
} | |
ptr = readers; | |
while(*ptr) { | |
if(which < 0 || counter == which) { | |
r = SCardConnect(ctx, ptr, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &handle, &active); | |
if(r != SCARD_S_SUCCESS) { | |
if(counter == which) { | |
fprintf(stderr, "E: Could not connect to card reader %d %s: %x\n", which, ptr, r); | |
exit(EXIT_FAILURE); | |
} | |
} else { | |
printf("Connected to smart card reader %s\n", ptr); | |
ioreq = (active == SCARD_PROTOCOL_T0 ? SCARD_PCI_T0 : SCARD_PCI_T1); | |
return handle; | |
} | |
} | |
ptr += strlen(ptr) + 1; | |
counter++; | |
} | |
fprintf(stderr, "E: Could not find a suitable reader\n"); | |
exit(EXIT_FAILURE); | |
} | |
void performApdu(SCARDHANDLE h, char *apduString) { | |
size_t len = strlen(apduString); | |
char apduBytes[(len/2) + 1]; | |
unsigned char recvBytes[300] = {0}; | |
DWORD recvlen = sizeof(recvBytes) - 1; | |
LONG r; | |
printf("Attempting to send APDU %s\n", apduString); | |
apduBytes[len/2] = 0; | |
for(int i=0; i<len/2; i++) { | |
char hexbyte[3] = {0}; | |
char *loc; | |
hexbyte[0] = apduString[i*2]; | |
hexbyte[1] = apduString[i*2+1]; | |
apduBytes[i] = strtol(hexbyte, &loc, 16); | |
if(loc != &(hexbyte[2])) { | |
fprintf(stderr, "E: Invalid hexadecimal character found, cannot continue\n"); | |
exit(EXIT_FAILURE); | |
} | |
} | |
r = SCardTransmit(h, ioreq, apduBytes, (len / 2), NULL, recvBytes, &recvlen); | |
if(r != SCARD_S_SUCCESS) { | |
fprintf(stderr, "E: Could not transmit %s: %x\n", apduString, r); | |
exit(EXIT_FAILURE); | |
} | |
printf("SW12: %02X %02X\n", recvBytes[recvlen - 2], recvBytes[recvlen - 1]); | |
if(recvlen > 2) { | |
int i; | |
for(i = 0; i <= (recvlen - 2) / 8; i++) { | |
for(int j = 0; j < 8 && i * 8 + j < (recvlen - 2); j++) { | |
printf("%02X ", recvBytes[i * 8 + j]); | |
} | |
printf(i % 2 ? "\n" : " "); | |
} | |
if(i % 2) { | |
printf("\n"); | |
} | |
} | |
} | |
int main(int argc, char**argv) { | |
SCARDCONTEXT ctx; | |
SCARDHANDLE handle = 0; | |
int c; | |
SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &ctx); | |
while((c = getopt_long(argc, argv, "a:r:", options, &optind)) > 0) { | |
switch(c) { | |
case 'a': | |
if(!handle) { | |
handle = openReader(ctx, -1, 0); | |
} | |
performApdu(handle, optarg); | |
break; | |
case 'r': | |
handle = openReader(ctx, strtol(optarg, NULL, 10), handle); | |
break; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment