[git] GPGME - branch, master, updated. gpgme-1.6.0-297-gbe4ff75

by Werner Koch cvs at cvs.gnupg.org
Tue Aug 23 15:26:49 CEST 2016


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GnuPG Made Easy".

The branch, master has been updated
       via  be4ff75d7d5ac6ed15feb245ef3cec59b4bad561 (commit)
       via  3955dce06e9d056599e5ec7d40301e66b9305195 (commit)
       via  26c5ba528ce1411d96655952ec48359105695c0f (commit)
      from  24e61984c9532924135c57b8ff98489a2d3bd4a3 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit be4ff75d7d5ac6ed15feb245ef3cec59b4bad561
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Aug 23 15:22:28 2016 +0200

    core: Change the way TOFU information are represented.
    
    * src/gpgme.h.in (struct _gpgme_signature): Remove field 'tofu'.  Add
    field 'key'.
    (struct _gpgme_key): Add field 'fpr'.
    (struct _gpgme_user_id): Add field 'tofu'.
    (struct _gpgme_tofu_info): Remove fields 'address' and 'fpr'.
    * src/key.c (gpgme_key_unref): Release TOFU and FPR.
    * src/keylist.c (keylist_colon_handler): Store the fingerprint of the
    first subkey also in KEY.
    * src/verify.c (release_tofu_info): Remove.
    (release_op_data): Release KEY.
    (parse_tofu_user): Rewrite for new data structure.
    (parse_tofu_stats): Ditto.
    (parse_tofu_stats_long): Ditto.
    * tests/run-verify.c (print_result): Ditto.
    * tests/run-keylist.c (main): Print more fields.
    --
    
    TOFU information are now associated with the user ID and not with a
    separate object.
    
    Note that this breaks code relying on the former non-released TOFU
    feature.  The C++ bindings won't work right now.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/NEWS b/NEWS
index ce16687..1294e0b 100644
--- a/NEWS
+++ b/NEWS
@@ -15,8 +15,10 @@ Noteworthy changes in version 1.7.0 (unreleased) [C25/A14/R_]
  GPGME_PK_EDDSA                 NEW.
  gpgme_set_ctx_flag             NEW.
  gpgme_data_set_flag            NEW.
- gpgme_signature_t              EXTENDED: New field tofu.
+ gpgme_signature_t              EXTENDED: New field key.
+ gpgme_key_t                    EXTENDED: New field fpr.
  gpgme_subkey_t                 EXTENDED: New field keygrip.
+ gpgme_user_id_t                EXTENDED: New field tofu.
  gpgme_tofu_policy_t            NEW.
  gpgme_tofu_info_t              NEW.
  GPGME_STATUS_KEY_CONSIDERED    NEW.
diff --git a/doc/gpgme.texi b/doc/gpgme.texi
index b28c6ca..02551d9 100644
--- a/doc/gpgme.texi
+++ b/doc/gpgme.texi
@@ -3017,6 +3017,10 @@ This is the key ID of the subkey in hexadecimal digits.
 This is the fingerprint of the subkey in hexadecimal digits, if
 available.
 
+ at item char *keygrip
+The keygrip of the subkey in hex digit form or @code{NULL} if not
+availabale.
+
 @item long int timestamp
 This is the creation timestamp of the subkey.  This is -1 if the
 timestamp is invalid, and 0 if it is not available.
@@ -3144,6 +3148,16 @@ This is the comment component of @code{uid}, if available.
 @item char *email
 This is the email component of @code{uid}, if available.
 
+ at item char *address;
+The mail address (addr-spec from RFC-5322) of the user ID string.
+This is general the same as the @code{email} part of this structure
+but might be slightly different.  If no mail address is available
+ at code{NULL} is stored.
+
+ at item gpgme_tofu_info_t tofu
+If not @code{NULL} information from the TOFU database pertaining to
+this user id.
+
 @item gpgme_key_sig_t signatures
 This is a linked list with the signatures on this user ID.
 @end table
@@ -3168,8 +3182,8 @@ This is true if the key is disabled.
 
 @item unsigned int invalid : 1
 This is true if the key is invalid. This might have several reasons,
-for a example for the S/MIME backend, it will be set in during key
-listsing if the key could not be validated due to a missing
+for a example for the S/MIME backend, it will be set during key
+listings if the key could not be validated due to missing
 certificates or unmatched policies.
 
 @item unsigned int can_encrypt : 1
@@ -3224,6 +3238,13 @@ in the list is the primary key and usually available.
 @item gpgme_user_id_t uids
 This is a linked list with the user IDs of the key.  The first user ID
 in the list is the main (or primary) user ID.
+
+ at item char *fpr
+This field gives the fingerprint of the primary key.  Note that
+this is a copy of the fingerprint of the first subkey.  For an
+incomplete key (for example from a verification result) a subkey may
+be missing but this field may be set nevertheless.
+
 @end table
 @end deftp
 
