aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2025-05-05 13:02:52 +0000
committerWerner Koch <[email protected]>2025-05-05 13:03:01 +0000
commit87d6da1188db3c7df899821e4c0d895c61504522 (patch)
tree4304e4775c4d828c6371cecc471463c81e396a89
parentNew decrypt flags GPGME_DECRYPT_LISTONLY. (diff)
downloadgpgme-87d6da1188db3c7df899821e4c0d895c61504522.tar.gz
gpgme-87d6da1188db3c7df899821e4c0d895c61504522.zip
Mark the subkey used to find a key.
* src/gpgme.h.in (struct _gpgme_subkey): New flag subkey_match. * src/keylist.c (spacep): New. (op_data_t): Add field requested_subkey. (release_op_data): Free it. (exact_match_pattern): New. (maybe_setup_for_requested_subkey): New. (gpgme_op_keylist_start): Call it here. (gpgme_op_keylist_ext_start): Call it for each pattern until one found. (gpgme_op_keylist_next): Set the subkey_match field. --- This is needed for GnuPG-bug-id: 3325
-rw-r--r--NEWS1
-rw-r--r--src/gpgme.h.in5
-rw-r--r--src/keylist.c99
-rw-r--r--tests/run-keylist.c3
4 files changed, 106 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 6de14424..df59388c 100644
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,7 @@ Noteworthy changes in version 2.0.0 (unreleased)
GPGME_RANDOM_MODE_NORMAL NEW.
GPGME_RANDOM_MODE_ZBASE32 NEW.
GPGME_DECRYPT_LISTONLY NEW.
+ gpgme_subkey_t EXT: New field 'subkey_match'.
gpgme_attr_t REMOVED.
gpgme_get_sig_ulong_attr REMOVED.
gpgme_get_sig_string_attr REMOVED.
diff --git a/src/gpgme.h.in b/src/gpgme.h.in
index 69d9f54c..e56c293d 100644
--- a/src/gpgme.h.in
+++ b/src/gpgme.h.in
@@ -590,8 +590,11 @@ struct _gpgme_subkey
/* The compliance mode (is_de_vs) has not yet been approved. */
unsigned int beta_compliance : 1;
+ /* The key was found by an exact fingerprint match on this subkey. */
+ unsigned int subkey_match : 1;
+
/* Internal to GPGME, do not use. */
- unsigned int _unused : 16;
+ unsigned int _unused : 15;
/* Public key algorithm supported by this subkey. */
gpgme_pubkey_algo_t pubkey_algo;
diff --git a/src/keylist.c b/src/keylist.c
index f8dd2962..11b68408 100644
--- a/src/keylist.c
+++ b/src/keylist.c
@@ -44,6 +44,10 @@
#include "ops.h"
#include "debug.h"
+
+#define spacep(p) (*(p) == ' ' || *(p) == '\t')
+
+
struct key_queue_item_s
{
@@ -69,6 +73,10 @@ typedef struct
/* This points to the last sig in tmp_uid. */
gpgme_key_sig_t tmp_keysig;
+ /* Helper with a malloced uppercased fingerprint without '!' to be
+ * used to set the subkey_match flag. */
+ char *requested_subkey;
+
/* Something new is available. */
int key_cond;
struct key_queue_item_s *key_queue;
@@ -87,6 +95,9 @@ release_op_data (void *hook)
/* opd->tmp_uid and opd->tmp_keysig are actually part of opd->tmp_key,
so we do not need to release them here. */
+ if (opd->requested_subkey)
+ free (opd->requested_subkey);
+
while (key)
{
struct key_queue_item_s *next = key->next;
@@ -1207,6 +1218,64 @@ _gpgme_op_keylist_event_cb (void *data, gpgme_event_io_t type, void *type_data)
}
+/* Return true if PATTERN requests an extackt match. That is a
+ * sequence of at least 40 hexdigits followed by an exclamation mark
+ * and nothing else. Returns a pointer to the first hexdigit or
+ * NULL. */
+static const char *
+exact_match_pattern (const char *pattern)
+{
+ const char *s;
+ int hexlen;
+ const char *start;
+
+ for(s = pattern; *s && spacep (s); s++ ) /* Skip spaces. */
+ ;
+ if (s[0] == '0' && s[1] == 'x') /* Skip an optional "0x" prefix. */
+ s += 2;
+ start = s;
+ hexlen = strspn (s, "0123456789abcdefABCDEF");
+ if (hexlen >= 40 && s[hexlen] == '!')
+ {
+ s += hexlen+1;
+ /* Skip trailing spaces and LFs. */
+ for (; *s && (spacep (s) || *s == '\n' || *s == '\r'); s++ )
+ ;
+ if (!*s) /* Only spaces seen. */
+ return start;
+ }
+ return NULL;
+}
+
+
+/* Helper for gpgme_op_keylist_start and ..._start_ext. */
+static gpg_error_t
+maybe_setup_for_requested_subkey (op_data_t opd, const char *pattern)
+{
+ const char *s;
+ char *p;
+
+ if (pattern && (s=exact_match_pattern (pattern)))
+ {
+ free (opd->requested_subkey);
+ p = opd->requested_subkey = strdup (s);
+ if (!p)
+ return gpg_error_from_syserror ();
+ for (; *p; p++ )
+ {
+ if (*p >= 'a' && *p <= 'z')
+ *p &= ~0x20; /* Upcase it. */
+ else if (*p == '!') /* Remove the '!' suffix and stop. */
+ {
+ *p = 0;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+
/* Start a keylist operation within CTX, searching for keys which
match PATTERN. If SECRET_ONLY is true, only secret keys are
returned. */
@@ -1233,6 +1302,10 @@ gpgme_op_keylist_start (gpgme_ctx_t ctx, const char *pattern, int secret_only)
if (err)
return TRACE_ERR (err);
+ err = maybe_setup_for_requested_subkey (opd, pattern);
+ if (err)
+ return TRACE_ERR (err);
+
err = _gpgme_op_import_init_result (ctx);
if (err)
return TRACE_ERR (err);
@@ -1277,6 +1350,22 @@ gpgme_op_keylist_ext_start (gpgme_ctx_t ctx, const char *pattern[],
if (err)
return TRACE_ERR (err);
+ if (pattern && pattern[0])
+ {
+ int i;
+
+ for (i=0; pattern[i]; i++)
+ {
+ err = maybe_setup_for_requested_subkey (opd, pattern[i]);
+ if (err)
+ return TRACE_ERR (err);
+ /* We can only handle one exact subnkey request. Thus we
+ * stop after the first seen. */
+ if (opd->requested_subkey)
+ break;
+ }
+ }
+
err = _gpgme_op_import_init_result (ctx);
if (err)
return TRACE_ERR (err);
@@ -1378,6 +1467,16 @@ gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
*r_key = queue_item->key;
free (queue_item);
+ if (opd->requested_subkey && (*r_key)->subkeys && (*r_key)->subkeys->fpr)
+ {
+ /* Time to set the mark. */
+ gpgme_subkey_t subkey = (*r_key)->subkeys;
+
+ for (; subkey; subkey = subkey->next)
+ if (subkey->fpr && !strcmp (subkey->fpr, opd->requested_subkey))
+ subkey->subkey_match = 1;
+ }
+
TRACE_SUC ("key=%p (%s)", *r_key,
((*r_key)->subkeys && (*r_key)->subkeys->fpr) ?
(*r_key)->subkeys->fpr : "invalid");
diff --git a/tests/run-keylist.c b/tests/run-keylist.c
index 7bbb9769..44a16596 100644
--- a/tests/run-keylist.c
+++ b/tests/run-keylist.c
@@ -349,7 +349,8 @@ main (int argc, char **argv)
{
char *algostr;
- printf ("fpr %2d: %s\n", nsub, nonnull (subkey->fpr));
+ printf ("fpr %2d: %s%s\n", nsub, nonnull (subkey->fpr),
+ subkey->subkey_match? " (match)":"");
if (subkey->v5fpr)
printf ("v5fpr %2d: %s\n", nsub, nonnull (subkey->v5fpr));
if (subkey->keygrip)