[PATCH GnuPG 1/2] scd: allow to query FCP when selecting an application

Mario Haustein mario.haustein at hrz.tu-chemnitz.de
Sun Jan 4 17:06:54 CET 2026


* scd/iso7816.c (iso7816_select_application_ext): Add flag die query FCP
* scd/iso7816.h: define new response type flags
* scd/app.c: apply new flags
* scd/app-piv.c: ditto
* scd/app-p15.c: query FCI during application selection and fallback to
  FCP if file ID tag 0x83 is not found.

--
Some cards (for example STARCOS 3.7 based D-Trust Cards 6.1/6.4) don't
return the file ID of the application in the FCI response of the SELECT
command (P2=0x00). Instead the file ID is only returned if the FCP is
queried in the SELECT command (P2=0x04).

If the file ID is not returned in the FCI, we will fall back to the FCP
and then to the default home file ID if the FCP also fails.

Signed-off-by: Mario Haustein <mario.haustein at hrz.tu-chemnitz.de>
---
 scd/app-p15.c | 48 +++++++++++++++++++++++++++++++++++++++++-------
 scd/app-piv.c |  4 ++--
 scd/app.c     |  2 +-
 scd/iso7816.c | 15 +++++++++++++--
 scd/iso7816.h |  5 +++++
 5 files changed, 62 insertions(+), 12 deletions(-)

