More agent support for gpg.

This commit is contained in:
Werner Koch 2010-10-13 15:57:08 +00:00
parent 5a679857ef
commit 54591341a4
33 changed files with 496 additions and 311 deletions

5
NEWS
View File

@ -43,10 +43,13 @@ Noteworthy changes in version 2.1.x (under development)
* The OpenPGP import command is now able to merge secret keys. * The OpenPGP import command is now able to merge secret keys.
* Removed options: * Removed GPG options:
--export-options: export-secret-subkey-passwd --export-options: export-secret-subkey-passwd
--simple-sk-checksum --simple-sk-checksum
* New GPG options:
--try-secret-key
Noteworthy changes in version 2.0.13 (2009-09-04) Noteworthy changes in version 2.0.13 (2009-09-04)
------------------------------------------------- -------------------------------------------------

View File

@ -1,3 +1,24 @@
2010-10-13 Werner Koch <wk@g10code.com>
* call-pinentry.c (agent_get_passphrase): Support the close_button.
* gpg-agent.c (create_server_socket): Switch back to stderr
logging if we are not starting a agent.
* command.c (cmd_passwd, cmd_export_key): Move mapping of
GPG_ERR_FULLY_CANCELED to ..
(leave_cmd): .. here.
(option_handler): Add option agent-awareness.
* protect-tool.c (get_passphrase): Take care of
GPG_ERR_FULLY_CANCELED.
* findkey.c (try_unprotect_cb): Ditto.
(unprotect): Remove the fully_canceled hack.
* call-pinentry.c (start_pinentry): Ditto.
(agent_askpin): Ditto.
* pkdecrypt.c (agent_pkdecrypt): Ditto
* pksign.c (agent_pksign_do): Ditto.
* genkey.c (agent_ask_new_passphrase): Remove arg CANCEL_ALL.
2010-10-06 Werner Koch <wk@g10code.com> 2010-10-06 Werner Koch <wk@g10code.com>
* cvt-openpgp.c (convert_secret_key): Add missing break. * cvt-openpgp.c (convert_secret_key): Add missing break.

View File

@ -253,7 +253,7 @@ int pinentry_active_p (ctrl_t ctrl, int waitseconds);
int agent_askpin (ctrl_t ctrl, int agent_askpin (ctrl_t ctrl,
const char *desc_text, const char *prompt_text, const char *desc_text, const char *prompt_text,
const char *inital_errtext, const char *inital_errtext,
struct pin_entry_info_s *pininfo, int *r_cancelall); struct pin_entry_info_s *pininfo);
int agent_get_passphrase (ctrl_t ctrl, char **retpass, int agent_get_passphrase (ctrl_t ctrl, char **retpass,
const char *desc, const char *prompt, const char *desc, const char *prompt,
const char *errtext, int with_qualitybar); const char *errtext, int with_qualitybar);
@ -291,7 +291,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
/*-- genkey.c --*/ /*-- genkey.c --*/
int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent); int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent);
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
char **r_passphrase, int *r_cancelall); char **r_passphrase);
int agent_genkey (ctrl_t ctrl, const char *cache_nonce, int agent_genkey (ctrl_t ctrl, const char *cache_nonce,
const char *keyparam, size_t keyparmlen, membuf_t *outbuf); const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey); int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);

View File

