mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 18:48:13 -07:00
ADD: PACE functionality ref: https://github.com/Proxmark/proxmark3/pull/121
FIX: some missing usb_commands for EPA.
This commit is contained in:
parent
24344f28ad
commit
d0f3338e0c
8 changed files with 218 additions and 32 deletions
122
armsrc/epa.c
122
armsrc/epa.c
|
@ -5,7 +5,7 @@
|
|||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Routines to support the German eletronic "Personalausweis" (ID card)
|
||||
// Routines to support the German electronic "Personalausweis" (ID card)
|
||||
// Note that the functions which do not implement USB commands do NOT initialize
|
||||
// the card (with iso14443a_select_card etc.). If You want to use these
|
||||
// functions, You need to do the setup before calling them!
|
||||
|
@ -13,8 +13,7 @@
|
|||
|
||||
#include "iso14443a.h"
|
||||
#include "epa.h"
|
||||
#include "../common/cmd.h"
|
||||
|
||||
#include "cmd.h"
|
||||
|
||||
// Protocol and Parameter Selection Request
|
||||
// use regular (1x) speed in both directions
|
||||
|
@ -75,6 +74,32 @@ static const uint8_t oid_pace_start[] = {
|
|||
0x04 // id-PACE
|
||||
};
|
||||
|
||||
// APDUs for replaying:
|
||||
// MSE: Set AT (initiate PACE)
|
||||
static uint8_t apdu_replay_mse_set_at_pace[41];
|
||||
// General Authenticate (Get Nonce)
|
||||
static uint8_t apdu_replay_general_authenticate_pace_get_nonce[8];
|
||||
// General Authenticate (Map Nonce)
|
||||
static uint8_t apdu_replay_general_authenticate_pace_map_nonce[75];
|
||||
// General Authenticate (Mutual Authenticate)
|
||||
static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate[75];
|
||||
// General Authenticate (Perform Key Agreement)
|
||||
static uint8_t apdu_replay_general_authenticate_pace_perform_key_agreement[18];
|
||||
// pointers to the APDUs (for iterations)
|
||||
static struct {
|
||||
uint8_t len;
|
||||
uint8_t *data;
|
||||
} const apdus_replay[] = {
|
||||
{sizeof(apdu_replay_mse_set_at_pace), apdu_replay_mse_set_at_pace},
|
||||
{sizeof(apdu_replay_general_authenticate_pace_get_nonce), apdu_replay_general_authenticate_pace_get_nonce},
|
||||
{sizeof(apdu_replay_general_authenticate_pace_map_nonce), apdu_replay_general_authenticate_pace_map_nonce},
|
||||
{sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate), apdu_replay_general_authenticate_pace_mutual_authenticate},
|
||||
{sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement), apdu_replay_general_authenticate_pace_perform_key_agreement}
|
||||
};
|
||||
|
||||
// lengths of the replay APDUs
|
||||
static uint8_t apdu_lengths_replay[5];
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Closes the communication channel and turns off the field
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -216,11 +241,6 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length)
|
|||
//-----------------------------------------------------------------------------
|
||||
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();
|
||||
|
||||
|
@ -247,15 +267,10 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
|
|||
// return value of a function
|
||||
int func_return = 0;
|
||||
|
||||
// // 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);
|
||||
Dbprintf("epa: setup fucked up! %d", func_return);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -265,13 +280,10 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
|
|||
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) {
|
||||
Dbprintf("epa: Too small!");
|
||||
EPA_PACE_Collect_Nonce_Abort(2, card_access_length);
|
||||
return;
|
||||
}
|
||||
|
||||
Dbprintf("epa: foo!");
|
||||
|
||||
// this will hold the PACE info of the card
|
||||
pace_version_info_t pace_version_info;
|
||||
// search for the PACE OID
|
||||
|
@ -283,8 +295,6 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
|
|||
return;
|
||||
}
|
||||
|
||||
Dbprintf("epa: bar!");
|
||||
|
||||
// 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);
|
||||
|
@ -304,8 +314,6 @@ void EPA_PACE_Collect_Nonce(UsbCommand *c)
|
|||
EPA_Finish();
|
||||
|
||||
// save received information
|
||||
// ack->arg[1] = func_return;
|
||||
// memcpy(ack->d.asBytes, nonce, func_return);
|
||||
cmd_send(CMD_ACK,0,func_return,0,nonce,func_return);
|
||||
}
|
||||
|
||||
|
@ -414,13 +422,79 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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 = iso14_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;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set up a communication channel (Card Select, PPS)
|
||||
// Returns 0 on success or a non-zero error code on failure
|
||||
//-----------------------------------------------------------------------------
|
||||
int EPA_Setup()
|
||||
{
|
||||
|
||||
int return_code = 0;
|
||||
uint8_t uid[10];
|
||||
uint8_t pps_response[3];
|
||||
|
@ -429,20 +503,16 @@ int EPA_Setup()
|
|||
|
||||
// power up the field
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
// select the card
|
||||
return_code = iso14443a_select_card(uid, &card_select_info, NULL);
|
||||
if (return_code != 1) {
|
||||
Dbprintf("Epa: Can't select card");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// send the PPS request
|
||||
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);
|
||||
return_code = ReaderReceive(pps_response, pps_response_par);
|
||||
if (return_code != 3 || pps_response[0] != 0xD0) {
|
||||
return return_code == 0 ? 2 : return_code;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue