New mode to list a v5 fingerprint for v4 packets.

* src/gpgme.h.in (GPGME_KEYLIST_MODE_WITH_V5FPR): New.
(struct _gpgme_subkey): Add field v5fpr.
* src/engine-gpg.c (gpg_keylist_build_options): Pass new option to
gpg.
* src/key.c (gpgme_key_unref): Free new field.
* src/keylist.c (op_data_t): Parse and add "fp2" line.

* tests/run-keylist.c (show_usage): Add option --v5fpr.

* src/keylist.c (op_data_t): Add field failure_code.
(keylist_status_handler): Handle special value.
(gpgme_op_keylist_end): Return an error if a FAILURE line has been
seen.
--

Note that the failure code part has been added to better diagnose
problems if a wrong gpg version is used.  If verything works right we
should not get this because we check that the gnupg version sis either
>= 2.4.4 or less than 2.3 and >= 2.2.42.

Note further that the v5fpr field may also be used to get the SHA-256
fingerprint of X.509 certificates (even without passing the new mode
flag).

GnuPG-bug-id: 6705
This commit is contained in:
Werner Koch 2023-09-04 17:03:01 +02:00
parent b80d52a1f7
commit e36b2d1bce
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
7 changed files with 78 additions and 4 deletions

3
NEWS
View File

@ -3,10 +3,13 @@ Noteworthy changes in version 1.23.0 (unreleased)
* Support GPGME_ENCRYPT_ALWAYS_TRUST also for S/MIME. [T6559] * Support GPGME_ENCRYPT_ALWAYS_TRUST also for S/MIME. [T6559]
* New keylist mode GPGME_KEYLIST_MODE_WITH_V5FPR. [T6705]
* qt: Support refreshing keys via WKD. [T6672] * qt: Support refreshing keys via WKD. [T6672]
* Interface changes relative to the 1.22.0 release: * Interface changes relative to the 1.22.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_KEYLIST_MODE_WITH_V5FPR NEW.
qt: Protocol::wkdRefreshJob NEW. qt: Protocol::wkdRefreshJob NEW.
qt: WKDRefreshJob NEW. qt: WKDRefreshJob NEW.

View File

@ -2901,6 +2901,12 @@ option also makes sure that the keygrip is available in the output.
The @code{GPGME_KEYLIST_MODE_EPHEMERAL} symbol specifies that keys The @code{GPGME_KEYLIST_MODE_EPHEMERAL} symbol specifies that keys
flagged as ephemeral are included in the listing. flagged as ephemeral are included in the listing.
@item GPGME_KEYLIST_MODE_WITH_V5FPR
@since{1.23.0}
The @code{GPGME_KEYLIST_MODE_WITH_V5FPR} symbol specifies that key
listings shall also provide v5 style fingerprints for v4 OpenPGp keys.
@item GPGME_KEYLIST_MODE_VALIDATE @item GPGME_KEYLIST_MODE_VALIDATE
@since{0.4.5} @since{0.4.5}
@ -3610,6 +3616,10 @@ This is the key ID of the subkey in hexadecimal digits.
This is the fingerprint of the subkey in hexadecimal digits, if This is the fingerprint of the subkey in hexadecimal digits, if
available. available.
@item char *v5fpr
For a v4 OpenPGP key this is its v5 style fingerprint of the subkey in
hexadecimal digits, if available.
@item char *keygrip @item char *keygrip
@since{1.7.0} @since{1.7.0}

View File

@ -3267,6 +3267,12 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
err = add_arg (gpg, "--with-fingerprint"); err = add_arg (gpg, "--with-fingerprint");
} }
if (!err && (mode & GPGME_KEYLIST_MODE_WITH_V5FPR)
&& (have_gpg_version (gpg, "2.4.4")
|| (have_gpg_version (gpg, "2.2.42")
&& !have_gpg_version (gpg, "2.3.0"))))
err = add_arg (gpg, "--with-v5-fingerprint");
if (!err && (mode & GPGME_KEYLIST_MODE_WITH_TOFU) if (!err && (mode & GPGME_KEYLIST_MODE_WITH_TOFU)
&& have_gpg_version (gpg, "2.1.16")) && have_gpg_version (gpg, "2.1.16"))
err = add_arg (gpg, "--with-tofu-info"); err = add_arg (gpg, "--with-tofu-info");

View File

