aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2016-08-23 13:22:28 +0000
committerWerner Koch <[email protected]>2016-08-23 13:24:10 +0000
commitbe4ff75d7d5ac6ed15feb245ef3cec59b4bad561 (patch)
tree67dffdf32235e3e459aa52cd1b248420a6dc480f
parentcore: Extend gpgme_user_id_t with 'address'. (diff)
downloadgpgme-be4ff75d7d5ac6ed15feb245ef3cec59b4bad561.tar.gz
gpgme-be4ff75d7d5ac6ed15feb245ef3cec59b4bad561.zip
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 <[email protected]>
-rw-r--r--NEWS4
-rw-r--r--doc/gpgme.texi32
-rw-r--r--src/gpgme.h.in94
-rw-r--r--src/key.c17
-rw-r--r--src/keylist.c16
-rw-r--r--src/ops.h4
-rw-r--r--src/verify.c106
-rw-r--r--tests/run-keylist.c9
-rw-r--r--tests/run-verify.c50
9 files changed, 211 insertions, 121 deletions
diff --git a/NEWS b/NEWS
index ce166874..1294e0b7 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 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;
diff --git a/src/key.c b/src/key.c
index f642501b..38acc712 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 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). */
diff --git a/src/ops.h b/src/ops.h
index 9c275292..97b1019f 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 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);
+ }
}
}
}