@@ -4870,6 +4891,13 @@ The hash algorithm used to create this signature.
 
 @item char *pka_address
 The mailbox from the PKA information or @code{NULL}.
+
+ at item gpgme_key_t key
+An object describing the key used to create the signature.  This key
+object may be incomplete in that it only conveys information
+availabale directly with a signature.  It may also be @code{NULL} if
+such information is not readily available.
+
 @end table
 @end deftp
 
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 49cea77..c07cac8 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -624,6 +624,41 @@ struct _gpgme_engine_info
 typedef struct _gpgme_engine_info *gpgme_engine_info_t;
 
 
+/* An object with TOFU information.  */
+struct _gpgme_tofu_info
+{
+  struct _gpgme_tofu_info *next;
+
+  /* The TOFU validity:
+   *  0 := conflict
+   *  1 := key without history
+   *  2 := key with too little history
+   *  3 := key with enough history for basic trust
+   *  4 := key with a lot of history
+   */
+  unsigned int validity : 3;
+
+  /* The TOFU policy (gpgme_tofu_policy_t).  */
+  unsigned int policy : 4;
+
+  unsigned int _rfu : 25;
+
+  /* Number of signatures seen for this binding.  Capped at USHRT_MAX.  */
+  unsigned short signcount;
+  /* Number of encryptions done with this binding.  Capped at USHRT_MAX.  */
+  unsigned short encrcount;
+
+  /* Number of seconds since the first and the most recently seen
+   * message was verified.  */
+  unsigned int firstseen;
+  unsigned int lastseen;
+
+  /* If non-NULL a human readable string summarizing the TOFU data. */
+  char *description;
+};
+typedef struct _gpgme_tofu_info *gpgme_tofu_info_t;
+
+
 /* A subkey from a key.  */
 struct _gpgme_subkey
 {
@@ -807,6 +842,9 @@ struct _gpgme_user_id
    * might be slightly different.  IF no mail address is available
    * NULL is stored.  */
   char *address;
+
+  /* The malloced tofo information or NULL.  */
+  gpgme_tofu_info_t tofu;
 };
 typedef struct _gpgme_user_id *gpgme_user_id_t;
 
@@ -883,6 +921,11 @@ struct _gpgme_key
 
   /* The keylist mode that was active when listing the key.  */
   gpgme_keylist_mode_t keylist_mode;
+
+  /* This field gives the fingerprint of the primary key.  Note that
+   * this is a copy of the FPR of the first subkey.  We need it here
+   * to allow for an incomplete key object.  */
+  char *fpr;
 };
 typedef struct _gpgme_key *gpgme_key_t;
 
@@ -1570,50 +1613,6 @@ typedef enum
 gpgme_sigsum_t;
 
 
-struct _gpgme_tofu_info
-{
-  struct _gpgme_tofu_info *next;
-
-  /* The mail address (addr-spec from RFC5322) of the tofu binding.
-   *
-   * If no mail address is set for a User ID this is the name used
-   * for the user ID. Can be ambiguous when the same mail address or
-   * name is used in multiple user ids.
-   */
-  char *address;
-
-  /* The fingerprint of the primary key.  */
-  char *fpr;
-
-  /* The TOFU validity:
-   *  0 := conflict
-   *  1 := key without history
-   *  2 := key with too little history
-   *  3 := key with enough history for basic trust
-   *  4 := key with a lot of history
-   */
-  unsigned int validity : 3;
-
-  /* The TOFU policy (gpgme_tofu_policy_t).  */
-  unsigned int policy : 4;
-
-  unsigned int _rfu : 25;
-
-  /* Number of signatures seen for this binding.  Capped at USHRT_MAX.  */
-  unsigned short signcount;
-  unsigned short reserved;
-
-  /* Number of seconds since the first and the most recently seen
-   * message was verified.  */
-  unsigned int firstseen;
-  unsigned int lastseen;
-
-  /* If non-NULL a human readable string summarizing the TOFU data. */
-  char *description;
-};
-typedef struct _gpgme_tofu_info *gpgme_tofu_info_t;
-
-
 struct _gpgme_signature
 {
   struct _gpgme_signature *next;
@@ -1621,7 +1620,7 @@ struct _gpgme_signature
   /* A summary of the signature status.  */
   gpgme_sigsum_t summary;
 
-  /* The fingerprint or key ID of the signature.  */
+  /* The fingerprint of the signature.  This can be a subkey.  */
   char *fpr;
 
   /* The status of the signature.  */
@@ -1660,8 +1659,9 @@ struct _gpgme_signature
   /* The mailbox from the PKA information or NULL. */
   char *pka_address;
 
-  /* If non-NULL, TOFU info for this signature are available.  */
-  gpgme_tofu_info_t tofu;
+  /* If non-NULL, a possible incomplete key object with the data
+   * available for the signature.  */
+  gpgme_key_t key;
 };
 typedef struct _gpgme_signature *gpgme_signature_t;
 
