//----------------------------------------------------------------------------- // Abort helper function for EPA_PACE_Collect_Nonce // sets relevant data in ack, sends the response //----------------------------------------------------------------------------- static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) { // power down the field EPA_Finish(); // send the USB packet cmd_send(CMD_ACK,step,func_return,0,0,0); }
//----------------------------------------------------------------------------- // Abort helper function for EPA_PACE_Collect_Nonce // sets relevant data in ack, sends the response //----------------------------------------------------------------------------- static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) { // // step in which the failure occured // ack->arg[0] = step; // // last return code // ack->arg[1] = func_return; // power down the field EPA_Finish(); // send the USB packet cmd_send(CMD_ACK,step,func_return,0,0,0); //UsbSendPacket((void *)ack, sizeof(UsbCommand)); }
//----------------------------------------------------------------------------- // Acquire one encrypted PACE nonce //----------------------------------------------------------------------------- void EPA_PACE_Collect_Nonce(UsbCommand *c) { /* * ack layout: * arg: * 1. element * step where the error occured or 0 if no error occured * 2. element * return code of the last executed function * d: * Encrypted nonce */ // return value of a function int func_return; // // initialize ack with 0s // memset(ack->arg, 0, 12); // memset(ack->d.asBytes, 0, 48); // set up communication func_return = EPA_Setup(); if (func_return != 0) { EPA_PACE_Collect_Nonce_Abort(1, func_return); return; } // increase the timeout (at least some cards really do need this!) iso14a_set_timeout(0x0002FFFF); // read the CardAccess file // this array will hold the CardAccess file uint8_t card_access[256] = {0}; int card_access_length = EPA_Read_CardAccess(card_access, 256); // the response has to be at least this big to hold the OID if (card_access_length < 18) { EPA_PACE_Collect_Nonce_Abort(2, card_access_length); return; } // this will hold the PACE info of the card pace_version_info_t pace_version_info; // search for the PACE OID func_return = EPA_Parse_CardAccess(card_access, card_access_length, &pace_version_info); if (func_return != 0 || pace_version_info.version == 0) { EPA_PACE_Collect_Nonce_Abort(3, func_return); return; } // initiate the PACE protocol // use the CAN for the password since that doesn't change func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2); // now get the nonce uint8_t nonce[256] = {0}; uint8_t requested_size = (uint8_t)c->arg[0]; func_return = EPA_PACE_Get_Nonce(requested_size, nonce); // check if the command succeeded if (func_return < 0) { EPA_PACE_Collect_Nonce_Abort(4, func_return); return; } // all done, return EPA_Finish(); // save received information // ack->arg[1] = func_return; // memcpy(ack->d.asBytes, nonce, func_return); // UsbSendPacket((void *)ack, sizeof(UsbCommand)); cmd_send(CMD_ACK,0,func_return,0,nonce,func_return); }
//----------------------------------------------------------------------------- // Perform the PACE protocol by replaying given APDUs //----------------------------------------------------------------------------- void EPA_PACE_Replay(UsbCommand *c) { uint32_t timings[sizeof(apdu_lengths_replay) / sizeof(apdu_lengths_replay[0])] = {0}; // if an APDU has been passed, save it if (c->arg[0] != 0) { // make sure it's not too big if(c->arg[2] > apdus_replay[c->arg[0] - 1].len) { cmd_send(CMD_ACK, 1, 0, 0, NULL, 0); } memcpy(apdus_replay[c->arg[0] - 1].data + c->arg[1], c->d.asBytes, c->arg[2]); // save/update APDU length if (c->arg[1] == 0) { apdu_lengths_replay[c->arg[0] - 1] = c->arg[2]; } else { apdu_lengths_replay[c->arg[0] - 1] += c->arg[2]; } cmd_send(CMD_ACK, 0, 0, 0, NULL, 0); return; } // return value of a function int func_return; // set up communication func_return = EPA_Setup(); if (func_return != 0) { EPA_Finish(); cmd_send(CMD_ACK, 2, func_return, 0, NULL, 0); return; } // increase the timeout (at least some cards really do need this!)///////////// // iso14a_set_timeout(0x0003FFFF); // response APDU uint8_t response_apdu[300] = {0}; // now replay the data and measure the timings for (int i = 0; i < sizeof(apdu_lengths_replay); i++) { StartCountUS(); func_return = EPA_APDU(apdus_replay[i].data, apdu_lengths_replay[i], response_apdu); timings[i] = GetCountUS(); // every step but the last one should succeed if (i < sizeof(apdu_lengths_replay) - 1 && (func_return < 6 || response_apdu[func_return - 4] != 0x90 || response_apdu[func_return - 3] != 0x00)) { EPA_Finish(); cmd_send(CMD_ACK, 3 + i, func_return, 0, timings, 20); return; } } EPA_Finish(); cmd_send(CMD_ACK,0,0,0,timings,20); return; }