diff options
Diffstat (limited to '')
| -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 | 
5 files changed, 142 insertions, 95 deletions
| 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) | 