@ -384,6 +384,7 @@ gpgme_protocol_t;
#define GPGME_KEYLIST_MODE_EPHEMERAL 128 #define GPGME_KEYLIST_MODE_EPHEMERAL 128
#define GPGME_KEYLIST_MODE_VALIDATE 256 #define GPGME_KEYLIST_MODE_VALIDATE 256
#define GPGME_KEYLIST_MODE_FORCE_EXTERN 512 #define GPGME_KEYLIST_MODE_FORCE_EXTERN 512
#define GPGME_KEYLIST_MODE_WITH_V5FPR 1024
#define GPGME_KEYLIST_MODE_LOCATE (1|2) #define GPGME_KEYLIST_MODE_LOCATE (1|2)
#define GPGME_KEYLIST_MODE_LOCATE_EXTERNAL (1|2|512) #define GPGME_KEYLIST_MODE_LOCATE_EXTERNAL (1|2|512)
@ -616,6 +617,9 @@ struct _gpgme_subkey
/* The keygrip of the subkey in hex digit form or NULL if not available. */ /* The keygrip of the subkey in hex digit form or NULL if not available. */
char *keygrip; char *keygrip;
/* For OpenPGP the v5 fpr of a v4 key. For X.509 the SHA256 fingerprint. */
char *v5fpr;
}; };
typedef struct _gpgme_subkey *gpgme_subkey_t; typedef struct _gpgme_subkey *gpgme_subkey_t;

View File

@ -342,6 +342,7 @@ gpgme_key_unref (gpgme_key_t key)
{ {
gpgme_subkey_t next = subkey->next; gpgme_subkey_t next = subkey->next;
free (subkey->fpr); free (subkey->fpr);
free (subkey->v5fpr);
free (subkey->curve); free (subkey->curve);
free (subkey->keygrip); free (subkey->keygrip);
free (subkey->card_number); free (subkey->card_number);

View File

@ -58,6 +58,9 @@ typedef struct
/* The error code from ERROR keydb_search. */ /* The error code from ERROR keydb_search. */
gpgme_error_t keydb_search_err; gpgme_error_t keydb_search_err;
/* The error code from a FAILURE status line or 0. */
gpg_error_t failure_code;
gpgme_key_t tmp_key; gpgme_key_t tmp_key;
/* This points to the last uid in tmp_key. */ /* This points to the last uid in tmp_key. */
@ -146,6 +149,13 @@ keylist_status_handler (void *priv, gpgme_status_code_t code, char *args)
err = 0; err = 0;
break; break;
case GPGME_STATUS_FAILURE:
opd->failure_code = _gpgme_parse_failure (args);
if (opd->failure_code && !strcmp (args, "option-parser")
&& gpg_err_code (opd->failure_code) == GPG_ERR_GENERAL)
err = gpg_error (GPG_ERR_INV_ENGINE);
break;
case GPGME_STATUS_IMPORT_OK: case GPGME_STATUS_IMPORT_OK:
case GPGME_STATUS_IMPORT_PROBLEM: case GPGME_STATUS_IMPORT_PROBLEM:
case GPGME_STATUS_IMPORT_RES: case GPGME_STATUS_IMPORT_RES:
@ -570,7 +580,7 @@ keylist_colon_handler (void *priv, char *line)
gpgme_ctx_t ctx = (gpgme_ctx_t) priv; gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
enum enum
{ {
RT_NONE, RT_SIG, RT_UID, RT_TFS, RT_SUB, RT_PUB, RT_FPR, RT_GRP, RT_NONE, RT_SIG, RT_UID, RT_TFS, RT_SUB, RT_PUB, RT_FPR, RT_FP2, RT_GRP,
RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK RT_SSB, RT_SEC, RT_CRT, RT_CRS, RT_REV, RT_SPK
} }
rectype = RT_NONE; rectype = RT_NONE;
@ -623,6 +633,8 @@ keylist_colon_handler (void *priv, char *line)
rectype = RT_CRS; rectype = RT_CRS;
else if (!strcmp (field[0], "fpr") && key) else if (!strcmp (field[0], "fpr") && key)
rectype = RT_FPR; rectype = RT_FPR;
else if (!strcmp (field[0], "fp2") && key)
rectype = RT_FP2;
else if (!strcmp (field[0], "grp") && key) else if (!strcmp (field[0], "grp") && key)
rectype = RT_GRP; rectype = RT_GRP;
else if (!strcmp (field[0], "uid") && key) else if (!strcmp (field[0], "uid") && key)
@ -914,6 +926,27 @@ keylist_colon_handler (void *priv, char *line)
} }
break; break;
case RT_FP2:
/* Either the SHA256 fingerprint of an X.509 cert or the
* alternate fingerprint of a v4 OpenPGP packet. (We take only
* the first one). */
if (fields >= 10 && field[9] && *field[9])
{
/* Need to apply it to the last subkey because all subkeys
do have fingerprints. */
subkey = key->_last_subkey;
if (!subkey->v5fpr)
{
subkey->v5fpr = strdup (field[9]);
if (!subkey->v5fpr)
return gpg_error_from_syserror ();
}
/* Note that we don't store a copy in the key object as we
* do with the standard fingerprint. */
}
break;
case RT_GRP: case RT_GRP:
/* Field 10 has the keygrip. */ /* Field 10 has the keygrip. */
if (fields >= 10 && field[9] && *field[9]) if (fields >= 10 && field[9] && *field[9])
@ -1299,12 +1332,21 @@ gpgme_op_keylist_next (gpgme_ctx_t ctx, gpgme_key_t *r_key)
gpgme_error_t gpgme_error_t
gpgme_op_keylist_end (gpgme_ctx_t ctx) gpgme_op_keylist_end (gpgme_ctx_t ctx)
{ {
void *hook;
op_data_t opd;
gpg_error_t err;
TRACE (DEBUG_CTX, "gpgme_op_keylist_end", ctx, ""); TRACE (DEBUG_CTX, "gpgme_op_keylist_end", ctx, "");
if (!ctx) if (!ctx)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
return 0; err = _gpgme_op_data_lookup (ctx, OPDATA_KEYLIST, &hook, -1, NULL);
opd = hook;
if (!err && opd && opd->failure_code)
err = opd->failure_code;
return err;
} }