diff --git a/scd/app-p15.c b/scd/app-p15.c
index f5c5f7a17..d12179bb4 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -6431,6 +6431,8 @@ app_select_p15 (app_t app)
 {
   int slot = app_get_slot (app);
   int rc;
+  const char *aid;
+  size_t aidlen;
   unsigned short def_home_df = 0;
   card_type_t card_type = CARD_TYPE_UNKNOWN;
   int direct = 0;
@@ -6438,14 +6440,17 @@ app_select_p15 (app_t app)
   unsigned char *fci = NULL;
   size_t fcilen;
 
-  rc = iso7816_select_application_ext (slot, pkcs15_aid, sizeof pkcs15_aid, 
1,
-                                       &fci, &fcilen);
+  aid = pkcs15_aid;
+  aidlen = sizeof pkcs15_aid;
+  rc = iso7816_select_application_ext (slot, aid, aidlen,
+                                       ISO7816_SELECT_FCI, &fci, &fcilen);
   if (rc)
     {
       /* D-TRUST Card 4.x uses a different AID. */
-      rc = iso7816_select_application_ext (slot, pkcs15dtrust4_aid,
-                                           sizeof pkcs15dtrust4_aid, 1,
-                                           &fci, &fcilen);
+      aid = pkcs15dtrust4_aid;
+      aidlen = sizeof pkcs15dtrust4_aid;
+      rc = iso7816_select_application_ext (slot, aid, aidlen,
+                                           ISO7816_SELECT_FCI, &fci, 
&fcilen);
     }
   if (rc)
     { /* Not found: Try to locate it from 2F00.  We use direct path
@@ -6516,7 +6521,7 @@ app_select_p15 (app_t app)
           goto leave;
         }
 
-      /* Set the home DF from the FCI returned by the select.  */
+      /* Set the home DF from the FCI returned by the select. */
       if (!def_home_df && fci)
         {
           const unsigned char *s;
@@ -6525,14 +6530,43 @@ app_select_p15 (app_t app)
           s = find_tlv (fci, fcilen, 0x83, &n);
           if (s && n == 2)
             def_home_df = buf16_to_ushort (s);
+          else if (fcilen)
+            {
+              log_printhex (fci, fcilen, "fci:");
+              log_info ("p15: select did not return the DF - querying 
FCP\n");
+            }
+        }
+
+      /* Set the home DF from the FCP returned by the select, when not 
already
+       * contained in the FCI. STARCOS 3.7 (at least the D-Trust Card 6.1/6.4
+       * requires to request FCP instead of FCI. */
+      if (!def_home_df)
+        {
+          const unsigned char *s;
+          size_t n;
+
+          xfree (fci);
+
+          fci = NULL;
+          fcilen = 0;
+          rc = iso7816_select_application_ext (slot, aid, aidlen,
+                                               ISO7816_SELECT_FCP, &fci, 
&fcilen);
+
+          if (!rc && fci)
+            {
+              s = find_tlv (fci, fcilen, 0x83, &n);
+              if (s && n == 2)
+                def_home_df = buf16_to_ushort (s);
+            }
           else
             {
               if (fcilen)
-                log_printhex (fci, fcilen, "fci:");
+                log_printhex (fci, fcilen, "fcp:");
               log_info ("p15: select did not return the DF - using 
default\n");
               def_home_df = DEFAULT_HOME_DF;
             }
         }
+
       app->app_local->home_df = def_home_df;
 
       /* Store the card type.  FIXME: We might want to put this into
diff --git a/scd/app-piv.c b/scd/app-piv.c
index f35815e58..a5f2d6219 100644
--- a/scd/app-piv.c
+++ b/scd/app-piv.c
@@ -3684,8 +3684,8 @@ app_select_piv (app_t app)
   /* Note that we select using the AID without the 2 octet version
    * number.  This allows for better reporting of future specs.  We
    * need to use the use-zero-for-P2-flag.  */
-  err = iso7816_select_application_ext (slot, piv_aid, sizeof piv_aid, 
0x0001,
-                                        &apt, &aptlen);
+  err = iso7816_select_application_ext (slot, piv_aid, sizeof piv_aid,
+                                        ISO7816_SELECT_FCI, &apt, &aptlen);
   if (err)
     goto leave;
 
diff --git a/scd/app.c b/scd/app.c
index f08067e87..0329d3fb0 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -792,7 +792,7 @@ app_new_register (int slot, ctrl_t ctrl, const char *name,
                       buf = NULL;
                       if (!iso7816_select_application_ext (slot,
                                                        otp_aid, sizeof 
otp_aid,
-                                                       1, &buf, &buflen)
+                                                       ISO7816_SELECT_FCI, 
&buf, &buflen)
                           && buflen > 3)
                         card->cardversion = ((buf[0]<<16)|(buf[1]<<8)|
buf[2]);
                     }
diff --git a/scd/iso7816.c b/scd/iso7816.c
index 6634cd4a7..533e579de 100644
--- a/scd/iso7816.c
+++ b/scd/iso7816.c
@@ -152,9 +152,20 @@ iso7816_select_application_ext (int slot, const char 
*aid, size_t aidlen,
                                 unsigned int flags,
                                 unsigned char **result, size_t *resultlen)
 {
+  int p2;
   int sw;
-  sw = apdu_send (slot, 0, 0x00, CMD_SELECT_FILE, 4,
-                  (flags&1)? 0:0x0c, aidlen, aid,
+
+  switch (flags)
+    {
+    case ISO7816_SELECT_FCI: p2 = 0x00; break;
+    case ISO7816_SELECT_FCP: p2 = 0x04; break;
+    case ISO7816_SELECT_NORESP:
+    default:
+      p2 = 0x0c;
+    }
+
+  sw = apdu_send (slot, 0, 0x00, CMD_SELECT_FILE, 4, p2,
+                  aidlen, aid,
                   result, resultlen);
   return map_sw (sw);
 }
diff --git a/scd/iso7816.h b/scd/iso7816.h
index 67b9f47ab..aef5c2092 100644
--- a/scd/iso7816.h
+++ b/scd/iso7816.h
@@ -29,6 +29,11 @@
 #define ISO7816_CHANGE_REFERENCE_DATA 0x24
 #define ISO7816_RESET_RETRY_COUNTER   0x2C
 
+/* Flags to encode which data should be returned by SELECT */
+#define ISO7816_SELECT_NORESP  0       /* no response to SELECT */
+#define ISO7816_SELECT_FCI     1       /* query FCI (file control 
information) by SELECT */
+#define ISO7816_SELECT_FCP     2       /* query FCP (file control parameters) 
by SELECT */
+
 /* Error codes returned by iso7816_verify_status.  A non-negative
  * number gives the number of left tries.
  * NB: The values are also used by the CHV-STATUS lines and thus are
-- 
2.52.0
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 870 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.gnupg.org/pipermail/gnupg-devel/attachments/20260104/975a1199/attachment.sig>


More information about the Gnupg-devel mailing list