@ -467,8 +467,10 @@ start_pinentry (ctrl_t ctrl)
else else
{ {
rc = agent_inq_pinentry_launched (ctrl, pinentry_pid); rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
if (gpg_err_code (rc) == GPG_ERR_CANCELED) if (gpg_err_code (rc) == GPG_ERR_CANCELED
return unlock_pinentry (gpg_error (GPG_ERR_CANCELED)); || gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
return unlock_pinentry (gpg_err_make (GPG_ERR_SOURCE_DEFAULT,
gpg_err_code (rc)));
rc = 0; rc = 0;
} }
@ -727,7 +729,7 @@ int
agent_askpin (ctrl_t ctrl, agent_askpin (ctrl_t ctrl,
const char *desc_text, const char *prompt_text, const char *desc_text, const char *prompt_text,
const char *initial_errtext, const char *initial_errtext,
struct pin_entry_info_s *pininfo, int *r_cancel_all) struct pin_entry_info_s *pininfo)
{ {
int rc; int rc;
char line[ASSUAN_LINELENGTH]; char line[ASSUAN_LINELENGTH];
@ -737,9 +739,6 @@ agent_askpin (ctrl_t ctrl,
int saveflag; int saveflag;
int close_button; int close_button;
if (r_cancel_all)
*r_cancel_all = 0;
if (opt.batch) if (opt.batch)
return 0; /* fixme: we should return BAD PIN */ return 0; /* fixme: we should return BAD PIN */
@ -830,10 +829,10 @@ agent_askpin (ctrl_t ctrl,
&& gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
/* Set a flag in case the window close button was clicked to /* Change error code in case the window close button was clicked
cancel the operation. */ to cancel the operation. */
if (close_button && r_cancel_all && gpg_err_code (rc) == GPG_ERR_CANCELED) if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED)
*r_cancel_all = 1; rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA) if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
errtext = is_pin? _("PIN too long") errtext = is_pin? _("PIN too long")
@ -890,6 +889,7 @@ agent_get_passphrase (ctrl_t ctrl,
char line[ASSUAN_LINELENGTH]; char line[ASSUAN_LINELENGTH];
struct entry_parm_s parm; struct entry_parm_s parm;
int saveflag; int saveflag;
int close_button;
*retpass = NULL; *retpass = NULL;
if (opt.batch) if (opt.batch)
@ -942,14 +942,21 @@ agent_get_passphrase (ctrl_t ctrl,
saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL); saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
assuan_begin_confidential (entry_ctx); assuan_begin_confidential (entry_ctx);
close_button = 0;
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
inq_quality, entry_ctx, NULL, NULL); inq_quality, entry_ctx,
close_button_status_cb, &close_button);
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag); assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
/* Most pinentries out in the wild return the old Assuan error code /* Most pinentries out in the wild return the old Assuan error code
for canceled which gets translated to an assuan Cancel error and for canceled which gets translated to an assuan Cancel error and
not to the code for a user cancel. Fix this here. */ not to the code for a user cancel. Fix this here. */
if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED) if (rc && gpg_err_source (rc) && gpg_err_code (rc) == GPG_ERR_ASS_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED); rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
/* Change error code in case the window close button was clicked
to cancel the operation. */
if (close_button && gpg_err_code (rc) == GPG_ERR_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
if (rc) if (rc)
xfree (parm.buffer); xfree (parm.buffer);
else else

View File

@ -2425,7 +2425,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
pi2->check_cb_arg = pi->pin; pi2->check_cb_arg = pi->pin;
next_try: next_try:
err = agent_askpin (ctrl, description, NULL, initial_errtext, pi, NULL); err = agent_askpin (ctrl, description, NULL, initial_errtext, pi);
initial_errtext = NULL; initial_errtext = NULL;
if (err) if (err)
goto out; goto out;
@ -2433,7 +2433,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
/* Unless the passphrase is empty, ask to confirm it. */ /* Unless the passphrase is empty, ask to confirm it. */
if (pi->pin && *pi->pin) if (pi->pin && *pi->pin)
{ {
err = agent_askpin (ctrl, description2, NULL, NULL, pi2, NULL); err = agent_askpin (ctrl, description2, NULL, NULL, pi2);
if (err == -1) if (err == -1)
{ /* The re-entered one did not match and the user did not { /* The re-entered one did not match and the user did not
hit cancel. */ hit cancel. */

View File

@ -71,6 +71,7 @@ struct server_local_s
be done. */ be done. */
void *import_key; /* Malloced KEK for the import_key command. */ void *import_key; /* Malloced KEK for the import_key command. */
void *export_key; /* Malloced KEK for the export_key command. */ void *export_key; /* Malloced KEK for the export_key command. */
int allow_fully_canceled; /* Client is aware of GPG_ERR_FULLY_CANCELED. */
}; };
@ -364,6 +365,16 @@ leave_cmd (assuan_context_t ctx, gpg_error_t err)
if (!name) if (!name)
name = "?"; name = "?";
/* Not all users of gpg-agent know about the fully canceled
error code; map it back if needed. */
if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
if (!ctrl->server_local->allow_fully_canceled)
err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
}
/* Most code from common/ does not know the error source, thus /* Most code from common/ does not know the error source, thus
we fix this here. */ we fix this here. */
if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN) if (gpg_err_source (err) == GPG_ERR_SOURCE_UNKNOWN)
@ -1336,12 +1347,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
grip, &shadow_info, CACHE_MODE_IGNORE, NULL, grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
&s_skey, NULL); &s_skey, NULL);
if (rc) if (rc)
{ ;
/* Not all users of gpg-agent know about fully cancled; thus we
map it back. */
if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
}
else if (!s_skey) else if (!s_skey)
{ {
log_error ("changing a smartcard PIN is not yet supported\n"); log_error ("changing a smartcard PIN is not yet supported\n");
@ -1643,7 +1649,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
err = agent_ask_new_passphrase err = agent_ask_new_passphrase
(ctrl, _("Please enter the passphrase to protect the " (ctrl, _("Please enter the passphrase to protect the "
"imported object within the GnuPG system."), "imported object within the GnuPG system."),
&passphrase, NULL); &passphrase);
if (err) if (err)
goto leave; goto leave;
} }
@ -1751,17 +1757,12 @@ cmd_export_key (assuan_context_t ctx, char *line)
canonical S-expression. */ canonical S-expression. */
if (!passphrase) if (!passphrase)
{ {
int fully_canceled;
err = agent_ask_new_passphrase err = agent_ask_new_passphrase
(ctrl, _("This key (or subkey) is not protected with a passphrase." (ctrl, _("This key (or subkey) is not protected with a passphrase."
" Please enter a new passphrase to export it."), " Please enter a new passphrase to export it."),
&passphrase, &fully_canceled); &passphrase);
if (err) if (err)
{ goto leave;
if (fully_canceled)
err = gpg_error (GPG_ERR_FULLY_CANCELED);
goto leave;
}
} }
err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen); err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen);
} }
@ -1814,10 +1815,6 @@ cmd_export_key (assuan_context_t ctx, char *line)
xfree (ctrl->server_local->keydesc); xfree (ctrl->server_local->keydesc);
ctrl->server_local->keydesc = NULL; ctrl->server_local->keydesc = NULL;
/* Not all users of gpg-agent know about fully cancled; thus we map
it back unless we know that it is okay. */
if (!openpgp && gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
err = gpg_err_make (gpg_err_source (err), GPG_ERR_CANCELED);
return leave_cmd (ctx, err); return leave_cmd (ctx, err);
} }
@ -2185,7 +2182,14 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err = 0; gpg_error_t err = 0;
if (!strcmp (key, "putenv")) if (!strcmp (key, "agent-awareness"))
{
/* The value is a version string telling us of which agent
version the caller is aware of. */
ctrl->server_local->allow_fully_canceled =
gnupg_compare_version (value, "2.1.0");
}
else if (!strcmp (key, "putenv"))
{ {
/* Change the session's environment to be used for the /* Change the session's environment to be used for the
Pinentry. Valid values are: Pinentry. Valid values are:

View File

@ -780,7 +780,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
err = try_do_unprotect_cb (pi); err = try_do_unprotect_cb (pi);
} }
if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE) if (gpg_err_code (err) == GPG_ERR_BAD_PASSPHRASE)
err = agent_askpin (ctrl, prompt, NULL, NULL, pi, NULL); err = agent_askpin (ctrl, prompt, NULL, NULL, pi);
skeyidx = pi_arg.skeyidx; skeyidx = pi_arg.skeyidx;
if (!err) if (!err)
{ {

View File

@ -266,7 +266,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
if (any_flags) if (any_flags)
{ {
rc = agent_askpin (ctrl, info, prompt, again_text, pi, NULL); rc = agent_askpin (ctrl, info, prompt, again_text, pi);
again_text = NULL; again_text = NULL;
if (!rc && newpin) if (!rc && newpin)
{ {
@ -288,7 +288,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
is_puk? is_puk?
_("Repeat this PUK"): _("Repeat this PUK"):
_("Repeat this PIN")), _("Repeat this PIN")),
prompt, NULL, pi2, NULL); prompt, NULL, pi2);
if (!rc && strcmp (pi->pin, pi2->pin)) if (!rc && strcmp (pi->pin, pi2->pin))
{ {
again_text = (resetcode? again_text = (resetcode?
@ -312,7 +312,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
info? info:"", info? info:"",
info? "')":"") < 0) info? "')":"") < 0)
desc = NULL; desc = NULL;
rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi, NULL); rc = agent_askpin (ctrl, desc?desc:info, prompt, NULL, pi);
xfree (desc); xfree (desc);
} }

View File

@ -169,7 +169,8 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
_("I'll change it later"), 0); _("I'll change it later"), 0);
if (!err) if (!err)
arg->change_required = 1; arg->change_required = 1;
else if (gpg_err_code (err) == GPG_ERR_CANCELED) else if (gpg_err_code (err) == GPG_ERR_CANCELED
|| gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
err = 0; err = 0;
} }
xfree (desc); xfree (desc);
@ -290,7 +291,6 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
unsigned char *result; unsigned char *result;
size_t resultlen; size_t resultlen;
char hexgrip[40+1]; char hexgrip[40+1];
int fully_canceled;
if (r_passphrase) if (r_passphrase)
*r_passphrase = NULL; *r_passphrase = NULL;
@ -383,9 +383,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
arg.change_required = 0; arg.change_required = 0;
pi->check_cb_arg = &arg; pi->check_cb_arg = &arg;
rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, &fully_canceled); rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
if (gpg_err_code (rc) == GPG_ERR_CANCELED && fully_canceled)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
if (!rc) if (!rc)
{ {
assert (arg.unprotected_key); assert (arg.unprotected_key);

View File

@ -290,12 +290,10 @@ reenter_compare_cb (struct pin_entry_info_s *pi)
function returns 0 and store the passphrase at R_PASSPHRASE; if the function returns 0 and store the passphrase at R_PASSPHRASE; if the
user opted not to use a passphrase NULL will be stored there. The user opted not to use a passphrase NULL will be stored there. The
user needs to free the returned string. In case of an error and user needs to free the returned string. In case of an error and
error code is returned and NULL stored at R_PASSPHRASE. If error code is returned and NULL stored at R_PASSPHRASE. */
R_CANCEL_ALL is not NULL and the user canceled by directly closing
the window true will be stored at this address. */
gpg_error_t gpg_error_t
agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
char **r_passphrase, int *r_cancel_all) char **r_passphrase)
{ {
gpg_error_t err; gpg_error_t err;
const char *text1 = prompt; const char *text1 = prompt;
@ -316,7 +314,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
pi2->check_cb_arg = pi->pin; pi2->check_cb_arg = pi->pin;
next_try: next_try:
err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi, r_cancel_all); err = agent_askpin (ctrl, text1, NULL, initial_errtext, pi);
initial_errtext = NULL; initial_errtext = NULL;
if (!err) if (!err)
{ {
@ -329,7 +327,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
/* Unless the passphrase is empty, ask to confirm it. */ /* Unless the passphrase is empty, ask to confirm it. */
if (pi->pin && *pi->pin) if (pi->pin && *pi->pin)
{ {
err = agent_askpin (ctrl, text2, NULL, NULL, pi2, NULL); err = agent_askpin (ctrl, text2, NULL, NULL, pi2);
if (err == -1) if (err == -1)
{ /* The re-entered one did not match and the user did not { /* The re-entered one did not match and the user did not
hit cancel. */ hit cancel. */
@ -381,7 +379,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
rc = agent_ask_new_passphrase (ctrl, rc = agent_ask_new_passphrase (ctrl,
_("Please enter the passphrase to%0A" _("Please enter the passphrase to%0A"
"to protect your new key"), "to protect your new key"),
&passphrase, NULL); &passphrase);
if (rc) if (rc)
return rc; return rc;
@ -473,7 +471,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey)
rc = agent_ask_new_passphrase (ctrl, rc = agent_ask_new_passphrase (ctrl,
_("Please enter the new passphrase"), _("Please enter the new passphrase"),
&passphrase, NULL); &passphrase);
if (!rc) if (!rc)
{ {
rc = store_key (s_skey, passphrase, 1); rc = store_key (s_skey, passphrase, 1);

View File

@ -1523,6 +1523,8 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
a hang. */ a hang. */
if (!is_ssh && !check_for_running_agent (1, 1)) if (!is_ssh && !check_for_running_agent (1, 1))
{ {
log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX);
log_set_file (NULL);
log_error (_("a gpg-agent is already running - " log_error (_("a gpg-agent is already running - "
"not starting a new one\n")); "not starting a new one\n"));
*name = 0; /* Inhibit removal of the socket by cleanup(). */ *name = 0; /* Inhibit removal of the socket by cleanup(). */

View File

@ -67,8 +67,6 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
rc = agent_key_from_file (ctrl, NULL, desc_text, rc = agent_key_from_file (ctrl, NULL, desc_text,
ctrl->keygrip, &shadow_info, ctrl->keygrip, &shadow_info,
CACHE_MODE_NORMAL, NULL, &s_skey, NULL); CACHE_MODE_NORMAL, NULL, &s_skey, NULL);
if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
if (rc) if (rc)
{ {
if (gpg_err_code (rc) == GPG_ERR_ENOENT) if (gpg_err_code (rc) == GPG_ERR_ENOENT)

View File

@ -256,8 +256,6 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip, rc = agent_key_from_file (ctrl, cache_nonce, desc_text, ctrl->keygrip,
&shadow_info, cache_mode, lookup_ttl, &shadow_info, cache_mode, lookup_ttl,
&s_skey, NULL); &s_skey, NULL);
if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
if (rc) if (rc)
{ {
log_error ("failed to read the secret key\n"); log_error ("failed to read the secret key\n");

View File

@ -704,7 +704,8 @@ get_passphrase (int promptno)
repeat, repeat, 1, &pw); repeat, repeat, 1, &pw);
if (err) if (err)
{ {
if (gpg_err_code (err) == GPG_ERR_CANCELED) if (gpg_err_code (err) == GPG_ERR_CANCELED
|| gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
log_info (_("cancelled\n")); log_info (_("cancelled\n"));
else else
log_error (_("error while asking for the passphrase: %s\n"), log_error (_("error while asking for the passphrase: %s\n"),

View File

@ -1,3 +1,8 @@
2010-10-13 Werner Koch <wk@g10code.com>
* miscellaneous.c (parse_version_number, parse_version_string)
(gnupg_compare_version): New.
2010-10-04 Werner Koch <wk@g10code.com> 2010-10-04 Werner Koch <wk@g10code.com>
* gettime.c (asctimestamp) [W32CE]: Do not print the timezone. * gettime.c (asctimestamp) [W32CE]: Do not print the timezone.

View File

@ -236,3 +236,81 @@ match_multistr (const char *multistr,const char *match)
} }
/* Parse the first portion of the version number S and store it at
NUMBER. On success, the function returns a pointer into S starting
with the first character, which is not part of the initial number
portion; on failure, NULL is returned. */
static const char*
parse_version_number (const char *s, int *number)
{
int val = 0;
if (*s == '0' && digitp (s+1))
return NULL; /* Leading zeros are not allowed. */
for (; digitp (s); s++ )
{
val *= 10;
val += *s - '0';
}
*number = val;
return val < 0? NULL : s;
}
/* Break up the complete string representation of the version number S,
which is expected to have this format:
<major number>.<minor number>.<micro number><patch level>.
The major, minor and micro number components will be stored at
MAJOR, MINOR and MICRO. On success, a pointer to the last
component, the patch level, will be returned; on failure, NULL will
be returned. */
static const char *
parse_version_string (const char *s, int *major, int *minor, int *micro)
{
s = parse_version_number (s, major);
if (!s || *s != '.')
return NULL;
s++;
s = parse_version_number (s, minor);
if (!s || *s != '.')
return NULL;
s++;
s = parse_version_number (s, micro);
if (!s)
return NULL;
return s; /* Patchlevel. */
}
/* Return true if version string is at least version B. */
int
gnupg_compare_version (const char *a, const char *b)
{
int a_major, a_minor, a_micro;
int b_major, b_minor, b_micro;
const char *a_plvl, *b_plvl;
if (!a || !b)
return 0;
/* Parse version A. */
a_plvl = parse_version_string (a, &a_major, &a_minor, &a_micro);
if (!a_plvl )
return 0; /* Invalid version number. */
/* Parse version B. */
b_plvl = parse_version_string (b, &b_major, &b_minor, &b_micro);
if (!b_plvl )
return 0; /* Invalid version number. */
/* Compare version numbers. */
return (a_major > b_major
|| (a_major == b_major && a_minor > b_minor)
|| (a_major == b_major && a_minor == b_minor
&& a_micro > b_micro)
|| (a_major == b_major && a_minor == b_minor
&& a_micro == b_micro
&& strcmp (a_plvl, b_plvl) >= 0));
}

View File

@ -267,6 +267,8 @@ int is_file_compressed (const char *s, int *ret_rc);
int match_multistr (const char *multistr,const char *match); int match_multistr (const char *multistr,const char *match);
int gnupg_compare_version (const char *a, const char *b);
/*-- Simple replacement functions. */ /*-- Simple replacement functions. */
#ifndef HAVE_TTYNAME #ifndef HAVE_TTYNAME

View File

@ -1782,13 +1782,27 @@ Remove all entries from the @option{--group} list.
Use @var{name} as the key to sign with. Note that this option overrides Use @var{name} as the key to sign with. Note that this option overrides
@option{--default-key}. @option{--default-key}.
@ifset gpgtwoone
@item --try-secret-key @var{name}
@opindex try-secret-key
For hidden recipients GPG needs to know the keys to use for trial
decryption. The key set with @option{--default-key} is always tried
first, but this is often not sufficient. This option allows to set more
keys to be used for trial decryption. Although any valid user-id
specification may be used for @var{name} it makes sense to use at least
the long keyid to avoid ambiguities. Note that gpg-agent might pop up a
pinentry for a lot keys to do the trial decryption. If you want to stop
all further trial decryption you may use close-window button instead of
the cancel button.
@end ifset
@item --try-all-secrets @item --try-all-secrets
@opindex try-all-secrets @opindex try-all-secrets
Don't look at the key ID as stored in the message but try all secret Don't look at the key ID as stored in the message but try all secret
keys in turn to find the right decryption key. This option forces the keys in turn to find the right decryption key. This option forces the
behaviour as used by anonymous recipients (created by using behaviour as used by anonymous recipients (created by using
@option{--throw-keyids}) and might come handy in case where an encrypted @option{--throw-keyids} or @option{--hidden-recipient}) and might come
message contains a bogus key ID. handy in case where an encrypted message contains a bogus key ID.
@item --skip-hidden-recipients @item --skip-hidden-recipients
@itemx --no-skip-hidden-recipients @itemx --no-skip-hidden-recipients

View File

@ -1,3 +1,33 @@
2010-10-13 Werner Koch <wk@g10code.com>
* call-agent.c (start_agent): Send option agent-awareness.
(status_sc_op_failure): Take care of GPG_ERR_FULLY_CANCELED.
* passphrase.c (passphrase_get): Ditto.
* import.c (transfer_secret_keys): Ditto.
* card-util.c (write_sc_op_status): Ditto.
* getkey.c (enum_secret_keys): Rewrite.
* pubkey-enc.c (get_session_key): Skip keys without an encryption
capability. Handle GPG_ERR_FULLY_CANCELED.
* gpg.c: Add option --try-secret-key.
* options.h (struct opt): Add field secret_keys_to_try.
* passphrase.c (next_to_last_passphrase): Remove.
2010-10-12 Werner Koch <wk@g10code.com>
* keygen.c (generate_subkeypair): Check availibility of secret parts.
* keylist.c (print_card_serialno): Change to take a hexified serialno.
(list_keyblock_print): Print serialno and stub key indicators.
(list_keyblock_colon): Ditto.
* getkey.c (have_any_secret_key): Remove. Replace all calls by
agent_probe_any_secret_key.
* gpgv.c (agent_probe_any_secret_key): New.
(agent_get_keyinfo): New.
2010-10-08 Werner Koch <wk@g10code.com> 2010-10-08 Werner Koch <wk@g10code.com>
* gpg.c: Add option --with-keygrip. * gpg.c: Add option --with-keygrip.

View File

@ -99,6 +99,7 @@ status_sc_op_failure (int rc)
case 0: case 0:
break; break;
case GPG_ERR_CANCELED: case GPG_ERR_CANCELED:
case GPG_ERR_FULLY_CANCELED:
write_status_text (STATUS_SC_OP_FAILURE, "1"); write_status_text (STATUS_SC_OP_FAILURE, "1");
break; break;
case GPG_ERR_BAD_PIN: case GPG_ERR_BAD_PIN:
@ -142,6 +143,11 @@ start_agent (ctrl_t ctrl, int for_card)
agents. */ agents. */
assuan_transact (agent_ctx, "OPTION allow-pinentry-notify", assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
NULL, NULL, NULL, NULL, NULL, NULL); NULL, NULL, NULL, NULL, NULL, NULL);
/* Tell the agent about what version we are aware. This is
here used to indirectly enable GPG_ERR_FULLY_CANCELED. */
assuan_transact (agent_ctx, "OPTION agent-awareness=2.1.0",
NULL, NULL, NULL, NULL, NULL, NULL);
} }
} }

View File

@ -58,6 +58,7 @@ write_sc_op_status (gpg_error_t err)
break; break;
#if GNUPG_MAJOR_VERSION != 1 #if GNUPG_MAJOR_VERSION != 1
case GPG_ERR_CANCELED: case GPG_ERR_CANCELED:
case GPG_ERR_FULLY_CANCELED:
write_status_text (STATUS_SC_OP_FAILURE, "1"); write_status_text (STATUS_SC_OP_FAILURE, "1");
break; break;
case GPG_ERR_BAD_PIN: case GPG_ERR_BAD_PIN:

View File

@ -568,8 +568,9 @@ leave:
* first pubkey certificate which has the given name in a user_id. If * first pubkey certificate which has the given name in a user_id. If
* PK has the pubkey algo set, the function will only return a pubkey * PK has the pubkey algo set, the function will only return a pubkey
* with that algo. If NAMELIST is NULL, the first key is returned. * with that algo. If NAMELIST is NULL, the first key is returned.
* The caller should provide storage for the PK. If RET_KB is not * The caller should provide storage for the PK or pass NULL if it is
* NULL the function will return the keyblock there. */ * not needed. If RET_KB is not NULL the function stores the entire
* keyblock at that address. */
static int static int
key_byname (GETKEY_CTX *retctx, strlist_t namelist, key_byname (GETKEY_CTX *retctx, strlist_t namelist,
PKT_public_key *pk, PKT_public_key *pk,
@ -1146,12 +1147,13 @@ getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
} }
/* Get a key by name and store it into PK. If RETCTX is not NULL /* Get a key by name and store it into PK if that is not NULL. If
* return the search context which needs to be released by the caller * RETCTX is not NULL return the search context which needs to be
* using getkey_end. If NAME is NULL use the default key (see below). * released by the caller using getkey_end. If NAME is NULL use the
* On success and if RET_KEYBLOCK is not NULL the found keyblock is * default key (see below). On success and if RET_KEYBLOCK is not
* stored at this address. WANT_SECRET passed as true requires that a * NULL the found keyblock is stored at this address. WANT_SECRET
* secret key is available for the selected key. * passed as true requires that a secret key is available for the
* selected key.
* *
* If WANT_SECRET is true and NAME is NULL and a default key has been * If WANT_SECRET is true and NAME is NULL and a default key has been
* defined that defined key is used. In all other cases the first * defined that defined key is used. In all other cases the first
@ -2459,7 +2461,7 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
goto skip; goto skip;
} }
if (want_secret && !have_any_secret_key (NULL, ctx->keyblock)) if (want_secret && agent_probe_any_secret_key (NULL, ctx->keyblock))
goto skip; /* No secret key available. */ goto skip; /* No secret key available. */
/* Warning: node flag bits 0 and 1 should be preserved by /* Warning: node flag bits 0 and 1 should be preserved by
@ -2504,57 +2506,42 @@ found:
/**************** /*
* FIXME: Replace by the generic function * Enumerate certain secret keys. Caller must use these procedure:
* It does not work as it is right now - it is used at
* one place: to get the key for an anonymous recipient.
*
* set with_subkeys true to include subkeys
* set with_spm true to include secret-parts-missing keys
*
* Enumerate all primary secret keys. Caller must use these procedure:
* 1) create a void pointer and initialize it to NULL * 1) create a void pointer and initialize it to NULL
* 2) pass this void pointer by reference to this function * 2) pass this void pointer by reference to this function
* and provide space for the secret key (pass a buffer for sk) * and provide space for the secret key (pass a buffer for sk)
* 3) call this function as long as it does not return -1 * 3) call this function as long as it does not return an error.
* to indicate EOF. * The error code GPG_ERR_EOF indicates the end of the listing.
* 4) Always call this function a last time with SK set to NULL, * 4) Always call this function a last time with SK set to NULL,
* so that can free it's context. * so that can free it's context.
*/ */
int gpg_error_t
enum_secret_keys (void **context, PKT_public_key * sk, enum_secret_keys (void **context, PKT_public_key *sk)
int with_subkeys, int with_spm)
{ {
log_debug ("FIXME: Anonymous recipient does not yet work\n"); gpg_error_t err = 0;
return -1; const char *name;
#if 0
int rc = 0;
struct struct
{ {
int eof; int eof;
int first; int state;
KEYDB_HANDLE hd; strlist_t sl;
KBNODE keyblock; kbnode_t keyblock;
KBNODE node; kbnode_t node;
} *c = *context; } *c = *context;
if (!c) if (!c)
{ {
/* Make a new context. */ /* Make a new context. */
c = xmalloc_clear (sizeof *c); c = xtrycalloc (1, sizeof *c);
if (!c)
return gpg_error_from_syserror ();
*context = c; *context = c;
c->hd = keydb_new (1); /*FIXME*/
c->first = 1;
c->keyblock = NULL;
c->node = NULL;
} }
if (!sk) if (!sk)
{ {
/* Free the context. */ /* Free the context. */
keydb_release (c->hd);
release_kbnode (c->keyblock); release_kbnode (c->keyblock);
xfree (c); xfree (c);
*context = NULL; *context = NULL;
@ -2562,48 +2549,79 @@ enum_secret_keys (void **context, PKT_public_key * sk,
} }
if (c->eof) if (c->eof)
return -1; return gpg_error (GPG_ERR_EOF);
do for (;;)
{ {
/* Get the next secret key from the current keyblock. */ /* Loop until we have a keyblock. */
while (!c->keyblock)
{
/* Loop over the list of secret keys. */
do
{
name = NULL;
switch (c->state)
{
case 0: /* First try to use the --default-key. */
if (opt.def_secret_key && *opt.def_secret_key)
name = opt.def_secret_key;
c->state = 1;
break;
case 1: /* Init list of keys to try. */
c->sl = opt.secret_keys_to_try;
c->state++;
break;
case 2: /* Get next item from list. */
if (c->sl)
{
name = c->sl->d;
c->sl = c->sl->next;
}
else
c->state++;
break;
default: /* No more names to check - stop. */
c->eof = 1;
return gpg_error (GPG_ERR_EOF);
}
}
while (!name || !*name);
err = getkey_byname (NULL, NULL, name, 1, &c->keyblock);
if (err)
{
/* getkey_byname might return a keyblock even in the
error case - I have not checked. Thus better release
it. */
release_kbnode (c->keyblock);
c->keyblock = NULL;
}
else
c->node = c->keyblock;
}
/* Get the next key from the current keyblock. */
for (; c->node; c->node = c->node->next) for (; c->node; c->node = c->node->next)
{ {
if ((c->node->pkt->pkttype == PKT_SECRET_KEY if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
|| (with_subkeys || c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
&& c->node->pkt->pkttype == PKT_SECRET_SUBKEY))
&& !(c->node->pkt->pkt.secret_key->protect.s2k.mode == 1001
&& !with_spm))
{ {
copy_secret_key (sk, c->node->pkt->pkt.secret_key); copy_public_key (sk, c->node->pkt->pkt.public_key);
c->node = c->node->next; c->node = c->node->next;
return 0; /* Found. */ return 0; /* Found. */
} }
} }
/* Dispose the keyblock and continue. */
release_kbnode (c->keyblock); release_kbnode (c->keyblock);
c->keyblock = c->node = NULL; c->keyblock = NULL;
rc = c->first ? keydb_search_first (c->hd) : keydb_search_next (c->hd);
c->first = 0;
if (rc)
{
keydb_release (c->hd);
c->hd = NULL;
c->eof = 1;
return -1; /* eof */
}
rc = keydb_get_keyblock (c->hd, &c->keyblock);
c->node = c->keyblock;
} }
while (!rc);
return rc; /* Error. */
#endif
} }
/********************************************* /*********************************************
*********** User ID printing helpers ******* *********** User ID printing helpers *******
*********************************************/ *********************************************/

View File

@ -177,6 +177,7 @@ enum cmd_and_opt_values
oDefRecipient, oDefRecipient,
oDefRecipientSelf, oDefRecipientSelf,
oNoDefRecipient, oNoDefRecipient,
oTrySecretKey,
oOptions, oOptions,
oDebug, oDebug,
oDebugLevel, oDebugLevel,
@ -460,6 +461,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oLocalUser, "local-user", ARGPARSE_s_s (oLocalUser, "local-user",
N_("|USER-ID|use USER-ID to sign or decrypt")), N_("|USER-ID|use USER-ID to sign or decrypt")),
ARGPARSE_s_s (oTrySecretKey, "try-secret-key", "@"),
ARGPARSE_s_i (oCompress, NULL, ARGPARSE_s_i (oCompress, NULL,
N_("|N|set compress level to N (0 disables)")), N_("|N|set compress level to N (0 disables)")),
ARGPARSE_s_i (oCompressLevel, "compress-level", "@"), ARGPARSE_s_i (oCompressLevel, "compress-level", "@"),
@ -1622,6 +1625,7 @@ gpgconf_list (const char *configfile)
es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("default-key:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("default-key:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("try-secret-key:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("auto-key-locate:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("auto-key-locate:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT); es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
@ -2526,6 +2530,12 @@ main (int argc, char **argv)
sl->flags = 2; sl->flags = 2;
any_explicit_recipient = 1; any_explicit_recipient = 1;
break; break;
case oTrySecretKey:
add_to_strlist2 (&opt.secret_keys_to_try,
pargs.r.ret_str, utf8_strings);
break;
case oTextmodeShort: opt.textmode = 2; break; case oTextmodeShort: opt.textmode = 2; break;
case oTextmode: opt.textmode=1; break; case oTextmode: opt.textmode=1; break;
case oNoTextmode: opt.textmode=0; break; case oNoTextmode: opt.textmode=0; break;

View File

@ -546,3 +546,21 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
(void)pk; (void)pk;
return gpg_error (GPG_ERR_NO_SECKEY); return gpg_error (GPG_ERR_NO_SECKEY);
} }
gpg_error_t
agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
{
(void)ctrl;
(void)keyblock;
return gpg_error (GPG_ERR_NO_SECKEY);
}
gpg_error_t
agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
{
(void)ctrl;
(void)hexkeygrip;
*r_serialno = NULL;
return gpg_error (GPG_ERR_NO_SECKEY);
}

View File

@ -362,7 +362,7 @@ import_print_stats (void *hd)
* Read the next keyblock from stream A. * Read the next keyblock from stream A.
* PENDING_PKT should be initialzed to NULL * PENDING_PKT should be initialzed to NULL
* and not chnaged form the caller. * and not chnaged form the caller.
* Retunr: 0 = okay, -1 no more blocks or another errorcode. * Return: 0 = okay, -1 no more blocks or another errorcode.
*/ */
static int static int
read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ) read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
@ -1142,8 +1142,15 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
stats->count++; stats->count++;
stats->secret_read++; stats->secret_read++;
/* For now we ignore the stub keys becuase we don't have real /* We ignore stub keys. The way we handle them in other parts
support for them in gpg-agent. */ of the code is by asking the agent whether any secret key is
available for a given keyblock and then concluding that we
have a secret key; all secret (sub)keys of the keyblock the
agent does not know of are then stub keys. This works also
for card stub keys. The learn command or the card-status
command may be used to check with the agent whether a card
has been inserted and a stub key is in turn generated by the
agent. */
if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002) if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
continue; continue;
@ -1288,7 +1295,8 @@ transfer_secret_keys (ctrl_t ctrl, struct stats_s *stats, kbnode_t sec_keyblock)
write_status (STATUS_RSA_OR_IDEA); write_status (STATUS_RSA_OR_IDEA);
idea_cipher_warn (0); idea_cipher_warn (0);
} }
if (gpg_err_code (err) == GPG_ERR_CANCELED) if (gpg_err_code (err) == GPG_ERR_CANCELED
|| gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
break; /* Don't try the other subkeys. */ break; /* Don't try the other subkeys. */
} }
} }

View File

@ -241,11 +241,8 @@ gpg_error_t getkey_next (getkey_ctx_t ctx, PKT_public_key *pk,
kbnode_t *ret_keyblock); kbnode_t *ret_keyblock);
void getkey_end (getkey_ctx_t ctx); void getkey_end (getkey_ctx_t ctx);
int have_any_secret_key (ctrl_t ctrl, kbnode_t keyblock); gpg_error_t enum_secret_keys (void **context, PKT_public_key *pk);
//int enum_secret_keys( void **context, PKT_secret_key *sk,
// int with_subkeys, int with_spm );
void merge_keys_and_selfsig( KBNODE keyblock ); void merge_keys_and_selfsig( KBNODE keyblock );
char*get_user_id_string( u32 *keyid ); char*get_user_id_string( u32 *keyid );
char*get_user_id_string_native( u32 *keyid ); char*get_user_id_string_native( u32 *keyid );