View File

@ -55,6 +55,7 @@ show_usage (int ex)
" --tofu use GPGME_KEYLIST_MODE_TOFU\n" " --tofu use GPGME_KEYLIST_MODE_TOFU\n"
" --sig-notations use GPGME_KEYLIST_MODE_SIG_NOTATIONS\n" " --sig-notations use GPGME_KEYLIST_MODE_SIG_NOTATIONS\n"
" --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n" " --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n"
" --v5fpr use GPGME_KEYLIST_MODE_V5FPR\n"
" --validate use GPGME_KEYLIST_MODE_VALIDATE\n" " --validate use GPGME_KEYLIST_MODE_VALIDATE\n"
" --import import all keys\n" " --import import all keys\n"
" --offline use offline mode\n" " --offline use offline mode\n"
@ -179,9 +180,14 @@ main (int argc, char **argv)
mode |= GPGME_KEYLIST_MODE_VALIDATE; mode |= GPGME_KEYLIST_MODE_VALIDATE;
argc--; argv++; argc--; argv++;
} }
else if (!strcmp (*argv, "--with-secret")) else if (!strcmp (*argv, "--validate"))
{ {
mode |= GPGME_KEYLIST_MODE_WITH_SECRET; mode |= GPGME_KEYLIST_MODE_VALIDATE;
argc--; argv++;
}
else if (!strcmp (*argv, "--v5fpr"))
{
mode |= GPGME_KEYLIST_MODE_WITH_V5FPR;
argc--; argv++; argc--; argv++;
} }
else if (!strcmp (*argv, "--import")) else if (!strcmp (*argv, "--import"))
@ -305,6 +311,8 @@ main (int argc, char **argv)
for (nsub=0; subkey; subkey = subkey->next, nsub++) for (nsub=0; subkey; subkey = subkey->next, nsub++)
{ {
printf ("fpr %2d: %s\n", nsub, nonnull (subkey->fpr)); printf ("fpr %2d: %s\n", nsub, nonnull (subkey->fpr));
if (subkey->v5fpr)
printf ("v5fpr %2d: %s\n", nsub, nonnull (subkey->v5fpr));
if (subkey->keygrip) if (subkey->keygrip)
printf ("grip %2d: %s\n", nsub, subkey->keygrip); printf ("grip %2d: %s\n", nsub, subkey->keygrip);
if (subkey->curve) if (subkey->curve)