diff --git a/src/key.c b/src/key.c
index f642501..38acc71 100644
--- a/src/key.c
+++ b/src/key.c
@@ -356,6 +356,7 @@ gpgme_key_unref (gpgme_key_t key)
     {
       gpgme_user_id_t next_uid = uid->next;
       gpgme_key_sig_t keysig = uid->signatures;
+      gpgme_tofu_info_t tofu = uid->tofu;
 
       while (keysig)
 	{
@@ -373,8 +374,21 @@ gpgme_key_unref (gpgme_key_t key)
           free (keysig);
 	  keysig = next_keysig;
         }
+
+      while (tofu)
+        {
+          /* NB: The ->next is currently not used but we are prepared
+           * for it.  */
+          gpgme_tofu_info_t tofu_next = tofu->next;
+
+          free (tofu->description);
+          free (tofu);
+          tofu = tofu_next;
+        }
+
       if (uid->address && uid->address != uid->email)
         free (uid->address);
+
       free (uid);
       uid = next_uid;
     }
@@ -386,10 +400,13 @@ gpgme_key_unref (gpgme_key_t key)
 
   if (key->chain_id)
     free (key->chain_id);
+  if (key->fpr)
+    free (key->fpr);
 
   free (key);
 }
 
+
 

 /* Support functions.  */
 
diff --git a/src/keylist.c b/src/keylist.c
index 5a346ea..38ddd0c 100644
--- a/src/keylist.c
+++ b/src/keylist.c
@@ -708,6 +708,22 @@ keylist_colon_handler (void *priv, char *line)
               if (!subkey->fpr)
                 return gpg_error_from_syserror ();
             }
+          /* If this is the first subkey, store the fingerprint also
+             in the KEY object.  */
+          if (subkey == key->subkeys)
+            {
+              if (key->fpr && strcmp (key->fpr, subkey->fpr))
+                {
+                  /* FPR already set but mismatch: Should never happen.  */
+                  return trace_gpg_error (GPG_ERR_INTERNAL);
+                }
+              if (!key->fpr)
+                {
+                  key->fpr = strdup (subkey->fpr);
+                  if (!key->fpr)
+                    return gpg_error_from_syserror ();
+                }
+            }
 	}
 
       /* Field 13 has the gpgsm chain ID (take only the first one).  */
diff --git a/src/ops.h b/src/ops.h
index 9c27529..97b1019 100644
--- a/src/ops.h
+++ b/src/ops.h
@@ -138,9 +138,11 @@ gpgme_error_t _gpgme_progress_status_handler (void *priv,
 gpgme_error_t _gpgme_key_new (gpgme_key_t *r_key);
 gpgme_error_t _gpgme_key_add_subkey (gpgme_key_t key,
 				     gpgme_subkey_t *r_subkey);
-gpgme_error_t _gpgme_key_append_name (gpgme_key_t key, const char *src, int convert);
+gpgme_error_t _gpgme_key_append_name (gpgme_key_t key,
+                                      const char *src, int convert);
 gpgme_key_sig_t _gpgme_key_add_sig (gpgme_key_t key, char *src);
 
+
 

 /* From keylist.c.  */
 void _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type,
diff --git a/src/verify.c b/src/verify.c
index 1ec09fe..173d1cb 100644
--- a/src/verify.c
+++ b/src/verify.c
@@ -50,22 +50,6 @@ typedef struct
 
 
 static void
-release_tofu_info (gpgme_tofu_info_t t)
-{
-  while (t)
-    {
-      gpgme_tofu_info_t t2 = t->next;
-
-      free (t->address);
-      free (t->fpr);
-      free (t->description);
-      free (t);
-      t = t2;
-    }
-}
-
-
-static void
 release_op_data (void *hook)
 {
   op_data_t opd = (op_data_t) hook;
@@ -88,7 +72,8 @@ release_op_data (void *hook)
 	free (sig->fpr);
       if (sig->pka_address)
 	free (sig->pka_address);
-      release_tofu_info (sig->tofu);
+      if (sig->key)
+        gpgme_key_unref (sig->key);
       free (sig);
       sig = next;
     }
@@ -690,49 +675,80 @@ parse_tofu_user (gpgme_signature_t sig, char *args)
 {
   gpg_error_t err;
   char *tail;
-  gpgme_tofu_info_t ti, ti2;
+  gpgme_user_id_t uid;
+  gpgme_tofu_info_t ti;
+  char *fpr = NULL;
+  char *address = NULL;
 
   tail = strchr (args, ' ');
   if (!tail || tail == args)
-    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No fingerprint.  */
+    {
+      err = trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No fingerprint.  */
+      goto leave;
+    }
   *tail++ = 0;
 
-  ti = calloc (1, sizeof *ti);
-  if (!ti)
-    return gpg_error_from_syserror ();
-
-  ti->fpr = strdup (args);
-  if (!ti->fpr)
+  fpr = strdup (args);
+  if (!fpr)
     {
-      free (ti);
-      return gpg_error_from_syserror ();
+      err = gpg_error_from_syserror ();
+      goto leave;
     }
 
   args = tail;
   tail = strchr (args, ' ');
   if (tail == args)
-    return trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No addr-spec.  */
+    {
+      err = trace_gpg_error (GPG_ERR_INV_ENGINE);  /* No addr-spec.  */
+      goto leave;
+    }
   if (tail)
     *tail = 0;
 
-  err = _gpgme_decode_percent_string (args, &ti->address, 0, 0);
+  err = _gpgme_decode_percent_string (args, &address, 0, 0);
   if (err)
+    goto leave;
+
+  if (!sig->key)
     {
-      free (ti);
-      return err;
+      err = _gpgme_key_new (&sig->key);
+      if (err)
+        goto leave;
+      sig->key->fpr = fpr;
+      fpr = NULL;
+    }
+  else if (!sig->key->fpr)
+    {
+      err = trace_gpg_error (GPG_ERR_INTERNAL);
+      goto leave;
+    }
+  else if (strcmp (sig->key->fpr, fpr))
+    {
+      /* The engine did not emit NEWSIG before a new key.  */
+      err = trace_gpg_error (GPG_ERR_INV_ENGINE);
+      goto leave;
     }
 
-  /* Append to the tofu info list.  */
-  if (!sig->tofu)
-    sig->tofu = ti;
-  else
+  err = _gpgme_key_append_name (sig->key, address, 0);
+  if (err)
+    goto leave;
+
+  uid = sig->key->_last_uid;
+  assert (uid);
+
+  ti = calloc (1, sizeof *ti);
+  if (!ti)
     {
-      for (ti2 = sig->tofu; ti2->next; ti2 = ti2->next)
-        ;
-      ti2->next = ti;
+      err = gpg_error_from_syserror ();
+      goto leave;
     }
+  uid->tofu = ti;
 
-  return 0;
+
+ leave:
+  free (fpr);
+  free (address);
+  return err;
 }
 
 
@@ -749,12 +765,10 @@ parse_tofu_stats (gpgme_signature_t sig, char *args)
   int nfields;
   unsigned long uval;
 
-  if (!sig->tofu)
+  if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
-  for (ti = sig->tofu; ti->next; ti = ti->next)
-    ;
   if (ti->firstseen || ti->signcount || ti->validity || ti->policy)
-    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen.  */
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set.  */
 
   nfields = _gpgme_split_fields (args, field, DIM (field));
   if (nfields < 3)
@@ -825,12 +839,10 @@ parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw)
   gpgme_tofu_info_t ti;
   char *p;
 