View File

@ -1638,7 +1638,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
/* See whether we have a matching secret key. */ /* See whether we have a matching secret key. */
if (seckey_check) if (seckey_check)
{ {
have_seckey = have_any_secret_key (ctrl, keyblock); have_seckey = !agent_probe_any_secret_key (ctrl, keyblock);
if (have_seckey && !quiet) if (have_seckey && !quiet)
tty_printf (_("Secret key is available.\n")); tty_printf (_("Secret key is available.\n"));
} }

View File

@ -3441,6 +3441,8 @@ generate_subkeypair (KBNODE keyblock)
u32 expire; u32 expire;
unsigned int nbits; unsigned int nbits;
u32 cur_time; u32 cur_time;
char *hexgrip = NULL;
char *serialno = NULL;
/* Break out the primary key. */ /* Break out the primary key. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY); node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@ -3476,37 +3478,16 @@ generate_subkeypair (KBNODE keyblock)
goto leave; goto leave;
} }
#warning ask gpg-agent on the availibility of the secret key err = hexkeygrip_from_pk (pri_psk, &hexgrip);
/* if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001) */ if (err)
/* { */ goto leave;
/* tty_printf (_("Secret parts of primary key are not available.\n")); */ if (agent_get_keyinfo (NULL, hexgrip, &serialno))
/* err = G10ERR_NO_SECKEY; */ {
/* goto leave; */ tty_printf (_("Secret parts of primary key are not available.\n"));
/* } */ goto leave;
}
if (serialno)
/* /\* Unprotect to get the passphrase. *\/ */ tty_printf (_("Secret parts of primary key are stored on-card.\n"));
/* switch (is_secret_key_protected (pri_sk) ) */
/* { */
/* case -1: */
/* err = G10ERR_PUBKEY_ALGO; */
/* break; */
/* case 0: */
/* tty_printf (_("This key is not protected.\n")); */
/* break; */
/* case -2: */
/* tty_printf (_("Secret parts of primary key are stored on-card.\n")); */
/* ask_pass = 1; */
/* break; */
/* default: */
/* tty_printf (_("Key is protected.\n")); */
/* err = check_secret_key ( pri_sk, 0 ); */
/* if (!err) */
/* passphrase = get_last_passphrase(); */
/* break; */
/* } */
/* if (err) */
/* goto leave; */
algo = ask_algo (1, NULL, &use); algo = ask_algo (1, NULL, &use);
assert (algo); assert (algo);
@ -3536,6 +3517,8 @@ generate_subkeypair (KBNODE keyblock)
write_status_text (STATUS_KEY_CREATED, "S"); write_status_text (STATUS_KEY_CREATED, "S");
leave: leave:
xfree (hexgrip);
xfree (serialno);
if (err) if (err)
log_error (_("Key generation failed: %s\n"), g10_errstr (err) ); log_error (_("Key generation failed: %s\n"), g10_errstr (err) );
return err; return err;

