From 4dc9af24156b4fd52c7b76e7522b9b7a64e5386a Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Wed, 4 Jun 2014 09:57:54 +0200 Subject: [PATCH] Add new keylist mode GPGME_KEYLIST_MODE_WITH_SECRET. * src/gpgme.h.in (GPGME_KEYLIST_MODE_WITH_SECRET): New. * src/engine-gpg.c (gpg_keylist_build_options): Handle new mode. * src/engine-gpgsm.c (gpgsm_keylist, gpgsm_keylist_ext): Ditto. * src/keylist.c (parse_sec_field15): Add arg key and take care of --with-secret output. * src/gpgme-tool.c (gt_get_keylist_mode, cmd_keylist_mode): Add "with_secret". Print card info and and secret flag for subkeys. -- Note: This mode may only be used with GnuPG >= 2.1. --- NEWS | 6 ++++++ doc/gpgme.texi | 22 ++++++++++++++++------ src/engine-gpg.c | 2 ++ src/engine-gpgsm.c | 12 +++++++++++- src/gpgme-tool.c | 10 ++++++++++ src/gpgme.h.in | 1 + src/keylist.c | 24 ++++++++++++++++++------ 7 files changed, 64 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index b7a6227d..c6a8f52e 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,12 @@ Noteworthy changes in version 1.5.1 (unreleased) [C__/A__/R_] ------------------------------------------------------------- + * Add support for GnuPG 2.1's --with-secret option. + + * Interface changes relative to the 1.5.0 release: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GPGME_KEYLIST_MODE_WITH_SECRET NEW. + Noteworthy changes in version 1.5.0 (2014-05-21) [C23/A12/R0] ------------------------------------------------------------- diff --git a/doc/gpgme.texi b/doc/gpgme.texi index e3265740..1f4a9e1d 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2472,6 +2472,13 @@ signature notations on key signatures should be included in the listed keys. This only works if @code{GPGME_KEYLIST_MODE_SIGS} is also enabled. +@item GPGME_KEYLIST_MODE_WITH_SECRET +The @code{GPGME_KEYLIST_MODE_WITH_SECRET} returns information about +the presence of a corresponding secret key in a public key listing. A +public key listing with this mode is slower than a standard listing +but can be used instead of a second run to list the secret keys. This +is only supported for GnuPG versions >= 2.1. + @item GPGME_KEYLIST_MODE_EPHEMERAL The @code{GPGME_KEYLIST_MODE_EPHEMERAL} symbol specifies that keys flagged as ephemeral are included in the listing. @@ -2712,9 +2719,11 @@ This is true if the subkey can be used for qualified signatures according to local government regulations. @item unsigned int secret : 1 -This is true if the subkey is a secret key. Note that it will be false -if the key is actually a stub key; i.e. a secret key operation is -currently not possible (offline-key). +This is true if the subkey is a secret key. Note that it will be +false if the key is actually a stub key; i.e. a secret key operation +is currently not possible (offline-key). This is only set if a +listing of secret keys has been requested or if +@code{GPGME_KEYLIST_MODE_WITH_SECRET} is active. @item gpgme_pubkey_algo_t pubkey_algo This is the public key algorithm supported by this subkey. @@ -2905,9 +2914,10 @@ This is true if the key can be used for qualified signatures according to local government regulations. @item unsigned int secret : 1 -This is true if the key is a secret key. Note, that this will always be -true even if the corresponding subkey flag may be false (offline/stub -keys). +This is true if the key is a secret key. Note, that this will always +be true even if the corresponding subkey flag may be false +(offline/stub keys). This is only set if a listing of secret keys has +been requested or if @code{GPGME_KEYLIST_MODE_WITH_SECRET} is active. @item gpgme_protocol_t protocol This is the protocol supported by this key. diff --git a/src/engine-gpg.c b/src/engine-gpg.c index ede098ef..4df0f3e4 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2194,6 +2194,8 @@ gpg_keylist_build_options (engine_gpg_t gpg, int secret_only, err = add_arg (gpg, "--with-fingerprint"); if (!err) err = add_arg (gpg, "--with-fingerprint"); + if (!err && (mode & GPGME_KEYLIST_MODE_WITH_SECRET)) + err = add_arg (gpg, "--with-secret"); if (!err && (mode & GPGME_KEYLIST_MODE_SIGS) && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS)) diff --git a/src/engine-gpgsm.c b/src/engine-gpgsm.c index 710bf14a..8ec15985 100644 --- a/src/engine-gpgsm.c +++ b/src/engine-gpgsm.c @@ -1551,7 +1551,7 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, the agent. However on a fresh installation no public keys are available and thus there is no need for gpgsm to ask the agent whether a secret key exists for the public key. */ - if (secret_only) + if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET)) gpgsm_assuan_simple_command (gpgsm->assuan_ctx, "GETINFO agent-check", NULL, NULL); @@ -1580,6 +1580,11 @@ gpgsm_keylist (void *engine, const char *pattern, int secret_only, "OPTION with-ephemeral-keys=1": "OPTION with-ephemeral-keys=0" , NULL, NULL); + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (mode & GPGME_KEYLIST_MODE_WITH_SECRET)? + "OPTION with-secret=1": + "OPTION with-secret=0" , + NULL, NULL); /* Length is "LISTSECRETKEYS " + p + '\0'. */ @@ -1645,6 +1650,11 @@ gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only, "OPTION with-validation=1": "OPTION with-validation=0" , NULL, NULL); + gpgsm_assuan_simple_command (gpgsm->assuan_ctx, + (mode & GPGME_KEYLIST_MODE_WITH_SECRET)? + "OPTION with-secret=1": + "OPTION with-secret=0" , + NULL, NULL); if (pattern && *pattern) diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index be8ed078..f02fffa7 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -1861,6 +1861,8 @@ gt_get_keylist_mode (gpgme_tool_t gt) modes[idx++] = "sigs"; if (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS) modes[idx++] = "sig_notations"; + if (mode & GPGME_KEYLIST_MODE_WITH_SECRET) + modes[idx++] = "with_secret"; if (mode & GPGME_KEYLIST_MODE_EPHEMERAL) modes[idx++] = "ephemeral"; if (mode & GPGME_KEYLIST_MODE_VALIDATE) @@ -2591,6 +2593,8 @@ cmd_keylist_mode (assuan_context_t ctx, char *line) mode |= GPGME_KEYLIST_MODE_SIGS; if (strstr (line, "sig_notations")) mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS; + if (strstr (line, "with_secret")) + mode |= GPGME_KEYLIST_MODE_WITH_SECRET; if (strstr (line, "ephemeral")) mode |= GPGME_KEYLIST_MODE_EPHEMERAL; if (strstr (line, "validate")) @@ -3299,6 +3303,12 @@ cmd_keylist (assuan_context_t ctx, char *line) result_xml_tag_start (&state, "subkey", NULL); /* FIXME: more data */ result_add_fpr (&state, "fpr", subkey->fpr); + result_add_value (&state, "secret", subkey->secret); + result_add_value (&state, "is_cardkey", subkey->is_cardkey); + if (subkey->card_number) + result_add_string (&state, "card_number", subkey->card_number); + if (subkey->curve) + result_add_string (&state, "curve", subkey->curve); result_xml_tag_end (&state); /* subkey */ subkey = subkey->next; } diff --git a/src/gpgme.h.in b/src/gpgme.h.in index d47f4ba9..15ed8037 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -370,6 +370,7 @@ gpgme_protocol_t; #define GPGME_KEYLIST_MODE_EXTERN 2 #define GPGME_KEYLIST_MODE_SIGS 4 #define GPGME_KEYLIST_MODE_SIG_NOTATIONS 8 +#define GPGME_KEYLIST_MODE_WITH_SECRET 16 #define GPGME_KEYLIST_MODE_EPHEMERAL 128 #define GPGME_KEYLIST_MODE_VALIDATE 256 diff --git a/src/keylist.c b/src/keylist.c index 582b241b..36ee3eaa 100644 --- a/src/keylist.c +++ b/src/keylist.c @@ -367,7 +367,7 @@ set_ownertrust (gpgme_key_t key, const char *src) reference to smartcards. FIELD is the content of the field and we are allowed to modify it. */ static gpg_error_t -parse_sec_field15 (gpgme_subkey_t subkey, char *field) +parse_sec_field15 (gpgme_key_t key, gpgme_subkey_t subkey, char *field) { if (!*field) ; /* Empty. */ @@ -375,17 +375,25 @@ parse_sec_field15 (gpgme_subkey_t subkey, char *field) { /* This is a stub for an offline key. We reset the SECRET flag of the subkey here. Note that the secret flag of the entire - key will be true even then. */ + key will be true even then. We even explicitly set + key->secret to make it works for GPGME_KEYLIST_MODE_WITH_SECRET. */ subkey->secret = 0; + key->secret = 1; } else if (strchr ("01234567890ABCDEFabcdef", *field)) { /* Fields starts with a hex digit; thus it is a serial number. */ + key->secret = 1; subkey->is_cardkey = 1; subkey->card_number = strdup (field); if (!subkey->card_number) return gpg_error_from_syserror (); } + else if (*field == '+') + { + key->secret = 1; + subkey->secret = 1; + } else { /* RFU. */ @@ -578,9 +586,11 @@ keylist_colon_handler (void *priv, char *line) set_mainkey_capability (key, field[11]); /* Field 15 carries special flags of a secret key. */ - if (fields >= 15 && key->secret) + if (fields >= 15 + && (key->secret + || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET))) { - err = parse_sec_field15 (subkey, field[14]); + err = parse_sec_field15 (key, subkey, field[14]); if (err) return err; } @@ -649,9 +659,11 @@ keylist_colon_handler (void *priv, char *line) set_subkey_capability (subkey, field[11]); /* Field 15 carries special flags of a secret key. */ - if (fields >= 15 && key->secret) + if (fields >= 15 + && (key->secret + || (ctx->keylist_mode & GPGME_KEYLIST_MODE_WITH_SECRET))) { - err = parse_sec_field15 (subkey, field[14]); + err = parse_sec_field15 (key, subkey, field[14]); if (err) return err; }