diff options
Diffstat (limited to 'src')
-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) |