-  if (!sig->tofu)
+  if (!sig->key || !sig->key->_last_uid || !(ti = sig->key->_last_uid->tofu))
     return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen.  */
-  for (ti = sig->tofu; ti->next; ti = ti->next)
-    ;
   if (ti->description)
-    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen.  */
+    return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already set.  */
 
   err = _gpgme_decode_percent_string (args, &ti->description, 0, 0);
   if (err)
diff --git a/tests/run-keylist.c b/tests/run-keylist.c
index cc4c354..bae2dbb 100644
--- a/tests/run-keylist.c
+++ b/tests/run-keylist.c
@@ -233,7 +233,14 @@ main (int argc, char **argv)
       for (nuids=0, uid=key->uids; uid; uid = uid->next, nuids++)
         {
           printf ("userid %d: %s\n", nuids, nonnull(uid->uid));
-          printf ("valid  %d: %s\n", nuids,
+          printf ("  mbox %d: %s\n", nuids, nonnull(uid->address));
+          if (uid->email && uid->email != uid->address)
+            printf (" email %d: %s\n", nuids, uid->email);
+          if (uid->name)
+            printf ("  name %d: %s\n", nuids, uid->name);
+          if (uid->comment)
+            printf (" cmmnt %d: %s\n", nuids, uid->comment);
+          printf (" valid %d: %s\n", nuids,
                   uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
                   uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
                   uid->validity == GPGME_VALIDITY_NEVER? "never":
diff --git a/tests/run-verify.c b/tests/run-verify.c
index b174516..ef4dd32 100644
--- a/tests/run-verify.c
+++ b/tests/run-verify.c
@@ -111,6 +111,7 @@ print_result (gpgme_verify_result_t result)
 {
   gpgme_signature_t sig;
   gpgme_sig_notation_t nt;
+  gpgme_user_id_t uid;
   gpgme_tofu_info_t ti;
   int count = 0;
 
@@ -153,29 +154,34 @@ print_result (gpgme_verify_result_t result)
           if ((nt->value?strlen (nt->value):0) != nt->value_len)
             printf ("    warning : value larger (%d)\n", nt->value_len);
         }
-      for (ti = sig->tofu; ti; ti = ti->next)
+      if (sig->key)
         {
-          printf ("  tofu addr .: %s\n", ti->address);
-          if (!sig->fpr || strcmp (sig->fpr, ti->fpr))
-            printf ("    WARNING .: fpr mismatch (%s)\n", ti->fpr);
-          printf ("    validity : %u (%s)\n", ti->validity,
-                  ti->validity == 0? "conflict" :
-                  ti->validity == 1? "no history" :
-                  ti->validity == 2? "little history" :
-                  ti->validity == 3? "enough history" :
-                  ti->validity == 4? "lot of history" : "?");
-          printf ("    policy ..: %u (%s)\n", ti->policy,
-                  ti->policy == GPGME_TOFU_POLICY_NONE? "none" :
-                  ti->policy == GPGME_TOFU_POLICY_AUTO? "auto" :
-                  ti->policy == GPGME_TOFU_POLICY_GOOD? "good" :
-                  ti->policy == GPGME_TOFU_POLICY_UNKNOWN? "unknown" :
-                  ti->policy == GPGME_TOFU_POLICY_BAD? "bad" :
-                  ti->policy == GPGME_TOFU_POLICY_ASK? "ask" : "?");
-          printf ("    sigcount : %hu\n", ti->signcount);
-          printf ("    firstseen: %u\n", ti->firstseen);
-          printf ("    lastseen : %u\n", ti->lastseen);
-          printf ("    desc ....: ");
-          print_description (nonnull (ti->description), 15);
+          printf ("  primary fpr: %s\n", nonnull (sig->key->fpr));
+          for (uid = sig->key->uids; uid; uid = uid->next)
+            {
+              printf ("  tofu addr .: %s\n", nonnull (uid->address));
+              ti = uid->tofu;
+              if (!ti)
+                continue;
+              printf ("    validity : %u (%s)\n", ti->validity,
+                      ti->validity == 0? "conflict" :
+                      ti->validity == 1? "no history" :
+                      ti->validity == 2? "little history" :
+                      ti->validity == 3? "enough history" :
+                      ti->validity == 4? "lot of history" : "?");
+              printf ("    policy ..: %u (%s)\n", ti->policy,
+                      ti->policy == GPGME_TOFU_POLICY_NONE? "none" :
+                      ti->policy == GPGME_TOFU_POLICY_AUTO? "auto" :
+                      ti->policy == GPGME_TOFU_POLICY_GOOD? "good" :
+                      ti->policy == GPGME_TOFU_POLICY_UNKNOWN? "unknown" :
+                      ti->policy == GPGME_TOFU_POLICY_BAD? "bad" :
+                      ti->policy == GPGME_TOFU_POLICY_ASK? "ask" : "?");
+              printf ("    sigcount : %hu\n", ti->signcount);
+              printf ("    firstseen: %u\n", ti->firstseen);
+              printf ("    lastseen : %u\n", ti->lastseen);
+              printf ("    desc ....: ");
+              print_description (nonnull (ti->description), 15);
+            }
         }
     }
 }

commit 3955dce06e9d056599e5ec7d40301e66b9305195
Author: Werner Koch <wk at gnupg.org>
Date:   Tue Aug 23 06:48:50 2016 +0200

    core: Extend gpgme_user_id_t with 'address'.
    
    * src/mbox-util.c, src/mbox-util.h: Adjust for use in gpgme.
    * src/Makefile.am (main_sources): Add mbox-util.
    * src/key.c (_gpgme_key_append_name): Set 'address' field of uid.
    (gpgme_key_unref): Free it.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/Makefile.am b/src/Makefile.am
index 6691540..d541f87 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -76,6 +76,7 @@ endif
 main_sources =								\
 	util.h conversion.c b64dec.c get-env.c context.h ops.h		\
 	parsetlv.c parsetlv.h                                           \
+	mbox-util.c mbox-util.h                                         \
 	data.h data.c data-fd.c data-stream.c data-mem.c data-user.c	\
 	data-compat.c data-identify.c					\
 	signers.c sig-notation.c					\
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 40f5442..49cea77 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -801,6 +801,12 @@ struct _gpgme_user_id
 
   /* Internal to GPGME, do not use.  */
   gpgme_key_sig_t _last_keysig;
+
+  /* The mail address (addr-spec from RFC5322) of the UID string.
+   * This is general the same as the EMAIL part of this struct but
+   * might be slightly different.  IF no mail address is available
+   * NULL is stored.  */
+  char *address;
 };
 typedef struct _gpgme_user_id *gpgme_user_id_t;
 