View File

@ -40,11 +40,12 @@
#include "main.h" #include "main.h"
#include "i18n.h" #include "i18n.h"
#include "status.h" #include "status.h"
#include "call-agent.h"
static void list_all (int); static void list_all (int);
static void list_one (strlist_t names, int secret); static void list_one (strlist_t names, int secret);
static void locate_one (ctrl_t ctrl, strlist_t names); static void locate_one (ctrl_t ctrl, strlist_t names);
static void print_card_serialno (PKT_public_key *sk); static void print_card_serialno (const char *serialno);
struct sig_stats struct sig_stats
{ {
@ -175,6 +176,7 @@ print_pubkey_info (estream_t fp, PKT_public_key * pk)
/* Print basic information of a secret key including the card serial /* Print basic information of a secret key including the card serial
number information. */ number information. */
#ifdef ENABLE_CARD_SUPPORT
void void
print_card_key_info (estream_t fp, kbnode_t keyblock) print_card_key_info (estream_t fp, kbnode_t keyblock)
{ {
@ -224,7 +226,7 @@ print_card_key_info (estream_t fp, kbnode_t keyblock)
/* } */ /* } */
/* } */ /* } */
} }
#endif /*ENABLE_CARD_SUPPORT*/
/* Flags = 0x01 hashed 0x02 critical. */ /* Flags = 0x01 hashed 0x02 critical. */
@ -444,7 +446,7 @@ list_all (int secret)
log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc)); log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc));
goto leave; goto leave;
} }
if (secret && !have_any_secret_key (NULL, keyblock)) if (secret && agent_probe_any_secret_key (NULL, keyblock))
; /* Secret key listing requested but this isn't one. */ ; /* Secret key listing requested but this isn't one. */
else else
{ {
@ -757,13 +759,15 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
static void static void
list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque) list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
{ {
int rc = 0; int rc;
KBNODE kbctx; KBNODE kbctx;
KBNODE node; KBNODE node;
PKT_public_key *pk; PKT_public_key *pk;
struct sig_stats *stats = opaque; struct sig_stats *stats = opaque;
int skip_sigs = 0; int skip_sigs = 0;
int s2k_char; int s2k_char;
char *hexgrip = NULL;
char *serialno = NULL;
/* Get the keyid from the keyblock. */ /* Get the keyid from the keyblock. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY); node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@ -775,10 +779,23 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
} }
pk = node->pkt->pkt.public_key; pk = node->pkt->pkt.public_key;
/* Fixme: Get s2k mode from the agent. */ if (secret || opt.with_keygrip)
s2k_char = (/*(sk->protect.s2k.mode == 1001)? '#' : {
(sk->protect.s2k.mode == 1002)? '>' : */' '); rc = hexkeygrip_from_pk (pk, &hexgrip);
if (rc)
log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
}
if (secret)
{
if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
s2k_char = serialno? '>':' ';
else
s2k_char = '#'; /* Key not found. */
}
else
s2k_char = ' ';
check_trustdb_stale (); check_trustdb_stale ();
@ -822,19 +839,11 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
if (fpr) if (fpr)
print_fingerprint (pk, 0); print_fingerprint (pk, 0);
if (opt.with_keygrip) if (opt.with_keygrip && hexgrip)
{ es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
char *p;
if (!hexkeygrip_from_pk (pk, &p)) if (serialno)
{ print_card_serialno (serialno);
es_fprintf (es_stdout, " Keygrip = %s\n", p);
xfree (p);
}
}
/* FIXME: Change this function to take a PK and ask the agent: */
/* if (secret) print_card_serialno (sk); */
if (opt.with_key_data) if (opt.with_key_data)
print_key_data (pk); print_key_data (pk);
@ -895,10 +904,25 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
else else
skip_sigs = 0; skip_sigs = 0;
/* Fixme: Get s2k mode from the agent. */ xfree (serialno); serialno = NULL;
s2k_char = (/*(sk->protect.s2k.mode == 1001)? '#' : xfree (hexgrip); hexgrip = NULL;
(sk->protect.s2k.mode == 1002)? '>' : */' '); if (secret || opt.with_keygrip)
{
rc = hexkeygrip_from_pk (pk2, &hexgrip);
if (rc)
log_error ("error computing a keygrip: %s\n",
gpg_strerror (rc));
}
if (secret)
{
if (!agent_get_keyinfo (NULL, hexgrip, &serialno))
s2k_char = serialno? '>':' ';
else
s2k_char = '#'; /* Key not found. */
}
else
s2k_char = ' ';
es_fprintf (es_stdout, "%s%c %4u%c/%s %s", es_fprintf (es_stdout, "%s%c %4u%c/%s %s",
secret? "ssb":"sub", secret? "ssb":"sub",
s2k_char, s2k_char,
@ -926,20 +950,11 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
if (fpr > 1) if (fpr > 1)
{ {
print_fingerprint (pk2, 0); print_fingerprint (pk2, 0);
/* FIXME: (see above) */ if (serialno)
/* if (secret) */ print_card_serialno (serialno);
/* print_card_serialno (sk2); */
}
if (opt.with_keygrip)
{
char *p;
if (!hexkeygrip_from_pk (pk2, &p))
{
es_fprintf (es_stdout, " Keygrip = %s\n", p);
xfree (p);
}
} }
if (opt.with_keygrip && hexgrip)
es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
if (opt.with_key_data) if (opt.with_key_data)
print_key_data (pk2); print_key_data (pk2);
} }
@ -1050,6 +1065,8 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
} }
} }
es_putc ('\n', es_stdout); es_putc ('\n', es_stdout);
xfree (serialno);
xfree (hexgrip);
} }
void void
@ -1079,7 +1096,7 @@ print_revokers (PKT_public_key * pk)
static void static void
list_keyblock_colon (KBNODE keyblock, int secret, int fpr) list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
{ {
int rc = 0; int rc;
KBNODE kbctx; KBNODE kbctx;
KBNODE node; KBNODE node;
PKT_public_key *pk; PKT_public_key *pk;
@ -1088,6 +1105,9 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
int ulti_hack = 0; int ulti_hack = 0;
int i; int i;
char *p; char *p;
char *hexgrip = NULL;
char *serialno = NULL;
int stubkey;
/* Get the keyid from the keyblock. */ /* Get the keyid from the keyblock. */
node = find_kbnode (keyblock, PKT_PUBLIC_KEY); node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
@ -1099,6 +1119,15 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
} }
pk = node->pkt->pkt.public_key; pk = node->pkt->pkt.public_key;
if (secret || opt.with_keygrip || opt.with_key_data)
{
rc = hexkeygrip_from_pk (pk, &hexgrip);
if (rc)
log_error ("error computing a keygrip: %s\n", gpg_strerror (rc));
}
stubkey = 0;
if (secret && agent_get_keyinfo (NULL, hexgrip, &serialno))
stubkey = 1; /* Key not found. */
keyid_from_pk (pk, keyid); keyid_from_pk (pk, keyid);
es_fputs (secret? "sec:":"pub:", es_stdout); es_fputs (secret? "sec:":"pub:", es_stdout);
@ -1135,16 +1164,10 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
{ {
es_putc (':', es_stdout); /* End of field 13. */ es_putc (':', es_stdout); /* End of field 13. */
es_putc (':', es_stdout); /* End of field 14. */ es_putc (':', es_stdout); /* End of field 14. */
if (/*FIXME sk->protect.s2k.mode*/1 == 1001) if (stubkey)
es_putc ('#', es_stdout); /* Key is just a stub. */ es_putc ('#', es_stdout);
else if (/*FIXME sk->protect.s2k.mode*/1 == 1002) else if (serialno)
{ es_fputs(serialno, es_stdout);
/* Key is stored on an external token (card) or handled by
the gpg-agent. Print the serial number of that token
here. */
/* FIXME: for (i = 0; i < sk->protect.ivlen; i++) */
/* es_fprintf (es_stdout, "%02X", sk->protect.iv[i]); */
}
es_putc (':', es_stdout); /* End of field 15. */ es_putc (':', es_stdout); /* End of field 15. */
} }
es_putc ('\n', es_stdout); es_putc ('\n', es_stdout);
@ -1154,11 +1177,8 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
print_fingerprint (pk, 0); print_fingerprint (pk, 0);
if (opt.with_key_data || opt.with_keygrip) if (opt.with_key_data || opt.with_keygrip)
{ {
if (!hexkeygrip_from_pk (pk, &p)) if (hexgrip)
{ es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
es_fprintf (es_stdout, "grp:::::::::%s:\n", p);
xfree (p);
}
if (opt.with_key_data) if (opt.with_key_data)
print_key_data (pk); print_key_data (pk);
} }
@ -1213,7 +1233,21 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{ {
u32 keyid2[2]; u32 keyid2[2];
PKT_public_key *pk2 = node->pkt->pkt.public_key; PKT_public_key *pk2;
pk2 = node->pkt->pkt.public_key;
xfree (hexgrip); hexgrip = NULL;
xfree (serialno); serialno = NULL;
if (secret || opt.with_keygrip || opt.with_key_data)
{
rc = hexkeygrip_from_pk (pk2, &hexgrip);
if (rc)
log_error ("error computing a keygrip: %s\n",
gpg_strerror (rc));
}
stubkey = 0;
if (secret && agent_get_keyinfo (NULL, hexgrip, &serialno))
stubkey = 1; /* Key not found. */
keyid_from_pk (pk2, keyid2); keyid_from_pk (pk2, keyid2);
es_fputs (secret? "ssb:":"sub:", es_stdout); es_fputs (secret? "ssb:":"sub:", es_stdout);
@ -1243,16 +1277,10 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
{ {
es_putc (':', es_stdout); /* End of field 13. */ es_putc (':', es_stdout); /* End of field 13. */
es_putc (':', es_stdout); /* End of field 14. */ es_putc (':', es_stdout); /* End of field 14. */
if (/*FIXME:sk2->protect.s2k.mode*/1 == 1001) if (stubkey)
es_putc ('#', es_stdout); /* Key is just a stub. */ es_putc ('#', es_stdout);
else if (/*FIXME: sk2->protect.s2k.mode*/1 == 1002) else if (serialno)
{ es_fputs (serialno, es_stdout);
/* Key is stored on an external token (card) or
handled by the gpg-agent. Print the serial
number of that token here. */
/* FIXME: for (i = 0; i < sk2->protect.ivlen; i++)
es_fprintf (es_stdout, "%02X", sk2->protect.iv[i]); */
}
es_putc (':', es_stdout); /* End of field 15. */ es_putc (':', es_stdout); /* End of field 15. */
} }
es_putc ('\n', es_stdout); es_putc ('\n', es_stdout);
@ -1260,11 +1288,8 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
print_fingerprint (pk2, 0); print_fingerprint (pk2, 0);
if (opt.with_key_data || opt.with_keygrip) if (opt.with_key_data || opt.with_keygrip)
{ {
if (!hexkeygrip_from_pk (pk2, &p)) if (hexgrip)
{ es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
es_fprintf (es_stdout, "grp:::::::::%s:\n", p);
xfree (p);
}
if (opt.with_key_data) if (opt.with_key_data)
print_key_data (pk2); print_key_data (pk2);
} }
@ -1385,6 +1410,9 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
/* fixme: check or list other sigs here */ /* fixme: check or list other sigs here */
} }
} }
xfree (hexgrip);
xfree (serialno);
} }
/* /*
@ -1550,38 +1578,25 @@ print_fingerprint (PKT_public_key *pk, int mode)
/* Print the serial number of an OpenPGP card if available. */ /* Print the serial number of an OpenPGP card if available. */
static void static void
print_card_serialno (PKT_public_key *pk) print_card_serialno (const char *serialno)
{ {
log_debug ("Fixme: Needs to be adjusted to gpg-agent\n"); if (!serialno)
/* int i; */ return;
if (opt.with_colons)
return; /* Handled elsewhere. */
/* if (!sk) */ es_fputs (_(" Card serial no. ="), es_stdout);
/* return; */ es_putc (' ', es_stdout);
/* if (!sk->is_protected || sk->protect.s2k.mode != 1002) */ if (strlen (serialno) == 32 && !strncmp (serialno, "D27600012401", 12))
/* return; /\* Not a card. *\/ */ {
/* if (opt.with_colons) */ /* This is an OpenPGP card. Print the relevant part. */
/* return; /\* Handled elsewhere. *\/ */ /* Example: D2760001240101010001000003470000 */
/* xxxxyyyyyyyy */
/* es_fputs (_(" Card serial no. ="), es_stdout); */ es_fprintf (es_stdout, "%.*s %.*s", 4, serialno+16, 8, serialno+20);
/* es_putc (' ', es_stdout); */ }
/* if (sk->protect.ivlen == 16 */ else
/* && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6)) */ es_fputs (serialno, es_stdout);
/* { */ es_putc ('\n', es_stdout);
/* /\* This is an OpenPGP card. Just print the relevant part. *\/ */
/* for (i = 8; i < 14; i++) */
/* { */
/* if (i == 10) */
/* es_putc (' ', es_stdout); */
/* es_fprintf (es_stdout, "%02X", sk->protect.iv[i]); */
/* } */
/* } */
/* else */
/* { */
/* /\* Something is wrong: Print all. *\/ */
/* for (i = 0; i < sk->protect.ivlen; i++) */
/* es_fprintf (es_stdout, "%02X", sk->protect.iv[i]); */
/* } */
/* es_putc ('\n', es_stdout); */
} }

