@@ -310,6 +310,98 @@ static const char* iso7816_capdu_read_record_get_string(
310
310
}
311
311
}
312
312
313
+ static const char * iso7816_capdu_put_data_get_string (
314
+ const uint8_t * c_apdu ,
315
+ size_t c_apdu_len ,
316
+ char * str ,
317
+ size_t str_len
318
+ )
319
+ {
320
+ enum iso7816_apdu_case_t apdu_case ;
321
+ struct iso7816_apdu_case_3s_t * apdu_case_3s ;
322
+ uint8_t P1 ;
323
+ uint8_t P2 ;
324
+
325
+ if ((c_apdu [0 ] & ISO7816_CLA_PROPRIETARY ) != 0 ||
326
+ (c_apdu [1 ] != 0xDA && c_apdu [1 ] != 0xDB )
327
+ ) {
328
+ // Not PUT DATA
329
+ return NULL ;
330
+ }
331
+
332
+ // PUT DATA must be APDU case 3S/3E but only support 3S for now
333
+ // See ISO 7816-4:2005, 7.4.3, table 64
334
+ apdu_case = iso7816_apdu_case (c_apdu , c_apdu_len );
335
+ switch (apdu_case ) {
336
+ case ISO7816_APDU_CASE_3S :
337
+ apdu_case_3s = (void * )c_apdu ;
338
+ break ;
339
+
340
+ case ISO7816_APDU_CASE_3E :
341
+ // Unsupported APDU case for PUT DATA
342
+ snprintf (str , str_len , "PUT DATA" );
343
+ return str ;
344
+
345
+ default :
346
+ // Invalid APDU case for PUT DATA
347
+ return NULL ;
348
+ }
349
+
350
+ // Extract P1 and P2 for convenience
351
+ P1 = apdu_case_3s -> P1 ;
352
+ P2 = apdu_case_3s -> P2 ;
353
+
354
+ // Decode P1 and P2
355
+ // See ISO 7816-4:2005, 7.4.1, table 62
356
+ if ((c_apdu [1 ] & 0x01 ) == 0 ) {
357
+ // Even INS code
358
+ if (P1 == 0 && P2 >= 0x40 && P2 <= 0xFE ) {
359
+ // P2 is 1-byte BER-TLV tag
360
+ snprintf (str , str_len , "PUT DATA for BER-TLV field %02X" , P2 );
361
+ return str ;
362
+ } else if (P1 == 1 ) {
363
+ // P2 is proprietary
364
+ snprintf (str , str_len , "PUT DATA for proprietary identifier %02X" , P2 );
365
+ return str ;
366
+ } else if (P1 == 2 && P2 >= 0x01 && P2 <= 0xFE ) {
367
+ // P2 is 1-byte SIMPLE-TLV tag
368
+ snprintf (str , str_len , "PUT DATA for SIMPLE-TLV field %02X" , P2 );
369
+ return str ;
370
+ } else if (P1 >= 0x40 ) {
371
+ // P1-P2 is 2-byte BER-TLV tag
372
+ snprintf (str , str_len , "PUT DATA for BER-TLV field %02X%02X" , P1 , P2 );
373
+ return str ;
374
+ }
375
+ } else {
376
+ // Odd INS code
377
+ if (P1 == 0x00 && (P2 & 0xE0 ) == 0x00 && // Highest 11 bits of P1-P2 are unset
378
+ (P2 & 0x1F ) != 0x00 && (P2 & 0x1F ) != 0x1F // Lowest 5 bits are not equal
379
+ ) {
380
+ // P2 is short EF identifier
381
+ snprintf (str , str_len , "PUT DATA for short EF %u" , P2 );
382
+ return str ;
383
+ } else if (P1 == 0x3F && P2 == 0xFF ) { // P1-P2 is 3FFF
384
+ // P1-P2 is current DF
385
+ snprintf (str , str_len , "PUT DATA for current DF" );
386
+ return str ;
387
+ } else if (P1 == 0x00 && P2 == 0x00 && // P1-P2 is 0000
388
+ apdu_case_3s -> Lc == 0 // No command data
389
+ ) {
390
+ // P1-P2 is current EF
391
+ snprintf (str , str_len , "PUT DATA for current EF" );
392
+ return str ;
393
+ } else if (P1 != 0x00 || P2 != 0x00 ) { // P1-P2 is not 0000
394
+ // P1-P2 is file identifier
395
+ snprintf (str , str_len , "PUT DATA for file %02X%02X" , P1 , P2 );
396
+ return str ;
397
+ }
398
+ }
399
+
400
+ // Unknown P1 and P2
401
+ snprintf (str , str_len , "PUT DATA" );
402
+ return str ;
403
+ }
404
+
313
405
const char * iso7816_capdu_get_string (
314
406
const void * c_apdu ,
315
407
size_t c_apdu_len ,
@@ -386,7 +478,7 @@ const char* iso7816_capdu_get_string(
386
478
case 0xD6 :
387
479
case 0xD7 : ins_str = "UPDATE BINARY" ; break ;
388
480
case 0xDA :
389
- case 0xDB : ins_str = "PUT DATA" ; break ;
481
+ case 0xDB : return iso7816_capdu_put_data_get_string ( c_apdu , c_apdu_len , str , str_len ) ;
390
482
case 0xDC :
391
483
case 0xDD : ins_str = "UPDATE RECORD" ; break ;
392
484
case 0xE0 : ins_str = "CREATE FILE" ; break ;
0 commit comments