@@ -137,6 +137,9 @@ struct emv_txn_t {
137
137
138
138
// ICC data
139
139
struct emv_tlv_list_t icc ;
140
+
141
+ // Cardholder application selection required?
142
+ bool application_selection_required ;
140
143
};
141
144
static struct emv_txn_t emv_txn ;
142
145
@@ -388,6 +391,7 @@ int main(int argc, char** argv)
388
391
size_t reader_idx ;
389
392
uint8_t atr [PCSC_MAX_ATR_SIZE ];
390
393
size_t atr_len = 0 ;
394
+ bool first_application_selection_prompt = true;
391
395
392
396
if (argc == 1 ) {
393
397
// No command line arguments
@@ -539,71 +543,127 @@ int main(int argc, char** argv)
539
543
goto emv_exit ;
540
544
}
541
545
542
- if (emv_app_list_is_empty (& app_list )) {
543
- printf ("No supported applications\n" );
544
- goto emv_exit ;
545
- }
546
-
547
546
printf ("Candidate applications:\n" );
548
547
for (struct emv_app_t * app = app_list .front ; app != NULL ; app = app -> next ) {
549
548
print_emv_app (app );
550
549
}
551
550
552
- if (emv_app_list_selection_is_required (& app_list )) {
551
+ emv_txn .application_selection_required = emv_app_list_selection_is_required (& app_list );
552
+ if (emv_txn .application_selection_required ) {
553
553
printf ("Cardholder selection is required\n" );
554
554
}
555
555
556
- // HACK: test application selection
557
- {
558
- char str [1024 ];
556
+ do {
557
+ struct emv_app_t * current_app ;
559
558
560
- // Use first application
561
- struct emv_app_t * current_app = emv_app_list_pop (& app_list );
562
- if (!current_app ) {
563
- printf ("No supported applications\n" );
559
+ // All application selection failures return to the start of the loop
560
+ // If no applications remain, terminate session
561
+ // See EMV 4.4 Book 1, 12.4
562
+ // See EMV 4.4 Book 4, 11.3
563
+ if (emv_app_list_is_empty (& app_list )) {
564
+ emv_debug_info ("Candidate list empty" );
565
+ printf ("OUTCOME: %s\n" , emv_outcome_get_string (EMV_OUTCOME_NOT_ACCEPTED ));
564
566
goto emv_exit ;
565
567
}
566
- emv_app_list_clear (& app_list );
567
-
568
- uint8_t current_aid [16 ];
569
- size_t current_aid_len = current_app -> aid -> length ;
570
- memcpy (current_aid , current_app -> aid -> value , current_app -> aid -> length );
571
- emv_app_free (current_app );
572
- current_app = NULL ;
573
-
574
- // Select application
575
- print_buf ("\nSELECT application" , current_aid , current_aid_len );
576
- uint8_t fci [EMV_RAPDU_DATA_MAX ];
577
- size_t fci_len = sizeof (fci );
578
- uint16_t sw1sw2 ;
579
- r = emv_ttl_select_by_df_name (& emv_txn .ttl , current_aid , current_aid_len , fci , & fci_len , & sw1sw2 );
580
- if (r ) {
581
- printf ("Failed to select application; r=%d\n" , r );
582
- goto emv_exit ;
583
- }
584
- print_buf ("FCI" , fci , fci_len );
585
- print_emv_buf (fci , fci_len , " " , 0 );
586
- printf ("SW1SW2 = %04hX (%s)\n" , sw1sw2 , iso7816_sw1sw2_get_string (sw1sw2 >> 8 , sw1sw2 & 0xff , str , sizeof (str )));
587
568
588
- if (sw1sw2 != 0x9000 ) {
589
- goto emv_exit ;
569
+ if (emv_txn .application_selection_required ) {
570
+ unsigned int app_count = 0 ;
571
+ int r ;
572
+ char s [4 ]; // two digits, newline and null
573
+ unsigned int input = 0 ;
574
+
575
+ if (first_application_selection_prompt ) {
576
+ printf ("\nSelect application:\n" );
577
+ first_application_selection_prompt = false;
578
+ } else {
579
+ // See EMV 4.4 Book 4, 11.3
580
+ printf ("\nTry again:\n" );
581
+ }
582
+ for (struct emv_app_t * app = app_list .front ; app != NULL ; app = app -> next ) {
583
+ ++ app_count ;
584
+ printf ("%u - %s\n" , app_count , app -> display_name );
585
+ }
586
+ printf ("Enter number: " );
587
+ if (!fgets (s , sizeof (s ), stdin )) {
588
+ printf ("Invalid input. Try again.\n" );
589
+ continue ;
590
+ }
591
+ r = sscanf (s , "%u" , & input );
592
+ if (r != 1 ) {
593
+ printf ("Invalid input. Try again.\n" );
594
+ continue ;
595
+ }
596
+ if (!input || input > app_count ) {
597
+ printf ("Invalid input. Try again.\n" );
598
+ continue ;
599
+ }
600
+
601
+ current_app = emv_app_list_remove_index (& app_list , input - 1 );
602
+
603
+ } else {
604
+ // Use first application
605
+ current_app = emv_app_list_pop (& app_list );
590
606
}
591
607
592
- // Create EMV application object
593
- struct emv_app_t * app ;
594
- app = emv_app_create_from_fci (fci , fci_len );
595
- if (r ) {
596
- printf ("emv_app_populate_from_fci() failed; r=%d\n" , r );
597
- goto emv_exit ;
608
+ // HACK: test application selection
609
+ {
610
+ char str [1024 ];
611
+
612
+ uint8_t current_aid [16 ];
613
+ size_t current_aid_len = current_app -> aid -> length ;
614
+ memcpy (current_aid , current_app -> aid -> value , current_app -> aid -> length );
615
+ emv_app_free (current_app );
616
+ current_app = NULL ;
617
+
618
+ // Select application
619
+ print_buf ("\nSELECT application" , current_aid , current_aid_len );
620
+ uint8_t fci [EMV_RAPDU_DATA_MAX ];
621
+ size_t fci_len = sizeof (fci );
622
+ uint16_t sw1sw2 ;
623
+ r = emv_ttl_select_by_df_name (& emv_txn .ttl , current_aid , current_aid_len , fci , & fci_len , & sw1sw2 );
624
+ if (r ) {
625
+ fprintf (stderr , "emv_ttl_select_by_df_name() failed; r=%d\n" , r );
626
+ continue ;
627
+ }
628
+ print_buf ("FCI" , fci , fci_len );
629
+ print_emv_buf (fci , fci_len , " " , 0 );
630
+ printf ("SW1SW2 = %04hX (%s)\n" , sw1sw2 , iso7816_sw1sw2_get_string (sw1sw2 >> 8 , sw1sw2 & 0xff , str , sizeof (str )));
631
+
632
+ if (sw1sw2 != 0x9000 ) {
633
+ continue ;
634
+ }
635
+
636
+ // Create EMV application object
637
+ struct emv_app_t * app ;
638
+ app = emv_app_create_from_fci (fci , fci_len );
639
+ if (r ) {
640
+ fprintf (stderr , "emv_app_populate_from_fci() failed; r=%d\n" , r );
641
+ continue ;
642
+ }
643
+ printf ("\n" );
644
+ print_emv_app (app );
645
+ print_emv_tlv_list (& app -> tlv_list );
646
+
647
+ // TODO: EMV 4.4 Book 1, 12.4, ensure that 84 matches SELECT command
648
+
649
+ // Capture ICC data
650
+ emv_txn .icc = app -> tlv_list ;
651
+ app -> tlv_list = EMV_TLV_LIST_INIT ;
652
+ emv_app_free (app );
653
+
654
+ // Application selection was successful
655
+ // TODO: EMV 4.4 Book 1, 12.4, create 9F06 from 84
656
+ break ;
598
657
}
599
- printf ("\n" );
600
- print_emv_app (app );
601
- print_emv_tlv_list (& app -> tlv_list );
658
+ } while (true);
602
659
603
- // Capture ICC data
604
- emv_txn .icc = app -> tlv_list ;
605
- app -> tlv_list = EMV_TLV_LIST_INIT ;
606
- emv_app_free (app );
660
+ // Application selection has been successful and the application list
661
+ // is no longer needed.
662
+ emv_app_list_clear (& app_list );
663
+
664
+ // HACK: test GPO and Read Application Data
665
+ {
666
+ char str [1024 ];
607
667
608
668
// Process PDOL
609
669
struct emv_tlv_t * pdol ;
@@ -660,6 +720,7 @@ int main(int argc, char** argv)
660
720
printf ("\nGET PROCESSING OPTIONS\n" );
661
721
uint8_t gpo_response [EMV_RAPDU_DATA_MAX ];
662
722
size_t gpo_response_len = sizeof (gpo_response );
723
+ uint16_t sw1sw2 ;
663
724
r = emv_ttl_get_processing_options (& emv_txn .ttl , gpo_data , gpo_data_len , gpo_response , & gpo_response_len , & sw1sw2 );
664
725
if (r ) {
665
726
printf ("Failed to get processign options; r=%d\n" , r );
0 commit comments