Hi Mario,

> For this card, all certificates have the same ID tag for each key (2 or 3 in 
> the example), as they are part of the same certificate chain. Thus the 

I have not checked the specs but I think this is Bad Idea even if
allowed. Clearly we will run into problems.

> Is there a way to avoid this unambiguity? Would it for example be possible to 
> use the path ID of the certificate file instead of the ID tag in the 

This would not solve the case if we have several certificates in one
record.  My proposed solution is to add a counter if there is any
duplicate id.  For already supported cards this should not matter and
the worst thing will be that the currently used IDs change - but they
are anyway dynamically assigned.

> Is this mailinglist the right place to discuss this issue or should I open a 
> task in the issue tracker?

Sure.  Here you get your audience.  Nevertheless I also created
https://dev.gnupg.org/T7001 for tracking.

>       0C UTF8String (32 bytes): Root-CA-Zertifikat fuer Signatur

Interesting that they provide the root CA's cert.  I doubt that this is
of any great help given that the verifier still needs to get that cert.
And everyone needs to assign trust to that certificate anyway.

Attached are two patches which I could not test.  Please let me know
whether they work for you.


Salam-Shalom,

   Werner

-- 
The pioneers of a warless world are the youth that
refuse military service.             - A. Einstein
From 7e1ab62f8dfe28dbbbd122274e98a21c35ae89a4 Mon Sep 17 00:00:00 2001
From: Werner Koch <[email protected]>
Date: Mon, 19 Feb 2024 13:51:02 +0100
Subject: [PATCH GnuPG 1/2] scd:p15: Take derive usage into account for
 decryption.

* scd/app-p15.c (set_usage_string): Map usageflags.derive also to 'e'.
(do_auth): Allow usageflags.sign_recover.
(do_decipher): Allow usageflags.derive.
(do_with_keygrip): Take usageflags.derive into account.

(do_decipher): Take a missing AODF for authentication not needed.
--

This is required for D-Trust ECC cards.

The AODF thing is unrelated but seems to be a good idea.

GnuPG-bug-id: 7000
---
 scd/app-p15.c | 33 +++++++++++++++++++--------------
 1 file changed, 19 insertions(+), 14 deletions(-)

diff --git a/scd/app-p15.c b/scd/app-p15.c
index 2bb90beaa..c9ab30fe9 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -305,7 +305,7 @@ struct prkdf_object_s
   keyaccess_flags_t accessflags;
 
   /* Extended key usage flags.  Only used if .valid is set.  This
-   * information is computed from an associated certificate15.  */
+   * information is computed from an associated certificate.  */
   struct {
     unsigned int valid:1;
     unsigned int sign:1;
@@ -4214,7 +4214,8 @@ set_usage_string (char usage[5], prkdf_object_t prkdf)
           && (!prkdf->extusage.valid || prkdf->extusage.sign))
         usage[usagelen++] = 'c';
       if ((prkdf->usageflags.decrypt
-           || prkdf->usageflags.unwrap)
+           || prkdf->usageflags.unwrap
+           || prkdf->usageflags.derive)
           && (!prkdf->extusage.valid || prkdf->extusage.encr))
         usage[usagelen++] = 'e';
       if ((prkdf->usageflags.sign
@@ -5927,7 +5928,8 @@ do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
   err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
   if (err)
     return err;
-  if (!(prkdf->usageflags.sign || prkdf->gpgusage.auth))
+  if (!(prkdf->usageflags.sign || prkdf->usageflags.sign_recover
+        || prkdf->gpgusage.auth))
     {
       log_error ("p15: key %s may not be used for authentication\n", keyidstr);
       return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
@@ -5970,6 +5972,7 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
     return err;
   if (!(prkdf->usageflags.decrypt
         || prkdf->usageflags.unwrap
+        || prkdf->usageflags.derive
         || prkdf->gpgusage.encr     ))
     {
       log_error ("p15: key %s may not be used for decryption\n", keyidstr);
@@ -5979,17 +5982,18 @@ do_decipher (app_t app, ctrl_t ctrl, const char *keyidstr,
   /* Find the authentication object to this private key object. */
   if (!prkdf->authid)
     {
-      log_error ("p15: no authentication object defined for %s\n", keyidstr);
-      /* fixme: we might want to go ahead and do without PIN
-         verification. */
-      return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+      log_info ("p15: no authentication object defined for %s\n", keyidstr);
+      aodf = NULL;
+    }
+  else
+    {
+      for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next)
+        if (aodf->objidlen == prkdf->authidlen
+            && !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen))
+          break;
+      if (!aodf)
+        log_info ("p15: no authentication for %s needed\n", keyidstr);
     }
-  for (aodf = app->app_local->auth_object_info; aodf; aodf = aodf->next)
-    if (aodf->objidlen == prkdf->authidlen
-        && !memcmp (aodf->objid, prkdf->authid, prkdf->authidlen))
-      break;
-  if (!aodf)
-    log_info ("p15: no authentication for %s needed\n", keyidstr);
 
   /* We need some more info about the key - get the keygrip to
    * populate these fields.  */
@@ -6274,7 +6278,8 @@ do_with_keygrip (app_t app, ctrl_t ctrl, int action,
             }
           else if (capability == GCRY_PK_USAGE_ENCR)
             {
-              if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap))
+              if (!(prkdf->usageflags.decrypt || prkdf->usageflags.unwrap
+                    || prkdf->usageflags.derive))
                 continue;
             }
           else if (capability == GCRY_PK_USAGE_AUTH)
-- 
2.39.2

From 408f601bb3ae3efbefbc41ca8556656c542cb353 Mon Sep 17 00:00:00 2001
From: Werner Koch <[email protected]>
Date: Mon, 19 Feb 2024 14:45:06 +0100
Subject: [PATCH GnuPG 2/2] scd:p15: Handle duplicate certificate ids.

* scd/app-p15.c (struct app_local_s): Add field cdf_dup_counter.
(objid_in_cdflist_p): New.
(read_p15_info): Clear the counter.
(read_ef_cdf): Detect and fix duplicate IDs.
--

GnuPG-bug-id: 7001
Reported-by: Mario Haustein <[email protected]>
---
 scd/app-p15.c | 39 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 37 insertions(+), 2 deletions(-)

diff --git a/scd/app-p15.c b/scd/app-p15.c
index c9ab30fe9..9ed51ae04 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -520,6 +520,9 @@ struct app_local_s
   /* Information on all useful certificates. */
   cdf_object_t useful_certificate_info;
 
+  /* Counter to make object ids of certificates unique.  */
+  unsigned int cdf_dup_counter;
+
   /* Information on all public keys. */
   prkdf_object_t public_key_info;
 
@@ -2419,6 +2422,22 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result)
 }
 
 
+/* Return true id CDFLIST has the given object id.  */
+static int
+objid_in_cdflist_p (cdf_object_t cdflist,
+                    const unsigned char *objid, size_t objidlen)
+{
+  cdf_object_t cdf;
+
+  if (!objid || !objidlen)
+    return 0;
+  for (cdf = cdflist; cdf; cdf = cdf->next)
+    if (cdf->objidlen == objidlen && !memcmp (cdf->objid, objid, objidlen))
+      return 1;
+  return 0;
+}
+
+
 /* Read and parse the Certificate Directory Files identified by FID.
    On success a newlist of CDF object gets stored at RESULT and the
    caller is then responsible of releasing this list.  On error a
@@ -2464,6 +2483,7 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result)
       unsigned long ul;
       const unsigned char *objid;
       size_t objidlen;
+      int objidextralen;
 
       err = parse_ber_header (&p, &n, &class, &tag, &constructed,
                               &ndef, &objlen, &hdrlen);
@@ -2588,8 +2608,12 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result)
           label = NULL;
         }
 
-      cdf->objidlen = objidlen;
-      cdf->objid = xtrymalloc (objidlen);
+      /* Card's have been found in the wild which do not have unique
+       * IDs for their certificate objects.  If we detect this we
+       * append a counter to the ID.  */
+      objidextralen = !!objid_in_cdflist_p (cdflist, objid, objidlen);
+      cdf->objidlen = objidlen + objidextralen;
+      cdf->objid = xtrymalloc (objidlen + objidextralen);
       if (!cdf->objid)
         {
           err = gpg_error_from_syserror ();
@@ -2597,6 +2621,16 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result)
           goto leave;
         }
       memcpy (cdf->objid, objid, objidlen);
+      if (objidextralen)
+        {
+          if (app->app_local->cdf_dup_counter == 255)
+            {
+              log_error ("p15: too many duplicate certificate ids\n");
+              err = gpg_error (GPG_ERR_TOO_MANY);
+              goto parse_error;
+            }
+          cdf->objid[objidlen] = ++app->app_local->cdf_dup_counter;
+        }
 
       cdf->pathlen = objlen/2;
       for (i=0; i < cdf->pathlen; i++, pp += 2, nn -= 2)
@@ -3664,6 +3698,7 @@ read_p15_info (app_t app)
   log_assert (!app->app_local->certificate_info);
   log_assert (!app->app_local->trusted_certificate_info);
   log_assert (!app->app_local->useful_certificate_info);
+  app->app_local->cdf_dup_counter = 0;
   err = read_ef_cdf (app, app->app_local->odf.certificates, 'c',
                      &app->app_local->certificate_info);
   if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)
-- 
2.39.2

Attachment: openpgp-digital-signature.asc
Description: PGP signature

_______________________________________________
Gnupg-devel mailing list
[email protected]
https://lists.gnupg.org/mailman/listinfo/gnupg-devel

Reply via email to