// includes #include #include // for atoi #include // for memset #include #include "/usr/local/towitoko/include/ctapi.h" // defines API CT_init, CT_data and CT_close #include "/usr/local/towitoko/include/ctbcs.h" // defines hex values for all available commands - easier than writing all hex values #include "/usr/local/towitoko/include/ctacs.h" // defined by me for easier access #include "/usr/local/towitoko/include/ctapi-add.h" // defined by me for easier access // defines // You may change these values for your setup #define COMPORT 0 // ---- > Change this according to the com-port where your cardterminal is attached to < ---- #define TERMINALPORT 0 // ---- > Change this according to the slot where your card is insertet if you have more slots < ---- //#define WAIT // Wait for card insertion - if you want to be prompted to insert your German Medical Card //#define SAFECOMMANDS // As far as I programmed this app now, commands always has size 5 but there // may be commands that need a larger amount of parameters // So, if you add functions, be sure to set commands yourself #define CHAROUTPUT // Output in char-format. Human readable //#define HEXOUTPUT // Output in hex-format. Not always human readable //#define DEBUG // turn on lots of debug information //#define FUN // turn on "ByeBye"-Output at the end of the programm // You should not change these values if you do not exactly understand this programm #define MAXMEM 1000 // Max. memory for response #define MAXBYTES 256 // There are exactly 256 Bytes of data on your German Medical Card // not lucky about the next define. should be provided by api ! //#define CTAPIADD_ERR_HOST -127 // I decided to write on an add-on for the ctapi because there are so many functions not documented elsewhere // structs struct { unsigned short ptn; // serial port number 0 if ttya = com1, negative if not assigned int status; // -1 void, 0 sync, 1 async unsigned char atr[33]; // ATR bytes unsigned short atr_size; // ATR size } cardterminal; // functions void handleErrorCode(char ec){ printf("An Error occured: "); switch (ec) { case ERR_INVALID : printf("Not a valid parameter or value\n"); break; case ERR_CT : printf("Cannot acces card terminal.\n"); break; case ERR_TRANS : printf("Not recoverable transmission error.\n"); break; case ERR_MEMORY : printf("Memory matching error in HTSI layer, maybe data is larger than buffer.\n"); break; case CTAPIADD_ERR_HOST : printf("Function terminated by host / operating system.\n"); break; case ERR_HTSI : printf("HTSI error.\n"); break; } } // main programm int main (int argc, char *argv[]) { unsigned char sad; // source address unsigned char dad; // destination address unsigned char command[300]; // commands, max 300 chars unsigned short commands; // how many commands unsigned char response[MAXMEM]; // response, max. 1000 chars unsigned short ctn; // card terminal number, freely choseable unsigned short ptn; // (com/ttyX) port number unsigned short lenr; // response length unsigned short host; // HOST is the local host char result; // return value of FUNctions int i; // some variables bool space = false; // initialize host = 2; // local host =2, 5 would be remote host commands = 5; // commands always is 5 ! (CLA, INS, P1, P2, LC) // arg-check if (argc == 1) { printf("Initializing with default values com 0/ttya"); ctn = 0; // the first terminal ptn = COMPORT; } else if (argc == 3) { ctn = atoi(argv[0]); ptn = atoi(argv[1]); } else { printf("\nUsage:\n\n"); printf("Either give no arguments or give 2 arguments where the first\n"); printf("is the cardterminalnumber (usually 0) and the second specifies\n"); printf("your com-port (0 for com 0/ttya, 1 for com 1/ttyb and so on)\n\n"); return(0); } // initialize struct cardterminal.ptn = ptn; // ptn = ptn cardterminal.status = -1; memset(cardterminal.atr,0,33); cardterminal.atr_size = 33; result = CT_init(ctn,ptn); // initialize on ctn 0 // (first reader slot) and com 0 / ttya // lets check if all is ok if (result != OK) { handleErrorCode(result); #ifdef DEBUG printf("Could not initialize card terminal %d on port %d. Result was %d. Aborting.",ctn,ptn,result); #endif return(1); } #ifdef DEBUG printf("main: result of CT_init(ctn=%d,ptn=%d) was: %d\n",ctn,ptn,result); #endif #ifdef WAIT printf("Please insert a German Medical Card and press Enter to continue."); getchar(); #endif // CT_command for REQEUST ICC( 0x20 0x12 0x01 0x00 0x00) // check, if card is inserted sad = host; // source = HOST, 5 would be REMOTE HOST dad = ctn; // destination = ctn; lenr = MAXBYTES; // response length is max. memory available for response command[0] = CTBCS_CLA; // Class byte of all CTBCS commands command[1] = CTBCS_INS_REQUEST; // Request ICC command[2] = CTBCS_P1_CT_KERNEL; // ICC interface command[3] = CTBCS_P2_STATUS_ICC; // return no data command[4] = 0x00; // empty otherwise: length of subsequent data field #ifdef SAVECOMMANDS commands = 5; #endif // how many commands are given to CT_data result = CT_data(ctn, &dad, &sad, commands, command, &lenr, response); // lets check if all is ok if (result != OK) { handleErrorCode(result); return(result); #ifdef DEBUG printf("main: result of operation CT_data(%d,%d,%d,%d,%d,%d) (REQUEST_ICC) was: %d\n",ctn,dad,sad,commands,lenr,response,result); #endif } #ifdef DEBUG printf("Terminal is ready for work.\n"); #endif // Terminal is now available for work // So let us get the ATR = Answer to Reset sad = host; // source = HOST, 5 would be REMOTE HOST dad = 0x01; // NOT SURE WHY 0x01 instead of 0x00 (=ctn) ??? lenr = MAXBYTES; // response length is max. memory available for response command[0] = CTBCS_CLA; // Class byte of all CTBCS commands command[1] = CTBCS_INS_REQUEST; // Request ICC command[2] = CTBCS_P1_INTERFACE1; // ICC interface command[3] = CTBCS_P2_REQUEST_GET_ATR; // return complete ATR command[4] = 0x00; // empty otherwise: length of subsequent data field #ifdef SAVECOMMANDS commands = 5; #endif result = CT_data(ctn, &dad, &sad, commands, command, &lenr, response); // lets check if all is ok if (result != OK ) { handleErrorCode(result); return(result); } #ifdef DEBUG printf("main: result of operation CT_data(%d,%d,%d,%d,%d,%d) (GET ATR) was: %d\n",ctn,dad,sad,commands,lenr,response,result); #endif // save cardterminal status cardterminal.status = response[lenr -1]; // status, see above memcpy(cardterminal.atr, response, lenr-2); cardterminal.atr_size = lenr -2; #ifdef DEBUG printf("Cardterminal status saved in struct.\n"); #endif // now lets look at the ATR #ifdef DEBUG printf("ATR (HEX): "); for (i = 0; i < cardterminal.atr_size; i++) { printf("%02X ", cardterminal.atr[i]); } printf("\n"); #endif // maybe we need to select the memory format before the next // would be cleaner - but works with German Medical Card // now let us get the desired information - the medical data // contained on the chipcard // relevant information is to be found after Byte 32 -> 0x21 sad = host; // source = HOST, 5 would be REMOTE HOST dad = ctn; // destination = ctn; lenr = (MAXBYTES+1); // response length is max. memory available for response command[0] = CTBCS_CLA; // Class byte of all CTBCS commands command[1] = CTACS_READ_BINARY; // READ BINARY command[2] = (0x21 >> 8); // P1: Offset. logical start address of the file is 0000 command[3] = (0x21 & 0x00FF); // P2: Offset. logical start address of the file is 0000 command[4] = (unsigned char) (MAXBYTES-0x21); // length of data field that is to be read, 00 is read available data #ifdef SAVECOMMANDS commands = 5; #endif result = CT_data(ctn, &dad, &sad, commands, command, &lenr, response); // lets check if all is ok if (result != OK ) { handleErrorCode(result); return(result); } #ifdef DEBUG printf("main: result of operation CT_data(%d,%d,%d,%d,%d,%d) (GET BINARY) was: %d\n",ctn,dad,sad,commands,lenr,response,result); #endif for (i = 0; i < lenr; i++) { switch(response[i]) { case 0x0A: space = false; break; case 0x20: if (!space) { printf(" "); space = true; } break; case 0x08: break; case 0x26: printf("&");break; case 0x27: printf("'");break; case 0x28: printf("(");break; case 0x29: printf(")");break; case 0x2B: printf("+");break; case 0x2D: printf("-");break; case 0x2E: printf(".");break; case 0x2F: printf("/");break; case 0x5F: printf("_");break; case 0x60: printf("VersichtertenDaten-Template :"); space = false;break; case 0x80: printf("\nKrankenkassen-Name :"); space = false; break; case 0x81: printf("\nKrankenkassen-Nummer :"); space = false; break; case 0x82: printf("\nVersicherten-Nummer :"); space = false; break; case 0x83: printf("\nVersichtern-Status :"); space = false; break; case 0x84: printf("\nTitel :"); space = false; break; case 0x85: printf("\nVorname :"); space = false; break; case 0x86: printf("\nNamenszusatz :"); space = false; break; case 0x87: printf("\nNachname :"); space = false; break; case 0x88: printf("\nGeburtsdatum :"); space = false; break; case 0x89: printf("\nStrasse :"); space = false; break; case 0x8A: printf("\nLänder-Code :"); space = false; break; case 0x8B: printf("\nPostleitzahl :"); space = false; break; case 0x8C: printf("\nOrt :"); space = false; break; case 0x8D: printf("\nGültigkeit :"); space = false; break; case 0x8E: printf("\nPrüfsumme :"); space = false; break; case 0x8F: printf("\nVersichertenkarten-Nummer :"); space = false; break; case 0x90: printf("\nStatus-Ergänzung :"); space = false; break; case 0xB0: space = false; break; case 0xC0: printf("\nSchlussdatensatz :"); space = false; break; #ifdef CHAROUTPUT default: printf("%c", response[i]); break; // for CHAR-Output #endif #ifdef HEXOUTPUT default: printf("%02X ", response[i]); break; // for HEX-Output #endif } } printf("\n"); // Closing the session #ifdef DEBUG printf("Trying to close cardterminal\n"); #endif result = CT_close(ctn); if (result != OK) { handleErrorCode(result); printf("Error. Could not close\n"); } #ifdef DEBUG printf("Closing connection returned %d.\n", result); #endif #ifdef FUN printf("Bye\n"); #endif return(result); }