mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
More agent support for gpg.
This commit is contained in:
parent
5a679857ef
commit
54591341a4
5
NEWS
5
NEWS
@ -43,10 +43,13 @@ Noteworthy changes in version 2.1.x (under development)
|
||||
|
||||
* The OpenPGP import command is now able to merge secret keys.
|
||||
|
||||
* Removed options:
|
||||
* Removed GPG options:
|
||||
--export-options: export-secret-subkey-passwd
|
||||
--simple-sk-checksum
|
||||
|
||||
* New GPG options:
|
||||
--try-secret-key
|
||||
|
||||
|
||||
Noteworthy changes in version 2.0.13 (2009-09-04)
|
||||
-------------------------------------------------
|
||||
|
@ -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>
|
||||
|
||||
* cvt-openpgp.c (convert_secret_key): Add missing break.
|
||||
|
@ -253,7 +253,7 @@ int pinentry_active_p (ctrl_t ctrl, int waitseconds);
|
||||
int agent_askpin (ctrl_t ctrl,
|
||||
const char *desc_text, const char *prompt_text,
|
||||
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,
|
||||
const char *desc, const char *prompt,
|
||||
const char *errtext, int with_qualitybar);
|
||||
@ -291,7 +291,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
/*-- genkey.c --*/
|
||||
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,
|
||||
char **r_passphrase, int *r_cancelall);
|
||||
char **r_passphrase);
|
||||
int agent_genkey (ctrl_t ctrl, const char *cache_nonce,
|
||||
const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
|
||||
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
|
||||
|
@ -467,8 +467,10 @@ start_pinentry (ctrl_t ctrl)
|
||||
else
|
||||
{
|
||||
rc = agent_inq_pinentry_launched (ctrl, pinentry_pid);
|
||||
if (gpg_err_code (rc) == GPG_ERR_CANCELED)
|
||||
return unlock_pinentry (gpg_error (GPG_ERR_CANCELED));
|
||||
if (gpg_err_code (rc) == 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;
|
||||
}
|
||||
|
||||
@ -727,7 +729,7 @@ int
|
||||
agent_askpin (ctrl_t ctrl,
|
||||
const char *desc_text, const char *prompt_text,
|
||||
const char *initial_errtext,
|
||||
struct pin_entry_info_s *pininfo, int *r_cancel_all)
|
||||
struct pin_entry_info_s *pininfo)
|
||||
{
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
@ -737,9 +739,6 @@ agent_askpin (ctrl_t ctrl,
|
||||
int saveflag;
|
||||
int close_button;
|
||||
|
||||
if (r_cancel_all)
|
||||
*r_cancel_all = 0;
|
||||
|
||||
if (opt.batch)
|
||||
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)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_CANCELED);
|
||||
|
||||
/* Set a flag in case the window close button was clicked to
|
||||
cancel the operation. */
|
||||
if (close_button && r_cancel_all && gpg_err_code (rc) == GPG_ERR_CANCELED)
|
||||
*r_cancel_all = 1;
|
||||
/* 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 (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
|
||||
errtext = is_pin? _("PIN too long")
|
||||
@ -890,6 +889,7 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct entry_parm_s parm;
|
||||
int saveflag;
|
||||
int close_button;
|
||||
|
||||
*retpass = NULL;
|
||||
if (opt.batch)
|
||||
@ -942,14 +942,21 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||
|
||||
saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
||||
assuan_begin_confidential (entry_ctx);
|
||||
close_button = 0;
|
||||
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);
|
||||
/* Most pinentries out in the wild return the old Assuan error code
|
||||
for canceled which gets translated to an assuan Cancel error and
|
||||
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)
|
||||
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)
|
||||
xfree (parm.buffer);
|
||||
else
|
||||
|
@ -2425,7 +2425,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
|
||||
pi2->check_cb_arg = pi->pin;
|
||||
|
||||
next_try:
|
||||
err = agent_askpin (ctrl, description, NULL, initial_errtext, pi, NULL);
|
||||
err = agent_askpin (ctrl, description, NULL, initial_errtext, pi);
|
||||
initial_errtext = NULL;
|
||||
if (err)
|
||||
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. */
|
||||
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)
|
||||
{ /* The re-entered one did not match and the user did not
|
||||
hit cancel. */
|
||||
|
@ -71,6 +71,7 @@ struct server_local_s
|
||||
be done. */
|
||||
void *import_key; /* Malloced KEK for the import_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)
|
||||
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
|
||||
we fix this here. */
|
||||
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,
|
||||
&s_skey, NULL);
|
||||
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)
|
||||
{
|
||||
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
|
||||
(ctrl, _("Please enter the passphrase to protect the "
|
||||
"imported object within the GnuPG system."),
|
||||
&passphrase, NULL);
|
||||
&passphrase);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
@ -1751,18 +1757,13 @@ cmd_export_key (assuan_context_t ctx, char *line)
|
||||
canonical S-expression. */
|
||||
if (!passphrase)
|
||||
{
|
||||
int fully_canceled;
|
||||
err = agent_ask_new_passphrase
|
||||
(ctrl, _("This key (or subkey) is not protected with a passphrase."
|
||||
" Please enter a new passphrase to export it."),
|
||||
&passphrase, &fully_canceled);
|
||||
&passphrase);
|
||||
if (err)
|
||||
{
|
||||
if (fully_canceled)
|
||||
err = gpg_error (GPG_ERR_FULLY_CANCELED);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
err = convert_to_openpgp (ctrl, s_skey, passphrase, &key, &keylen);
|
||||
}
|
||||
else
|
||||
@ -1814,10 +1815,6 @@ cmd_export_key (assuan_context_t ctx, char *line)
|
||||
xfree (ctrl->server_local->keydesc);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2185,7 +2182,14 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
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
|
||||
Pinentry. Valid values are:
|
||||
|
@ -780,7 +780,7 @@ convert_from_openpgp (ctrl_t ctrl, gcry_sexp_t s_pgp,
|
||||
err = try_do_unprotect_cb (pi);
|
||||
}
|
||||
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;
|
||||
if (!err)
|
||||
{
|
||||
|
@ -266,7 +266,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
|
||||
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;
|
||||
if (!rc && newpin)
|
||||
{
|
||||
@ -288,7 +288,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
is_puk?
|
||||
_("Repeat this PUK"):
|
||||
_("Repeat this PIN")),
|
||||
prompt, NULL, pi2, NULL);
|
||||
prompt, NULL, pi2);
|
||||
if (!rc && strcmp (pi->pin, pi2->pin))
|
||||
{
|
||||
again_text = (resetcode?
|
||||
@ -312,7 +312,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
|
||||
info? info:"",
|
||||
info? "')":"") < 0)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,8 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
|
||||
_("I'll change it later"), 0);
|
||||
if (!err)
|
||||
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;
|
||||
}
|
||||
xfree (desc);
|
||||
@ -290,7 +291,6 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
|
||||
unsigned char *result;
|
||||
size_t resultlen;
|
||||
char hexgrip[40+1];
|
||||
int fully_canceled;
|
||||
|
||||
if (r_passphrase)
|
||||
*r_passphrase = NULL;
|
||||
@ -383,9 +383,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
|
||||
arg.change_required = 0;
|
||||
pi->check_cb_arg = &arg;
|
||||
|
||||
rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi, &fully_canceled);
|
||||
if (gpg_err_code (rc) == GPG_ERR_CANCELED && fully_canceled)
|
||||
rc = gpg_err_make (gpg_err_source (rc), GPG_ERR_FULLY_CANCELED);
|
||||
rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
|
||||
if (!rc)
|
||||
{
|
||||
assert (arg.unprotected_key);
|
||||
|
@ -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
|
||||
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
|
||||
error code is returned and NULL stored at R_PASSPHRASE. If
|
||||
R_CANCEL_ALL is not NULL and the user canceled by directly closing
|
||||
the window true will be stored at this address. */
|
||||
error code is returned and NULL stored at R_PASSPHRASE. */
|
||||
gpg_error_t
|
||||
agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
||||
char **r_passphrase, int *r_cancel_all)
|
||||
char **r_passphrase)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const char *text1 = prompt;
|
||||
@ -316,7 +314,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
||||
pi2->check_cb_arg = pi->pin;
|
||||
|
||||
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;
|
||||
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. */
|
||||
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)
|
||||
{ /* The re-entered one did not match and the user did not
|
||||
hit cancel. */
|
||||
@ -381,7 +379,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
|
||||
rc = agent_ask_new_passphrase (ctrl,
|
||||
_("Please enter the passphrase to%0A"
|
||||
"to protect your new key"),
|
||||
&passphrase, NULL);
|
||||
&passphrase);
|
||||
if (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,
|
||||
_("Please enter the new passphrase"),
|
||||
&passphrase, NULL);
|
||||
&passphrase);
|
||||
if (!rc)
|
||||
{
|
||||
rc = store_key (s_skey, passphrase, 1);
|
||||
|
@ -1523,6 +1523,8 @@ create_server_socket (char *name, int is_ssh, assuan_sock_nonce_t *nonce)
|
||||
a hang. */
|
||||
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 - "
|
||||
"not starting a new one\n"));
|
||||
*name = 0; /* Inhibit removal of the socket by cleanup(). */
|
||||
|
@ -67,8 +67,6 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
rc = agent_key_from_file (ctrl, NULL, desc_text,
|
||||
ctrl->keygrip, &shadow_info,
|
||||
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 (gpg_err_code (rc) == GPG_ERR_ENOENT)
|
||||
|
@ -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,
|
||||
&shadow_info, cache_mode, lookup_ttl,
|
||||
&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)
|
||||
{
|
||||
log_error ("failed to read the secret key\n");
|
||||
|
@ -704,7 +704,8 @@ get_passphrase (int promptno)
|
||||
repeat, repeat, 1, &pw);
|
||||
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"));
|
||||
else
|
||||
log_error (_("error while asking for the passphrase: %s\n"),
|
||||
|
@ -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>
|
||||
|
||||
* gettime.c (asctimestamp) [W32CE]: Do not print the timezone.
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -267,6 +267,8 @@ int is_file_compressed (const char *s, int *ret_rc);
|
||||
|
||||
int match_multistr (const char *multistr,const char *match);
|
||||
|
||||
int gnupg_compare_version (const char *a, const char *b);
|
||||
|
||||
|
||||
/*-- Simple replacement functions. */
|
||||
#ifndef HAVE_TTYNAME
|
||||
|
18
doc/gpg.texi
18
doc/gpg.texi
@ -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
|
||||
@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
|
||||
@opindex try-all-secrets
|
||||
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
|
||||
behaviour as used by anonymous recipients (created by using
|
||||
@option{--throw-keyids}) and might come handy in case where an encrypted
|
||||
message contains a bogus key ID.
|
||||
@option{--throw-keyids} or @option{--hidden-recipient}) and might come
|
||||
handy in case where an encrypted message contains a bogus key ID.
|
||||
|
||||
@item --skip-hidden-recipients
|
||||
@itemx --no-skip-hidden-recipients
|
||||
|
@ -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>
|
||||
|
||||
* gpg.c: Add option --with-keygrip.
|
||||
|
@ -99,6 +99,7 @@ status_sc_op_failure (int rc)
|
||||
case 0:
|
||||
break;
|
||||
case GPG_ERR_CANCELED:
|
||||
case GPG_ERR_FULLY_CANCELED:
|
||||
write_status_text (STATUS_SC_OP_FAILURE, "1");
|
||||
break;
|
||||
case GPG_ERR_BAD_PIN:
|
||||
@ -142,6 +143,11 @@ start_agent (ctrl_t ctrl, int for_card)
|
||||
agents. */
|
||||
assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@ write_sc_op_status (gpg_error_t err)
|
||||
break;
|
||||
#if GNUPG_MAJOR_VERSION != 1
|
||||
case GPG_ERR_CANCELED:
|
||||
case GPG_ERR_FULLY_CANCELED:
|
||||
write_status_text (STATUS_SC_OP_FAILURE, "1");
|
||||
break;
|
||||
case GPG_ERR_BAD_PIN:
|
||||
|
152
g10/getkey.c
152
g10/getkey.c
@ -568,8 +568,9 @@ leave:
|
||||
* 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
|
||||
* 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
|
||||
* NULL the function will return the keyblock there. */
|
||||
* The caller should provide storage for the PK or pass NULL if it is
|
||||
* not needed. If RET_KB is not NULL the function stores the entire
|
||||
* keyblock at that address. */
|
||||
static int
|
||||
key_byname (GETKEY_CTX *retctx, strlist_t namelist,
|
||||
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
|
||||
* return the search context which needs to be released by the caller
|
||||
* using getkey_end. If NAME is NULL use the default key (see below).
|
||||
* On success and if RET_KEYBLOCK is not NULL the found keyblock is
|
||||
* stored at this address. WANT_SECRET passed as true requires that a
|
||||
* secret key is available for the selected key.
|
||||
/* Get a key by name and store it into PK if that is not NULL. If
|
||||
* RETCTX is not NULL return the search context which needs to be
|
||||
* released by the caller using getkey_end. If NAME is NULL use the
|
||||
* default key (see below). On success and if RET_KEYBLOCK is not
|
||||
* NULL the found keyblock is stored at this address. WANT_SECRET
|
||||
* 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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
/* Warning: node flag bits 0 and 1 should be preserved by
|
||||
@ -2504,57 +2506,42 @@ found:
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* FIXME: Replace by the generic function
|
||||
* 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:
|
||||
/*
|
||||
* Enumerate certain secret keys. Caller must use these procedure:
|
||||
* 1) create a void pointer and initialize it to NULL
|
||||
* 2) pass this void pointer by reference to this function
|
||||
* and provide space for the secret key (pass a buffer for sk)
|
||||
* 3) call this function as long as it does not return -1
|
||||
* to indicate EOF.
|
||||
* 3) call this function as long as it does not return an error.
|
||||
* 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,
|
||||
* so that can free it's context.
|
||||
*/
|
||||
int
|
||||
enum_secret_keys (void **context, PKT_public_key * sk,
|
||||
int with_subkeys, int with_spm)
|
||||
gpg_error_t
|
||||
enum_secret_keys (void **context, PKT_public_key *sk)
|
||||
{
|
||||
log_debug ("FIXME: Anonymous recipient does not yet work\n");
|
||||
return -1;
|
||||
#if 0
|
||||
|
||||
int rc = 0;
|
||||
gpg_error_t err = 0;
|
||||
const char *name;
|
||||
struct
|
||||
{
|
||||
int eof;
|
||||
int first;
|
||||
KEYDB_HANDLE hd;
|
||||
KBNODE keyblock;
|
||||
KBNODE node;
|
||||
int state;
|
||||
strlist_t sl;
|
||||
kbnode_t keyblock;
|
||||
kbnode_t node;
|
||||
} *c = *context;
|
||||
|
||||
|
||||
if (!c)
|
||||
{
|
||||
/* Make a new context. */
|
||||
c = xmalloc_clear (sizeof *c);
|
||||
c = xtrycalloc (1, sizeof *c);
|
||||
if (!c)
|
||||
return gpg_error_from_syserror ();
|
||||
*context = c;
|
||||
c->hd = keydb_new (1); /*FIXME*/
|
||||
c->first = 1;
|
||||
c->keyblock = NULL;
|
||||
c->node = NULL;
|
||||
}
|
||||
|
||||
if (!sk)
|
||||
{
|
||||
/* Free the context. */
|
||||
keydb_release (c->hd);
|
||||
release_kbnode (c->keyblock);
|
||||
xfree (c);
|
||||
*context = NULL;
|
||||
@ -2562,48 +2549,79 @@ enum_secret_keys (void **context, PKT_public_key * sk,
|
||||
}
|
||||
|
||||
if (c->eof)
|
||||
return -1;
|
||||
return gpg_error (GPG_ERR_EOF);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Loop until we have a keyblock. */
|
||||
while (!c->keyblock)
|
||||
{
|
||||
/* Loop over the list of secret keys. */
|
||||
do
|
||||
{
|
||||
/* Get the next secret key from the current keyblock. */
|
||||
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)
|
||||
{
|
||||
if ((c->node->pkt->pkttype == PKT_SECRET_KEY
|
||||
|| (with_subkeys
|
||||
&& c->node->pkt->pkttype == PKT_SECRET_SUBKEY))
|
||||
&& !(c->node->pkt->pkt.secret_key->protect.s2k.mode == 1001
|
||||
&& !with_spm))
|
||||
if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
||||
{
|
||||
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;
|
||||
return 0; /* Found. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Dispose the keyblock and continue. */
|
||||
release_kbnode (c->keyblock);
|
||||
c->keyblock = c->node = 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 */
|
||||
c->keyblock = NULL;
|
||||
}
|
||||
|
||||
rc = keydb_get_keyblock (c->hd, &c->keyblock);
|
||||
c->node = c->keyblock;
|
||||
}
|
||||
while (!rc);
|
||||
|
||||
return rc; /* Error. */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************
|
||||
*********** User ID printing helpers *******
|
||||
*********************************************/
|
||||
|
10
g10/gpg.c
10
g10/gpg.c
@ -177,6 +177,7 @@ enum cmd_and_opt_values
|
||||
oDefRecipient,
|
||||
oDefRecipientSelf,
|
||||
oNoDefRecipient,
|
||||
oTrySecretKey,
|
||||
oOptions,
|
||||
oDebug,
|
||||
oDebugLevel,
|
||||
@ -460,6 +461,8 @@ static ARGPARSE_OPTS opts[] = {
|
||||
ARGPARSE_s_s (oLocalUser, "local-user",
|
||||
N_("|USER-ID|use USER-ID to sign or decrypt")),
|
||||
|
||||
ARGPARSE_s_s (oTrySecretKey, "try-secret-key", "@"),
|
||||
|
||||
ARGPARSE_s_i (oCompress, NULL,
|
||||
N_("|N|set compress level to N (0 disables)")),
|
||||
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 ("default-key:%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 ("log-file:%lu:\n", GC_OPT_FLAG_NONE);
|
||||
es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT);
|
||||
@ -2526,6 +2530,12 @@ main (int argc, char **argv)
|
||||
sl->flags = 2;
|
||||
any_explicit_recipient = 1;
|
||||
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 oTextmode: opt.textmode=1; break;
|
||||
case oNoTextmode: opt.textmode=0; break;
|
||||
|
18
g10/gpgv.c
18
g10/gpgv.c
@ -546,3 +546,21 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
|
||||
(void)pk;
|
||||
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);
|
||||
}
|
||||
|
||||
|
16
g10/import.c
16
g10/import.c
@ -362,7 +362,7 @@ import_print_stats (void *hd)
|
||||
* Read the next keyblock from stream A.
|
||||
* PENDING_PKT should be initialzed to NULL
|
||||
* 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
|
||||
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->secret_read++;
|
||||
|
||||
/* For now we ignore the stub keys becuase we don't have real
|
||||
support for them in gpg-agent. */
|
||||
/* We ignore stub keys. The way we handle them in other parts
|
||||
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)
|
||||
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);
|
||||
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. */
|
||||
}
|
||||
}
|
||||
|
@ -241,11 +241,8 @@ gpg_error_t getkey_next (getkey_ctx_t ctx, PKT_public_key *pk,
|
||||
kbnode_t *ret_keyblock);
|
||||
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 );
|
||||
char*get_user_id_string( u32 *keyid );
|
||||
char*get_user_id_string_native( u32 *keyid );
|
||||
|
@ -1638,7 +1638,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
|
||||
/* See whether we have a matching secret key. */
|
||||
if (seckey_check)
|
||||
{
|
||||
have_seckey = have_any_secret_key (ctrl, keyblock);
|
||||
have_seckey = !agent_probe_any_secret_key (ctrl, keyblock);
|
||||
if (have_seckey && !quiet)
|
||||
tty_printf (_("Secret key is available.\n"));
|
||||
}
|
||||
|
45
g10/keygen.c
45
g10/keygen.c
@ -3441,6 +3441,8 @@ generate_subkeypair (KBNODE keyblock)
|
||||
u32 expire;
|
||||
unsigned int nbits;
|
||||
u32 cur_time;
|
||||
char *hexgrip = NULL;
|
||||
char *serialno = NULL;
|
||||
|
||||
/* Break out the primary key. */
|
||||
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
|
||||
@ -3476,37 +3478,16 @@ generate_subkeypair (KBNODE keyblock)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
#warning ask gpg-agent on the availibility of the secret key
|
||||
/* if (pri_sk->is_protected && pri_sk->protect.s2k.mode == 1001) */
|
||||
/* { */
|
||||
/* tty_printf (_("Secret parts of primary key are not available.\n")); */
|
||||
/* err = G10ERR_NO_SECKEY; */
|
||||
/* goto leave; */
|
||||
/* } */
|
||||
|
||||
|
||||
/* /\* Unprotect to get the passphrase. *\/ */
|
||||
/* 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; */
|
||||
err = hexkeygrip_from_pk (pri_psk, &hexgrip);
|
||||
if (err)
|
||||
goto leave;
|
||||
if (agent_get_keyinfo (NULL, hexgrip, &serialno))
|
||||
{
|
||||
tty_printf (_("Secret parts of primary key are not available.\n"));
|
||||
goto leave;
|
||||
}
|
||||
if (serialno)
|
||||
tty_printf (_("Secret parts of primary key are stored on-card.\n"));
|
||||
|
||||
algo = ask_algo (1, NULL, &use);
|
||||
assert (algo);
|
||||
@ -3536,6 +3517,8 @@ generate_subkeypair (KBNODE keyblock)
|
||||
write_status_text (STATUS_KEY_CREATED, "S");
|
||||
|
||||
leave:
|
||||
xfree (hexgrip);
|
||||
xfree (serialno);
|
||||
if (err)
|
||||
log_error (_("Key generation failed: %s\n"), g10_errstr (err) );
|
||||
return err;
|
||||
|
209
g10/keylist.c
209
g10/keylist.c
@ -40,11 +40,12 @@
|
||||
#include "main.h"
|
||||
#include "i18n.h"
|
||||
#include "status.h"
|
||||
#include "call-agent.h"
|
||||
|
||||
static void list_all (int);
|
||||
static void list_one (strlist_t names, int secret);
|
||||
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
|
||||
{
|
||||
@ -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
|
||||
number information. */
|
||||
#ifdef ENABLE_CARD_SUPPORT
|
||||
void
|
||||
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. */
|
||||
@ -444,7 +446,7 @@ list_all (int secret)
|
||||
log_error ("keydb_get_keyblock failed: %s\n", g10_errstr (rc));
|
||||
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. */
|
||||
else
|
||||
{
|
||||
@ -757,13 +759,15 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
|
||||
static void
|
||||
list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
KBNODE kbctx;
|
||||
KBNODE node;
|
||||
PKT_public_key *pk;
|
||||
struct sig_stats *stats = opaque;
|
||||
int skip_sigs = 0;
|
||||
int s2k_char;
|
||||
char *hexgrip = NULL;
|
||||
char *serialno = NULL;
|
||||
|
||||
/* Get the keyid from the keyblock. */
|
||||
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
|
||||
@ -776,9 +780,22 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
|
||||
pk = node->pkt->pkt.public_key;
|
||||
|
||||
/* Fixme: Get s2k mode from the agent. */
|
||||
s2k_char = (/*(sk->protect.s2k.mode == 1001)? '#' :
|
||||
(sk->protect.s2k.mode == 1002)? '>' : */' ');
|
||||
if (secret || opt.with_keygrip)
|
||||
{
|
||||
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 ();
|
||||
|
||||
@ -822,19 +839,11 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
if (fpr)
|
||||
print_fingerprint (pk, 0);
|
||||
|
||||
if (opt.with_keygrip)
|
||||
{
|
||||
char *p;
|
||||
if (opt.with_keygrip && hexgrip)
|
||||
es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
|
||||
|
||||
if (!hexkeygrip_from_pk (pk, &p))
|
||||
{
|
||||
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 (serialno)
|
||||
print_card_serialno (serialno);
|
||||
|
||||
if (opt.with_key_data)
|
||||
print_key_data (pk);
|
||||
@ -895,9 +904,24 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
else
|
||||
skip_sigs = 0;
|
||||
|
||||
/* Fixme: Get s2k mode from the agent. */
|
||||
s2k_char = (/*(sk->protect.s2k.mode == 1001)? '#' :
|
||||
(sk->protect.s2k.mode == 1002)? '>' : */' ');
|
||||
xfree (serialno); serialno = NULL;
|
||||
xfree (hexgrip); hexgrip = NULL;
|
||||
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",
|
||||
secret? "ssb":"sub",
|
||||
@ -926,20 +950,11 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
if (fpr > 1)
|
||||
{
|
||||
print_fingerprint (pk2, 0);
|
||||
/* FIXME: (see above) */
|
||||
/* if (secret) */
|
||||
/* 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 (serialno)
|
||||
print_card_serialno (serialno);
|
||||
}
|
||||
if (opt.with_keygrip && hexgrip)
|
||||
es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
|
||||
if (opt.with_key_data)
|
||||
print_key_data (pk2);
|
||||
}
|
||||
@ -1050,6 +1065,8 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
|
||||
}
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
xfree (serialno);
|
||||
xfree (hexgrip);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1079,7 +1096,7 @@ print_revokers (PKT_public_key * pk)
|
||||
static void
|
||||
list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
KBNODE kbctx;
|
||||
KBNODE node;
|
||||
PKT_public_key *pk;
|
||||
@ -1088,6 +1105,9 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
|
||||
int ulti_hack = 0;
|
||||
int i;
|
||||
char *p;
|
||||
char *hexgrip = NULL;
|
||||
char *serialno = NULL;
|
||||
int stubkey;
|
||||
|
||||
/* Get the keyid from the keyblock. */
|
||||
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;
|
||||
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);
|
||||
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 14. */
|
||||
if (/*FIXME sk->protect.s2k.mode*/1 == 1001)
|
||||
es_putc ('#', es_stdout); /* Key is just a stub. */
|
||||
else if (/*FIXME sk->protect.s2k.mode*/1 == 1002)
|
||||
{
|
||||
/* 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]); */
|
||||
}
|
||||
if (stubkey)
|
||||
es_putc ('#', es_stdout);
|
||||
else if (serialno)
|
||||
es_fputs(serialno, es_stdout);
|
||||
es_putc (':', es_stdout); /* End of field 15. */
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
@ -1154,11 +1177,8 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
|
||||
print_fingerprint (pk, 0);
|
||||
if (opt.with_key_data || opt.with_keygrip)
|
||||
{
|
||||
if (!hexkeygrip_from_pk (pk, &p))
|
||||
{
|
||||
es_fprintf (es_stdout, "grp:::::::::%s:\n", p);
|
||||
xfree (p);
|
||||
}
|
||||
if (hexgrip)
|
||||
es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
|
||||
if (opt.with_key_data)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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 14. */
|
||||
if (/*FIXME:sk2->protect.s2k.mode*/1 == 1001)
|
||||
es_putc ('#', es_stdout); /* Key is just a stub. */
|
||||
else if (/*FIXME: sk2->protect.s2k.mode*/1 == 1002)
|
||||
{
|
||||
/* 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]); */
|
||||
}
|
||||
if (stubkey)
|
||||
es_putc ('#', es_stdout);
|
||||
else if (serialno)
|
||||
es_fputs (serialno, es_stdout);
|
||||
es_putc (':', es_stdout); /* End of field 15. */
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
@ -1260,11 +1288,8 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
|
||||
print_fingerprint (pk2, 0);
|
||||
if (opt.with_key_data || opt.with_keygrip)
|
||||
{
|
||||
if (!hexkeygrip_from_pk (pk2, &p))
|
||||
{
|
||||
es_fprintf (es_stdout, "grp:::::::::%s:\n", p);
|
||||
xfree (p);
|
||||
}
|
||||
if (hexgrip)
|
||||
es_fprintf (es_stdout, "grp:::::::::%s:\n", hexgrip);
|
||||
if (opt.with_key_data)
|
||||
print_key_data (pk2);
|
||||
}
|
||||
@ -1385,6 +1410,9 @@ list_keyblock_colon (KBNODE keyblock, int secret, int fpr)
|
||||
/* 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. */
|
||||
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");
|
||||
/* int i; */
|
||||
if (!serialno)
|
||||
return;
|
||||
if (opt.with_colons)
|
||||
return; /* Handled elsewhere. */
|
||||
|
||||
/* if (!sk) */
|
||||
/* return; */
|
||||
/* if (!sk->is_protected || sk->protect.s2k.mode != 1002) */
|
||||
/* return; /\* Not a card. *\/ */
|
||||
/* if (opt.with_colons) */
|
||||
/* return; /\* Handled elsewhere. *\/ */
|
||||
|
||||
/* es_fputs (_(" Card serial no. ="), es_stdout); */
|
||||
/* es_putc (' ', es_stdout); */
|
||||
/* if (sk->protect.ivlen == 16 */
|
||||
/* && !memcmp (sk->protect.iv, "\xD2\x76\x00\x01\x24\x01", 6)) */
|
||||
/* { */
|
||||
/* /\* 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); */
|
||||
es_fputs (_(" Card serial no. ="), es_stdout);
|
||||
es_putc (' ', es_stdout);
|
||||
if (strlen (serialno) == 32 && !strncmp (serialno, "D27600012401", 12))
|
||||
{
|
||||
/* This is an OpenPGP card. Print the relevant part. */
|
||||
/* Example: D2760001240101010001000003470000 */
|
||||
/* xxxxyyyyyyyy */
|
||||
es_fprintf (es_stdout, "%.*s %.*s", 4, serialno+16, 8, serialno+20);
|
||||
}
|
||||
else
|
||||
es_fputs (serialno, es_stdout);
|
||||
es_putc ('\n', es_stdout);
|
||||
}
|
||||
|
||||
|
||||
|
@ -555,11 +555,10 @@ get_signature_count (PKT_public_key *pk)
|
||||
/* if(agent_scd_getattr("SIG-COUNTER",&info)==0) */
|
||||
/* return info.sig_counter; */
|
||||
/* } */
|
||||
#endif
|
||||
|
||||
/* How to do this without a card? */
|
||||
|
||||
#else
|
||||
(void)pk;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Expand %-strings. Returns a string which must be xfreed. Returns
|
||||
|
@ -79,6 +79,8 @@ struct
|
||||
const char *def_secret_key;
|
||||
char *def_recipient;
|
||||
int def_recipient_self;
|
||||
strlist_t secret_keys_to_try;
|
||||
|
||||
int def_cert_level;
|
||||
int min_cert_level;
|
||||
int ask_cert_level;
|
||||
|
@ -211,17 +211,6 @@ get_last_passphrase()
|
||||
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
|
||||
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
|
||||
@ -407,7 +396,8 @@ passphrase_get ( u32 *keyid, int mode, const char *cacheid, int repeat,
|
||||
|
||||
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") );
|
||||
if (canceled)
|
||||
|
@ -94,14 +94,13 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
|
||||
{
|
||||
void *enum_context = NULL;
|
||||
u32 keyid[2];
|
||||
char *p;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (sk)
|
||||
free_public_key (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)
|
||||
{
|
||||
rc = G10ERR_NO_SECKEY;
|
||||
@ -109,42 +108,22 @@ get_session_key (PKT_pubkey_enc * k, DEK * dek)
|
||||
}
|
||||
if (sk->pubkey_algo != k->pubkey_algo)
|
||||
continue;
|
||||
if (!(sk->pubkey_usage & PUBKEY_USAGE_ENC))
|
||||
continue;
|
||||
keyid_from_pk (sk, keyid);
|
||||
log_info (_("anonymous recipient; trying secret key %s ...\n"),
|
||||
keystr (keyid));
|
||||
|
||||
if (!opt.try_all_secrets && !is_status_enabled ())
|
||||
{
|
||||
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)
|
||||
{
|
||||
log_info (_("okay, we are the anonymous recipient.\n"));
|
||||
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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user