diff --git a/src/key.c b/src/key.c
index de97102..f642501 100644
--- a/src/key.c
+++ b/src/key.c
@@ -31,6 +31,8 @@
 #include "ops.h"
 #include "sema.h"
 #include "debug.h"
+#include "mbox-util.h"
+
 
 

 /* Protects all reference counters in keys.  All other accesses to a
@@ -233,6 +235,14 @@ _gpgme_key_append_name (gpgme_key_t key, const char *src, int convert)
     parse_user_id (uid->uid, &uid->name, &uid->email,
 		   &uid->comment, dst);
 
+  uid->address = _gpgme_mailbox_from_userid (uid->uid);
+  if (uid->address && uid->email && !strcmp (uid->address, uid->email))
+    {
+      /* The ADDRESS is the same as EMAIL: Save some space.  */
+      free (uid->address);
+      uid->address = uid->email;
+    }
+
   if (!key->uids)
     key->uids = uid;
   if (key->_last_uid)
@@ -363,6 +373,8 @@ gpgme_key_unref (gpgme_key_t key)
           free (keysig);
 	  keysig = next_keysig;
         }
+      if (uid->address && uid->address != uid->email)
+        free (uid->address);
       free (uid);
       uid = next_uid;
     }
diff --git a/src/mbox-util.c b/src/mbox-util.c
index c451198..83c8b5e 100644
--- a/src/mbox-util.c
+++ b/src/mbox-util.c
@@ -18,16 +18,34 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <config.h>
+/* NB: This code has been taken from GnuPG.  Please keep it in sync
+ * with GnuPG.  */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 
-#include "util.h"
 #include "mbox-util.h"
 