View File

@ -555,11 +555,10 @@ get_signature_count (PKT_public_key *pk)
/* if(agent_scd_getattr("SIG-COUNTER",&info)==0) */ /* if(agent_scd_getattr("SIG-COUNTER",&info)==0) */
/* return info.sig_counter; */ /* return info.sig_counter; */
/* } */ /* } */
#endif #else
(void)pk;
/* How to do this without a card? */
return 0; return 0;
#endif
} }
/* Expand %-strings. Returns a string which must be xfreed. Returns /* Expand %-strings. Returns a string which must be xfreed. Returns

View File

@ -79,6 +79,8 @@ struct
const char *def_secret_key; const char *def_secret_key;
char *def_recipient; char *def_recipient;
int def_recipient_self; int def_recipient_self;
strlist_t secret_keys_to_try;
int def_cert_level; int def_cert_level;
int min_cert_level; int min_cert_level;
int ask_cert_level; int ask_cert_level;

View File

@ -211,17 +211,6 @@ get_last_passphrase()
return p; return p;
} }
/* As if we had used the passphrase - make it the last_pw. */
void
next_to_last_passphrase(void)
{
if (next_pw)
{
last_pw=next_pw;
next_pw=NULL;
}
}
/* Here's an interesting question: since this passphrase was passed in /* Here's an interesting question: since this passphrase was passed in
on the command line, is there really any point in using secure on the command line, is there really any point in using secure
memory for it? I'm going with 'yes', since it doesn't hurt, and memory for it? I'm going with 'yes', since it doesn't hurt, and
@ -407,7 +396,8 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
if (!rc) if (!rc)
; ;
else if ( gpg_err_code (rc) == GPG_ERR_CANCELED ) else if (gpg_err_code (rc) == GPG_ERR_CANCELED
|| gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
{ {
log_info (_("cancelled by user\n") ); log_info (_("cancelled by user\n") );
if (canceled) if (canceled)

View File

@ -94,14 +94,13 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
{ {
void *enum_context = NULL; void *enum_context = NULL;
u32 keyid[2]; u32 keyid[2];
char *p;
for (;;) for (;;)
{ {
if (sk) if (sk)
free_public_key (sk); free_public_key (sk);
sk = xmalloc_clear (sizeof *sk); sk = xmalloc_clear (sizeof *sk);
rc = -1; /* FIXME:enum_secret_keys (&enum_context, sk, 1, 0);*/ rc = enum_secret_keys (&enum_context, sk);
if (rc) if (rc)
{ {
rc = G10ERR_NO_SECKEY; rc = G10ERR_NO_SECKEY;
@ -109,42 +108,22 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
} }
if (sk->pubkey_algo != k->pubkey_algo) if (sk->pubkey_algo != k->pubkey_algo)
continue; continue;
if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
continue;
keyid_from_pk (sk, keyid); keyid_from_pk (sk, keyid);
log_info (_("anonymous recipient; trying secret key %s ...\n"), log_info (_("anonymous recipient; trying secret key %s ...\n"),
keystr (keyid)); keystr (keyid));
if (!opt.try_all_secrets && !is_status_enabled ()) rc = get_it (k, dek, sk, keyid);
{
p = get_last_passphrase ();
set_next_passphrase (p);
xfree (p);
}
/* rc = check_secret_key( sk, opt.try_all_secrets?1:-1 ); /\* ask */
/* only */
/* once *\/ */
/* if( !rc ) */
{
rc = get_it (k, dek, sk, keyid);
/* Successfully checked the secret key (either it was a
card, had no passphrase, or had the right passphrase)
but couldn't decrypt the session key, so thus that key
is not the anonymous recipient. Move the next
passphrase into last for the next round. We only do
this if the secret key was successfully checked as in
the normal case, check_secret_key handles this for us
via passphrase_to_dek. */
if (rc)
next_to_last_passphrase ();
}
if (!rc) if (!rc)
{ {
log_info (_("okay, we are the anonymous recipient.\n")); log_info (_("okay, we are the anonymous recipient.\n"));
break; break;
} }
else if (gpg_err_code (rc) == GPG_ERR_FULLY_CANCELED)
break; /* Don't try any more secret keys. */
} }
enum_secret_keys (&enum_context, NULL, 0, 0); /* free context */ enum_secret_keys (&enum_context, NULL); /* free context */
} }
leave: leave: