diff options
Diffstat (limited to '')
| -rw-r--r-- | NEWS | 4 | ||||
| -rw-r--r-- | doc/gpgme.texi | 32 | ||||
| -rw-r--r-- | src/gpgme.h.in | 94 | ||||
| -rw-r--r-- | src/key.c | 17 | ||||
| -rw-r--r-- | src/keylist.c | 16 | ||||
| -rw-r--r-- | src/ops.h | 4 | ||||
| -rw-r--r-- | src/verify.c | 106 | ||||
| -rw-r--r-- | tests/run-keylist.c | 9 | ||||
| -rw-r--r-- | tests/run-verify.c | 50 | 
9 files changed, 211 insertions, 121 deletions
| @@ -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 b28c6cad..02551d98 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. +@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. +@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 +@code{NULL} is stored. + +@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. + +@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}. + +@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 49cea778..c07cac8d 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; @@ -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 5a346ea4..38ddd0c5 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).  */ @@ -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 1ec09fe8..173d1cb7 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 cc4c3545..bae2dbb9 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 b1745163..ef4dd32e 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); +            }          }      }  } | 