+/* Lowercase all ASCII characters in STRING.  */
+static char *
+ascii_strlwr (char *string)
+{
+  char *p;
+
+  for (p = string; *p; p++ )
+    if (!(*p & ~0x7f) && *p >= 'A' && *p <= 'Z')
+      *p |= 0x20;
+
+  return string;
+}
+
 
 static int
 string_count_chr (const char *string, int c)
@@ -117,7 +135,7 @@ has_dotdot_after_at (const char *string)
    Note that we can't do an utf-8 encoding checking here because in
    keygen.c this function is called with the native encoding and
    native to utf-8 encoding is only done later.  */
-int
+static int
 has_invalid_email_chars (const void *buffer, size_t length)
 {
   const unsigned char *s = buffer;
@@ -143,7 +161,7 @@ has_invalid_email_chars (const void *buffer, size_t length)
 
 /* Same as is_valid_mailbox (see below) but operates on non-nul
    terminated buffer.  */
-int
+static int
 is_valid_mailbox_mem (const void *name_arg, size_t namelen)
 {
   const char *name = name_arg;
@@ -162,7 +180,7 @@ is_valid_mailbox_mem (const void *name_arg, size_t namelen)
 /* Check whether NAME represents a valid mailbox according to
    RFC822. Returns true if so. */
 int
-is_valid_mailbox (const char *name)
+_gpgme_is_valid_mailbox (const char *name)
 {
   return name? is_valid_mailbox_mem (name, strlen (name)) : 0;
 }
@@ -173,7 +191,7 @@ is_valid_mailbox (const char *name)
    lowercase.  Caller must free the result.  Returns NULL if no valid
    mailbox was found (or we are out of memory). */
 char *
-mailbox_from_userid (const char *userid)
+_gpgme_mailbox_from_userid (const char *userid)
 {
   const char *s, *s_end;
   size_t len;
@@ -188,7 +206,7 @@ mailbox_from_userid (const char *userid)
       if (s_end && s_end > s)
         {
           len = s_end - s;
-          result = xtrymalloc (len + 1);
+          result = malloc (len + 1);
           if (!result)
             return NULL; /* Ooops - out of core.  */
           strncpy (result, s, len);
@@ -202,7 +220,7 @@ mailbox_from_userid (const char *userid)
               || string_has_ctrl_or_space (result)
               || has_dotdot_after_at (result))
             {
-              xfree (result);
+              free (result);
               result = NULL;
               errno = EINVAL;
             }
@@ -210,14 +228,14 @@ mailbox_from_userid (const char *userid)
       else
         errno = EINVAL;
     }
-  else if (is_valid_mailbox (userid))
+  else if (_gpgme_is_valid_mailbox (userid))
     {
       /* The entire user id is a mailbox.  Return that one.  Note that
          this fallback method has some restrictions on the valid
          syntax of the mailbox.  However, those who want weird
          addresses should know about it and use the regular <...>
          syntax.  */
-      result = xtrystrdup (userid);
+      result = strdup (userid);
     }
   else
     errno = EINVAL;
@@ -226,14 +244,14 @@ mailbox_from_userid (const char *userid)
 }
 
 
-/* Check whether UID is a valid standard user id of the form
-     "Heinrich Heine <heinrichh at duesseldorf.de>"
-   and return true if this is the case. */
-int
-is_valid_user_id (const char *uid)
-{
-  if (!uid || !*uid)
-    return 0;
+/* /\* Check whether UID is a valid standard user id of the form */
+/*      "Heinrich Heine <heinrichh at duesseldorf.de>" */
+/*    and return true if this is the case. *\/ */
+/* int */
+/* is_valid_user_id (const char *uid) */
+/* { */
+/*   if (!uid || !*uid) */
+/*     return 0; */
 
-  return 1;
-}
+/*   return 1; */
+/* } */
diff --git a/src/mbox-util.h b/src/mbox-util.h
index 9c7271f..3195a4d 100644
--- a/src/mbox-util.h
+++ b/src/mbox-util.h
@@ -19,11 +19,11 @@
 #ifndef GNUPG_COMMON_MBOX_UTIL_H
 #define GNUPG_COMMON_MBOX_UTIL_H
 
-int has_invalid_email_chars (const void *buffer, size_t length);
-int is_valid_mailbox (const char *name);
-int is_valid_mailbox_mem (const void *buffer, size_t length);
-char *mailbox_from_userid (const char *userid);
-int is_valid_user_id (const char *uid);
+/* int has_invalid_email_chars (const void *buffer, size_t length); */
+int _gpgme_is_valid_mailbox (const char *name);
+/* int _gpgme_is_valid_mailbox_mem (const void *buffer, size_t length); */
+char *_gpgme_mailbox_from_userid (const char *userid);
+/* int is_valid_user_id (const char *uid); */
 
 
 #endif /*GNUPG_COMMON_MBOX_UTIL_H*/

commit 26c5ba528ce1411d96655952ec48359105695c0f
Author: Werner Koch <wk at gnupg.org>
Date:   Mon Aug 22 20:50:37 2016 +0200

    core: New code for parsing mail addresses.
    
    * src/mbox-util.c: New.
    * src/mbox-util.h: New.
    --
    
    The files haven been copied verbatim from
    GnuPG 2.1.15 commit 54245979e691129ed9d3a6c642087fb8d3227449
    after the license has been changed in GnuPG.
    
    We need this file too match GnuPG's idea of a mail address.
    
    Signed-off-by: Werner Koch <wk at gnupg.org>

diff --git a/src/mbox-util.c b/src/mbox-util.c
new file mode 100644
index 0000000..c451198
--- /dev/null
+++ b/src/mbox-util.c
@@ -0,0 +1,239 @@
+/* mbox-util.c - Mail address helper functions
+ * Copyright (C) 1998-2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "mbox-util.h"
+
+
+static int
+string_count_chr (const char *string, int c)
+{
+  int count;
+
+  for (count=0; *string; string++ )
+    if ( *string == c )
+      count++;
+  return count;
+}
+
+static int
+mem_count_chr (const void *buffer, int c, size_t length)
+{
+  const char *s = buffer;
+  int count;
+
+  for (count=0; length; length--, s++)
+    if (*s == c)
+      count++;
+  return count;
+}
+
+
+/* This is a case-sensitive version of our memistr.  I wonder why no
+   standard function memstr exists but I better do not use the name
+   memstr to avoid future conflicts.  */
+static const char *
+my_memstr (const void *buffer, size_t buflen, const char *sub)
+{
+  const unsigned char *buf = buffer;
+  const unsigned char *t = (const unsigned char *)buf;
+  const unsigned char *s = (const unsigned char *)sub;
+  size_t n = buflen;
+
+  for ( ; n ; t++, n-- )
+    {
+      if (*t == *s)
+        {
+          for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
+            ;
+          if (!*s)
+            return (const char*)buf;
+          t = (const unsigned char *)buf;
+          s = (const unsigned char *)sub ;
+          n = buflen;
+	}
+    }
+  return NULL;
+}
+
+
+
+static int
+string_has_ctrl_or_space (const char *string)
+{
+  for (; *string; string++ )
+    if (!(*string & 0x80) && *string <= 0x20)
+      return 1;
+  return 0;
+}
+
+
+/* Return true if STRING has two consecutive '.' after an '@'
+   sign.  */
+static int
+has_dotdot_after_at (const char *string)
+{
+  string = strchr (string, '@');
+  if (!string)
+    return 0; /* No at-sign.  */
+  string++;
+  return !!strstr (string, "..");
+}
+
+
+/* Check whether BUFFER has characters not valid in an RFC-822
+   address.  LENGTH gives the length of BUFFER.
+
+   To cope with OpenPGP we ignore non-ascii characters so that for
+   example umlauts are legal in an email address.  An OpenPGP user ID
+   must be utf-8 encoded but there is no strict requirement for
+   RFC-822.  Thus to avoid IDNA encoding we put the address verbatim
+   as utf-8 into the user ID under the assumption that mail programs
+   handle IDNA at a lower level and take OpenPGP user IDs as utf-8.
+   Note that we can't do an utf-8 encoding checking here because in
+   keygen.c this function is called with the native encoding and
+   native to utf-8 encoding is only done later.  */
+int
+has_invalid_email_chars (const void *buffer, size_t length)
+{
+  const unsigned char *s = buffer;
+  int at_seen=0;
+  const char *valid_chars=
+    "01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+  for ( ; length && *s; length--, s++ )
+    {
+      if ((*s & 0x80))
+        continue; /* We only care about ASCII.  */
+      if (*s == '@')
+        at_seen=1;
+      else if (!at_seen && !(strchr (valid_chars, *s)
+                             || strchr ("!#$%&'*+/=?^`{|}~", *s)))
+        return 1;
+      else if (at_seen && !strchr (valid_chars, *s))
+        return 1;
+    }
+  return 0;
+}
+
+
+/* Same as is_valid_mailbox (see below) but operates on non-nul
+   terminated buffer.  */
+int
+is_valid_mailbox_mem (const void *name_arg, size_t namelen)
+{
+  const char *name = name_arg;
+
+  return !( !name
+            || !namelen
+            || has_invalid_email_chars (name, namelen)
+            || mem_count_chr (name, '@', namelen) != 1
+            || *name == '@'
+            || name[namelen-1] == '@'
+            || name[namelen-1] == '.'
+            || my_memstr (name, namelen, ".."));
+}
+
+
+/* Check whether NAME represents a valid mailbox according to
+   RFC822. Returns true if so. */
+int
+is_valid_mailbox (const char *name)
+{
+  return name? is_valid_mailbox_mem (name, strlen (name)) : 0;
+}
+
+
+/* Return the mailbox (local-part at domain) form a standard user id.
+   All plain ASCII characters in the result are converted to
+   lowercase.  Caller must free the result.  Returns NULL if no valid
+   mailbox was found (or we are out of memory). */
+char *
+mailbox_from_userid (const char *userid)
+{
+  const char *s, *s_end;
+  size_t len;
+  char *result = NULL;
+
+  s = strchr (userid, '<');
+  if (s)
+    {
+      /* Seems to be a standard user id.  */
+      s++;
+      s_end = strchr (s, '>');
+      if (s_end && s_end > s)
+        {
+          len = s_end - s;
+          result = xtrymalloc (len + 1);
+          if (!result)
+            return NULL; /* Ooops - out of core.  */
+          strncpy (result, s, len);
+          result[len] = 0;
+          /* Apply some basic checks on the address.  We do not use
+             is_valid_mailbox because those checks are too strict.  */
+          if (string_count_chr (result, '@') != 1  /* Need exactly one '@.  */
+              || *result == '@'           /* local-part missing.  */
+              || result[len-1] == '@'     /* domain missing.  */
+              || result[len-1] == '.'     /* ends with a dot.  */
+              || string_has_ctrl_or_space (result)
+              || has_dotdot_after_at (result))
+            {
+              xfree (result);
+              result = NULL;
+              errno = EINVAL;
+            }
+        }
+      else
+        errno = EINVAL;
+    }
+  else if (is_valid_mailbox (userid))
+    {
+      /* The entire user id is a mailbox.  Return that one.  Note that
+         this fallback method has some restrictions on the valid
+         syntax of the mailbox.  However, those who want weird
+         addresses should know about it and use the regular <...>
+         syntax.  */
+      result = xtrystrdup (userid);
+    }
+  else
+    errno = EINVAL;
+
+  return result? ascii_strlwr (result): NULL;
+}
+
+
+/* Check whether UID is a valid standard user id of the form
+     "Heinrich Heine <heinrichh at duesseldorf.de>"
+   and return true if this is the case. */
+int
+is_valid_user_id (const char *uid)
+{
+  if (!uid || !*uid)
+    return 0;
+
+  return 1;
+}
diff --git a/src/mbox-util.h b/src/mbox-util.h
new file mode 100644
index 0000000..9c7271f
--- /dev/null
+++ b/src/mbox-util.h
@@ -0,0 +1,29 @@
+/* mbox-util.h - Defs for mail address helper functions
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef GNUPG_COMMON_MBOX_UTIL_H
+#define GNUPG_COMMON_MBOX_UTIL_H
+
+int has_invalid_email_chars (const void *buffer, size_t length);
+int is_valid_mailbox (const char *name);
+int is_valid_mailbox_mem (const void *buffer, size_t length);
+char *mailbox_from_userid (const char *userid);
+int is_valid_user_id (const char *uid);
+
+
+#endif /*GNUPG_COMMON_MBOX_UTIL_H*/

-----------------------------------------------------------------------

Summary of changes:
 NEWS                |   4 +-
 doc/gpgme.texi      |  32 ++++++-
 src/Makefile.am     |   1 +
 src/gpgme.h.in      | 100 ++++++++++----------
 src/key.c           |  29 ++++++
 src/keylist.c       |  16 ++++
 src/mbox-util.c     | 257 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/mbox-util.h     |  29 ++++++
 src/ops.h           |   4 +-
 src/verify.c        | 106 ++++++++++++----------
 tests/run-keylist.c |   9 +-
 tests/run-verify.c  |  50 +++++-----
 12 files changed, 516 insertions(+), 121 deletions(-)
 create mode 100644 src/mbox-util.c
 create mode 100644 src/mbox-util.h


hooks/post-receive
-- 
GnuPG Made Easy
http://git.gnupg.org




More information about the Gnupg-commits mailing list