1 //----------------------------------------------------------------------------- 
   2 // Frederik Möllers - August 2012 
   4 // This code is licensed to you under the terms of the GNU GPL, version 2 or, 
   5 // at your option, any later version. See the LICENSE.txt file for the text of 
   7 //----------------------------------------------------------------------------- 
   8 // Routines to support the German electronic "Personalausweis" (ID card) 
   9 // Note that the functions which do not implement USB commands do NOT initialize 
  10 // the card (with iso14443a_select_card etc.). If You want to use these 
  11 // functions, You need to do the setup before calling them! 
  12 //----------------------------------------------------------------------------- 
  15 #include "iso14443a.h" 
  16 #include "iso14443b.h" 
  19 #include "fpgaloader.h" 
  23 // Protocol and Parameter Selection Request for ISO 14443 type A cards 
  24 // use regular (1x) speed in both directions 
  25 // CRC is already included 
  26 static const uint8_t pps
[] = {0xD0, 0x11, 0x00, 0x52, 0xA6}; 
  28 // APDUs for communication with German Identification Card 
  30 // General Authenticate (request encrypted nonce) WITHOUT the Le at the end 
  31 static const uint8_t apdu_general_authenticate_pace_get_nonce
[] = { 
  37         0x7C, // Type: Dynamic Authentication Data 
  38         0x00, // Length: 0 bytes 
  41 // MSE: Set AT (only CLA, INS, P1 and P2) 
  42 static const uint8_t apdu_mse_set_at_start
[] = { 
  49 // SELECT BINARY with the ID for EF.CardAccess 
  50 static const uint8_t apdu_select_binary_cardaccess
[] = { 
  61 static const uint8_t apdu_read_binary
[] = { 
  70 // the leading bytes of a PACE OID 
  71 static const uint8_t oid_pace_start
[] = { 
  72     0x04, // itu-t, identified-organization 
  75     0x00, // etsi-identified-organization 
  82 // APDUs for replaying: 
  83 // MSE: Set AT (initiate PACE) 
  84 static uint8_t apdu_replay_mse_set_at_pace
[41]; 
  85 // General Authenticate (Get Nonce) 
  86 static uint8_t apdu_replay_general_authenticate_pace_get_nonce
[8]; 
  87 // General Authenticate (Map Nonce) 
  88 static uint8_t apdu_replay_general_authenticate_pace_map_nonce
[75]; 
  89 // General Authenticate (Mutual Authenticate) 
  90 static uint8_t apdu_replay_general_authenticate_pace_mutual_authenticate
[75]; 
  91 // General Authenticate (Perform Key Agreement) 
  92 static uint8_t apdu_replay_general_authenticate_pace_perform_key_agreement
[18]; 
  93 // pointers to the APDUs (for iterations) 
  97 } const apdus_replay
[] = { 
  98         {sizeof(apdu_replay_mse_set_at_pace
), apdu_replay_mse_set_at_pace
}, 
  99         {sizeof(apdu_replay_general_authenticate_pace_get_nonce
), apdu_replay_general_authenticate_pace_get_nonce
}, 
 100         {sizeof(apdu_replay_general_authenticate_pace_map_nonce
), apdu_replay_general_authenticate_pace_map_nonce
}, 
 101         {sizeof(apdu_replay_general_authenticate_pace_mutual_authenticate
), apdu_replay_general_authenticate_pace_mutual_authenticate
}, 
 102         {sizeof(apdu_replay_general_authenticate_pace_perform_key_agreement
), apdu_replay_general_authenticate_pace_perform_key_agreement
} 
 105 // lengths of the replay APDUs 
 106 static uint8_t apdu_lengths_replay
[5]; 
 108 // type of card (ISO 14443 A or B) 
 109 static char iso_type 
= 0; 
 111 //----------------------------------------------------------------------------- 
 112 // Wrapper for sending APDUs to type A and B cards 
 113 //----------------------------------------------------------------------------- 
 114 int EPA_APDU(uint8_t *apdu
, size_t length
, uint8_t *response
) 
 119                         return iso14_apdu(apdu
, (uint16_t) length
, false, response
, NULL
); 
 122                         return iso14443b_apdu(apdu
, length
, response
); 
 130 //----------------------------------------------------------------------------- 
 131 // Closes the communication channel and turns off the field 
 132 //----------------------------------------------------------------------------- 
 135         FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF
); 
 140 //----------------------------------------------------------------------------- 
 141 // Parses DER encoded data, e.g. from EF.CardAccess and fills out the given 
 142 // structs. If a pointer is 0, it is ignored. 
 143 // The function returns 0 on success and if an error occured, it returns the 
 144 // offset where it occured. 
 146 // TODO: This function can access memory outside of the given data if the DER 
 147 //       encoding is broken 
 148 // TODO: Support skipping elements with a length > 0x7F 
 149 // TODO: Support OIDs with a length > 7F 
 150 // TODO: Support elements with long tags (tag is longer than 1 byte) 
 151 // TODO: Support proprietary PACE domain parameters 
 152 //----------------------------------------------------------------------------- 
 153 size_t EPA_Parse_CardAccess(uint8_t *data
, 
 155                             pace_version_info_t 
*pace_info
) 
 159         while (index 
<= length 
- 2) { 
 160                 // determine type of element 
 162                 if (data
[index
] == 0x31 || data
[index
] == 0x30) { 
 163                         // enter the set (skip tag + length) 
 165                         // check for extended length 
 166                         if ((data
[index 
- 1] & 0x80) != 0) { 
 167                                 index 
+= (data
[index
-1] & 0x7F); 
 171                 else if (data
[index
] == 0x06) { 
 172                         // is this a PACE OID? 
 173                         if (data
[index 
+ 1] == 0x0A // length matches 
 174                             && memcmp(data 
+ index 
+ 2, 
 176                                       sizeof(oid_pace_start
)) == 0 // content matches 
 177                             && pace_info 
!= NULL
) 
 179                                 // first, clear the pace_info struct 
 180                                 memset(pace_info
, 0, sizeof(pace_version_info_t
)); 
 181                                 memcpy(pace_info
->oid
, data 
+ index 
+ 2, sizeof(pace_info
->oid
)); 
 182                                 // a PACE OID is followed by the version 
 183                                 index 
+= data
[index 
+ 1] + 2; 
 184                                 if (data
[index
] == 02 && data
[index 
+ 1] == 01) { 
 185                                         pace_info
->version 
= data
[index 
+ 2]; 
 191                                 // after that there might(!) be the parameter ID 
 192                                 if (data
[index
] == 02 && data
[index 
+ 1] == 01) { 
 193                                         pace_info
->parameter_id 
= data
[index 
+ 2]; 
 199                                 index 
+= 2 + data
[index 
+ 1]; 
 202                 // if the length is 0, something is wrong 
 203                 // TODO: This needs to be extended to support long tags 
 204                 else if (data
[index 
+ 1] == 0) { 
 209                         // TODO: This needs to be extended to support long tags 
 210                         // TODO: This needs to be extended to support unknown elements with 
 212                         index 
+= 2 + data
[index 
+ 1]; 
 216         // TODO: We should check whether we reached the end in error, but for that 
 217         //       we need a better parser (e.g. with states like IN_SET or IN_PACE_INFO) 
 221 //----------------------------------------------------------------------------- 
 222 // Read the file EF.CardAccess and save it into a buffer (at most max_length bytes) 
 223 // Returns -1 on failure or the length of the data on success 
 224 // TODO: for the moment this sends only 1 APDU regardless of the requested length 
 225 //----------------------------------------------------------------------------- 
 226 int EPA_Read_CardAccess(uint8_t *buffer
, size_t max_length
) 
 228         // the response APDU of the card 
 229         // since the card doesn't always care for the expected length we send it, 
 230         // we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame) 
 231         uint8_t response_apdu
[262]; 
 232         int rapdu_length 
= 0; 
 234         // select the file EF.CardAccess 
 235         rapdu_length 
= EPA_APDU((uint8_t *)apdu_select_binary_cardaccess
, 
 236                                   sizeof(apdu_select_binary_cardaccess
), 
 239             || response_apdu
[rapdu_length 
- 4] != 0x90 
 240             || response_apdu
[rapdu_length 
- 3] != 0x00) 
 242                 DbpString("Failed to select EF.CardAccess!"); 
 247         rapdu_length 
= EPA_APDU((uint8_t *)apdu_read_binary
, 
 248                                   sizeof(apdu_read_binary
), 
 250         if (rapdu_length 
<= 6 
 251             || response_apdu
[rapdu_length 
- 4] != 0x90 
 252             || response_apdu
[rapdu_length 
- 3] != 0x00) 
 254                 Dbprintf("Failed to read EF.CardAccess!"); 
 258         // copy the content into the buffer 
 259         // length of data available: apdu_length - 4 (ISO frame) - 2 (SW) 
 260         size_t to_copy 
= rapdu_length 
- 6; 
 261         to_copy 
= to_copy 
< max_length 
? to_copy 
: max_length
; 
 262         memcpy(buffer
, response_apdu
+2, to_copy
); 
 266 //----------------------------------------------------------------------------- 
 267 // Abort helper function for EPA_PACE_Collect_Nonce 
 268 // sets relevant data in ack, sends the response 
 269 //----------------------------------------------------------------------------- 
 270 static void EPA_PACE_Collect_Nonce_Abort(uint8_t step
, int func_return
) 
 272         // power down the field 
 275         // send the USB packet 
 276         cmd_send(CMD_ACK
,step
,func_return
,0,0,0); 
 279 //----------------------------------------------------------------------------- 
 280 // Acquire one encrypted PACE nonce 
 281 //----------------------------------------------------------------------------- 
 282 void EPA_PACE_Collect_Nonce(UsbCommand 
*c
) 
 288          *           step where the error occured or 0 if no error occured 
 290      *           return code of the last executed function 
 295         // return value of a function 
 298         // set up communication 
 299         func_return 
= EPA_Setup(); 
 300         if (func_return 
!= 0) { 
 301                 EPA_PACE_Collect_Nonce_Abort(1, func_return
); 
 305         // read the CardAccess file 
 306         // this array will hold the CardAccess file 
 307         uint8_t card_access
[256] = {0}; 
 308         int card_access_length 
= EPA_Read_CardAccess(card_access
, 256); 
 309         // the response has to be at least this big to hold the OID 
 310         if (card_access_length 
< 18) { 
 311                 EPA_PACE_Collect_Nonce_Abort(2, card_access_length
); 
 315         // this will hold the PACE info of the card 
 316         pace_version_info_t pace_version_info
; 
 317         // search for the PACE OID 
 318         func_return 
= EPA_Parse_CardAccess(card_access
, 
 321         if (func_return 
!= 0 || pace_version_info
.version 
== 0) { 
 322                 EPA_PACE_Collect_Nonce_Abort(3, func_return
); 
 326         // initiate the PACE protocol 
 327         // use the CAN for the password since that doesn't change 
 328         func_return 
= EPA_PACE_MSE_Set_AT(pace_version_info
, 2); 
 331         uint8_t nonce
[256] = {0}; 
 332         uint8_t requested_size 
= (uint8_t)c
->arg
[0]; 
 333         func_return 
= EPA_PACE_Get_Nonce(requested_size
, nonce
); 
 334         // check if the command succeeded 
 337                 EPA_PACE_Collect_Nonce_Abort(4, func_return
); 
 344         // save received information 
 345         cmd_send(CMD_ACK
,0,func_return
,0,nonce
,func_return
); 
 348 //----------------------------------------------------------------------------- 
 349 // Performs the "Get Nonce" step of the PACE protocol and saves the returned 
 350 // nonce. The caller is responsible for allocating enough memory to store the 
 351 // nonce. Note that the returned size might be less or than or greater than the 
 353 // Returns the actual size of the nonce on success or a less-than-zero error 
 355 //----------------------------------------------------------------------------- 
 356 int EPA_PACE_Get_Nonce(uint8_t requested_length
, uint8_t *nonce
) 
 359         uint8_t apdu
[sizeof(apdu_general_authenticate_pace_get_nonce
) + 1]; 
 360         // copy the constant part 
 362                apdu_general_authenticate_pace_get_nonce
, 
 363                sizeof(apdu_general_authenticate_pace_get_nonce
)); 
 364         // append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU 
 365         apdu
[sizeof(apdu_general_authenticate_pace_get_nonce
)] = requested_length 
+ 4; 
 368         uint8_t response_apdu
[262]; 
 369         int send_return 
= EPA_APDU(apdu
, 
 372         // check if the command succeeded 
 374                 || response_apdu
[send_return 
- 4] != 0x90 
 375                 || response_apdu
[send_return 
- 3] != 0x00) 
 380         // if there is no nonce in the RAPDU, return here 
 381         if (send_return 
< 10) 
 386         // get the actual length of the nonce 
 387         uint8_t nonce_length 
= response_apdu
[5]; 
 388         if (nonce_length 
> send_return 
- 10) 
 390                 nonce_length 
= send_return 
- 10; 
 393         memcpy(nonce
, response_apdu 
+ 6, nonce_length
); 
 398 //----------------------------------------------------------------------------- 
 399 // Initializes the PACE protocol by performing the "MSE: Set AT" step 
 400 // Returns 0 on success or a non-zero error code on failure 
 401 //----------------------------------------------------------------------------- 
 402 int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info
, uint8_t password
) 
 404         // create the MSE: Set AT APDU 
 406         // the minimum length (will be increased as more data is added) 
 407         size_t apdu_length 
= 20; 
 408         // copy the constant part 
 410                apdu_mse_set_at_start
, 
 411                sizeof(apdu_mse_set_at_start
)); 
 415         apdu
[6] = sizeof(pace_version_info
.oid
); 
 418                pace_version_info
.oid
, 
 419                sizeof(pace_version_info
.oid
)); 
 426         // if standardized domain parameters are used, copy the ID 
 427         if (pace_version_info
.parameter_id 
!= 0) { 
 429                 // type: domain parameter 
 433                 // copy the parameter ID 
 434                 apdu
[22] = pace_version_info
.parameter_id
; 
 436         // now set Lc to the actual length 
 437         apdu
[4] = apdu_length 
- 5; 
 439         uint8_t response_apdu
[6]; 
 440         int send_return 
= EPA_APDU(apdu
, 
 443         // check if the command succeeded 
 445                 || response_apdu
[send_return 
- 4] != 0x90 
 446                 || response_apdu
[send_return 
- 3] != 0x00) 
 453 //----------------------------------------------------------------------------- 
 454 // Perform the PACE protocol by replaying given APDUs 
 455 //----------------------------------------------------------------------------- 
 456 void EPA_PACE_Replay(UsbCommand 
*c
) 
 458         uint32_t timings
[sizeof(apdu_lengths_replay
) / sizeof(apdu_lengths_replay
[0])] = {0}; 
 460         // if an APDU has been passed, save it 
 461         if (c
->arg
[0] != 0) { 
 462                 // make sure it's not too big 
 463                 if(c
->arg
[2] > apdus_replay
[c
->arg
[0] - 1].len
) 
 465                         cmd_send(CMD_ACK
, 1, 0, 0, NULL
, 0); 
 467                 memcpy(apdus_replay
[c
->arg
[0] - 1].data 
+ c
->arg
[1], 
 470                 // save/update APDU length 
 471                 if (c
->arg
[1] == 0) { 
 472                         apdu_lengths_replay
[c
->arg
[0] - 1] = c
->arg
[2]; 
 474                         apdu_lengths_replay
[c
->arg
[0] - 1] += c
->arg
[2]; 
 476                 cmd_send(CMD_ACK
, 0, 0, 0, NULL
, 0); 
 480         // return value of a function 
 483         // set up communication 
 484         func_return 
= EPA_Setup(); 
 485         if (func_return 
!= 0) { 
 487                 cmd_send(CMD_ACK
, 2, func_return
, 0, NULL
, 0); 
 492         uint8_t response_apdu
[300] = {0}; 
 494         // now replay the data and measure the timings 
 495         for (int i 
= 0; i 
< sizeof(apdu_lengths_replay
); i
++) { 
 497                 func_return 
= EPA_APDU(apdus_replay
[i
].data
, 
 498                                          apdu_lengths_replay
[i
], 
 500                 timings
[i
] = GetCountUS(); 
 501                 // every step but the last one should succeed 
 502                 if (i 
< sizeof(apdu_lengths_replay
) - 1 
 504                         || response_apdu
[func_return 
- 4] != 0x90 
 505                         || response_apdu
[func_return 
- 3] != 0x00)) 
 508                         cmd_send(CMD_ACK
, 3 + i
, func_return
, 0, timings
, 20); 
 513         cmd_send(CMD_ACK
,0,0,0,timings
,20); 
 517 //----------------------------------------------------------------------------- 
 518 // Set up a communication channel (Card Select, PPS) 
 519 // Returns 0 on success or a non-zero error code on failure 
 520 //----------------------------------------------------------------------------- 
 525         uint8_t pps_response
[3]; 
 526         uint8_t pps_response_par
[1]; 
 527         iso14a_card_select_t card_select_info
; 
 529         // first, look for type A cards 
 530         // power up the field 
 531         iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD
); 
 533         return_code 
= iso14443a_select_card(uid
, &card_select_info
, NULL
, true, 0, false); 
 534         if (return_code 
== 1) { 
 535                 // send the PPS request 
 536                 ReaderTransmit((uint8_t *)pps
, sizeof(pps
), NULL
); 
 537                 return_code 
= ReaderReceive(pps_response
, pps_response_par
); 
 538                 if (return_code 
!= 3 || pps_response
[0] != 0xD0) { 
 539                         return return_code 
== 0 ? 2 : return_code
; 
 541                 Dbprintf("ISO 14443 Type A"); 
 546         // if we're here, there is no type A card, so we look for type B 
 547         // power up the field 
 550         return_code 
= iso14443b_select_card(); 
 551         if (return_code 
== 1) { 
 552                 Dbprintf("ISO 14443 Type B"); 
 556         Dbprintf("No card found.");