mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
Re-implemented GPG's --passwd command and improved it.
This commit is contained in:
parent
c212133918
commit
02e4c3cb7e
18 changed files with 696 additions and 571 deletions
|
@ -1,3 +1,20 @@
|
|||
2010-10-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* cache.c (agent_put_cache): Allow deletion even if TTL is passwd
|
||||
as 0.
|
||||
|
||||
* genkey.c (agent_protect_and_store): Add arg PASSPHRASE_ADDR.
|
||||
* command.c (cmd_passwd): Add option --passwd-nonce.
|
||||
(struct server_local_s): Add LAST_CACHE_NONCE and LAST_PASSWD_NONCE.
|
||||
(clear_nonce_cache): New.
|
||||
(reset_notify): Clear the nonce cache.
|
||||
(start_command_handler): Ditto.
|
||||
|
||||
2010-10-25 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command.c (cmd_export_key): Free CACHE_NONCE.
|
||||
(cmd_passwd): Add option --cache-nonce.
|
||||
|
||||
2010-10-18 Werner Koch <wk@g10code.com>
|
||||
|
||||
* call-pinentry.c (start_pinentry): Print name of pinentry on
|
||||
|
|
|
@ -295,7 +295,8 @@ gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
|||
int agent_genkey (ctrl_t ctrl, const char *cache_nonce,
|
||||
const char *keyparam, size_t keyparmlen,
|
||||
int no_protection, membuf_t *outbuf);
|
||||
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
|
||||
gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
||||
char **passphrase_addr);
|
||||
|
||||
/*-- protect.c --*/
|
||||
unsigned long get_standard_s2k_count (void);
|
||||
|
|
|
@ -284,7 +284,7 @@ agent_put_cache (const char *key, cache_mode_t cache_mode,
|
|||
default: ttl = opt.def_cache_ttl; break;
|
||||
}
|
||||
}
|
||||
if (!ttl || cache_mode == CACHE_MODE_IGNORE)
|
||||
if ((!ttl && data) || cache_mode == CACHE_MODE_IGNORE)
|
||||
return 0;
|
||||
|
||||
for (r=thecache; r; r = r->next)
|
||||
|
|
142
agent/command.c
142
agent/command.c
|
@ -72,6 +72,8 @@ struct server_local_s
|
|||
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. */
|
||||
char *last_cache_nonce; /* Last CACHE_NOCNE sent as status (malloced). */
|
||||
char *last_passwd_nonce; /* Last PASSWD_NOCNE sent as status (malloced). */
|
||||
};
|
||||
|
||||
|
||||
|
@ -153,6 +155,26 @@ write_and_clear_outbuf (assuan_context_t ctx, membuf_t *mb)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
clear_nonce_cache (ctrl_t ctrl)
|
||||
{
|
||||
if (ctrl->server_local->last_cache_nonce)
|
||||
{
|
||||
agent_put_cache (ctrl->server_local->last_cache_nonce,
|
||||
CACHE_MODE_NONCE, NULL, 0);
|
||||
xfree (ctrl->server_local->last_cache_nonce);
|
||||
ctrl->server_local->last_cache_nonce = NULL;
|
||||
}
|
||||
if (ctrl->server_local->last_passwd_nonce)
|
||||
{
|
||||
agent_put_cache (ctrl->server_local->last_passwd_nonce,
|
||||
CACHE_MODE_NONCE, NULL, 0);
|
||||
xfree (ctrl->server_local->last_passwd_nonce);
|
||||
ctrl->server_local->last_passwd_nonce = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
reset_notify (assuan_context_t ctx, char *line)
|
||||
{
|
||||
|
@ -166,6 +188,9 @@ reset_notify (assuan_context_t ctx, char *line)
|
|||
|
||||
xfree (ctrl->server_local->keydesc);
|
||||
ctrl->server_local->keydesc = NULL;
|
||||
|
||||
clear_nonce_cache (ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1331,44 +1356,135 @@ cmd_learn (assuan_context_t ctx, char *line)
|
|||
|
||||
|
||||
static const char hlp_passwd[] =
|
||||
"PASSWD <hexstring_with_keygrip>\n"
|
||||
"PASSWD [--cache-nonce=<c>] [--passwd-nonce=<s>] <hexstring_with_keygrip>\n"
|
||||
"\n"
|
||||
"Change the passphrase/PIN for the key identified by keygrip in LINE.";
|
||||
static gpg_error_t
|
||||
cmd_passwd (assuan_context_t ctx, char *line)
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
gpg_error_t err;
|
||||
int c;
|
||||
char *cache_nonce = NULL;
|
||||
char *passwd_nonce = NULL;
|
||||
unsigned char grip[20];
|
||||
gcry_sexp_t s_skey = NULL;
|
||||
unsigned char *shadow_info = NULL;
|
||||
char *passphrase = NULL;
|
||||
char *pend;
|
||||
|
||||
rc = parse_keygrip (ctx, line, grip);
|
||||
if (rc)
|
||||
cache_nonce = option_value (line, "--cache-nonce");
|
||||
if (cache_nonce)
|
||||
{
|
||||
for (pend = cache_nonce; *pend && !spacep (pend); pend++)
|
||||
;
|
||||
c = *pend;
|
||||
*pend = '\0';
|
||||
cache_nonce = xtrystrdup (cache_nonce);
|
||||
*pend = c;
|
||||
if (!cache_nonce)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
passwd_nonce = option_value (line, "--passwd-nonce");
|
||||
if (passwd_nonce)
|
||||
{
|
||||
for (pend = passwd_nonce; *pend && !spacep (pend); pend++)
|
||||
;
|
||||
c = *pend;
|
||||
*pend = '\0';
|
||||
passwd_nonce = xtrystrdup (passwd_nonce);
|
||||
*pend = c;
|
||||
if (!passwd_nonce)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
line = skip_options (line);
|
||||
|
||||
err = parse_keygrip (ctx, line, grip);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
ctrl->in_passwd++;
|
||||
rc = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc,
|
||||
grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
|
||||
&s_skey, NULL);
|
||||
if (rc)
|
||||
err = agent_key_from_file (ctrl, cache_nonce, ctrl->server_local->keydesc,
|
||||
grip, &shadow_info, CACHE_MODE_IGNORE, NULL,
|
||||
&s_skey, &passphrase);
|
||||
if (err)
|
||||
;
|
||||
else if (!s_skey)
|
||||
{
|
||||
log_error ("changing a smartcard PIN is not yet supported\n");
|
||||
rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
else
|
||||
rc = agent_protect_and_store (ctrl, s_skey);
|
||||
{
|
||||
char *newpass = NULL;
|
||||
|
||||
if (passwd_nonce)
|
||||
newpass = agent_get_cache (passwd_nonce, CACHE_MODE_NONCE);
|
||||
err = agent_protect_and_store (ctrl, s_skey, &newpass);
|
||||
if (!err && passphrase)
|
||||
{
|
||||
/* A passphrase existed on the old key and the change was
|
||||
successful. Return a nonce for that old passphrase to
|
||||
let the caller try to unprotect the other subkeys with
|
||||
the same key. */
|
||||
if (!cache_nonce)
|
||||
{
|
||||
char buf[12];
|
||||
gcry_create_nonce (buf, 12);
|
||||
cache_nonce = bin2hex (buf, 12, NULL);
|
||||
}
|
||||
if (cache_nonce
|
||||
&& !agent_put_cache (cache_nonce, CACHE_MODE_NONCE,
|
||||
passphrase, 120 /*seconds*/))
|
||||
{
|
||||
assuan_write_status (ctx, "CACHE_NONCE", cache_nonce);
|
||||
xfree (ctrl->server_local->last_cache_nonce);
|
||||
ctrl->server_local->last_cache_nonce = cache_nonce;
|
||||
cache_nonce = NULL;
|
||||
}
|
||||
if (newpass)
|
||||
{
|
||||
/* If we have a new passphrase (which might be empty) we
|
||||
store it under a passwd nonce so that the caller may
|
||||
send that nonce again to use it for another key. */
|
||||
if (!passwd_nonce)
|
||||
{
|
||||
char buf[12];
|
||||
gcry_create_nonce (buf, 12);
|
||||
passwd_nonce = bin2hex (buf, 12, NULL);
|
||||
}
|
||||
if (passwd_nonce
|
||||
&& !agent_put_cache (passwd_nonce, CACHE_MODE_NONCE,
|
||||
newpass, 120 /*seconds*/))
|
||||
{
|
||||
assuan_write_status (ctx, "PASSWD_NONCE", passwd_nonce);
|
||||
xfree (ctrl->server_local->last_passwd_nonce);
|
||||
ctrl->server_local->last_passwd_nonce = passwd_nonce;
|
||||
passwd_nonce = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
xfree (newpass);
|
||||
}
|
||||
ctrl->in_passwd--;
|
||||
|
||||
xfree (ctrl->server_local->keydesc);
|
||||
ctrl->server_local->keydesc = NULL;
|
||||
|
||||
leave:
|
||||
xfree (passphrase);
|
||||
gcry_sexp_release (s_skey);
|
||||
xfree (shadow_info);
|
||||
return leave_cmd (ctx, rc);
|
||||
xfree (cache_nonce);
|
||||
return leave_cmd (ctx, err);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1812,6 +1928,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
|
|||
|
||||
|
||||
leave:
|
||||
xfree (cache_nonce);
|
||||
xfree (passphrase);
|
||||
xfree (wrappedkey);
|
||||
gcry_cipher_close (cipherhd);
|
||||
|
@ -2448,6 +2565,9 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
|
|||
}
|
||||
}
|
||||
|
||||
/* Reset the nonce caches. */
|
||||
clear_nonce_cache (ctrl);
|
||||
|
||||
/* Reset the SCD if needed. */
|
||||
agent_reset_scd (ctrl);
|
||||
|
||||
|
|
|
@ -405,7 +405,7 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
|
|||
xfree (pi);
|
||||
return rc;
|
||||
}
|
||||
rc = agent_protect_and_store (ctrl, s_skey);
|
||||
rc = agent_protect_and_store (ctrl, s_skey, NULL);
|
||||
gcry_sexp_release (s_skey);
|
||||
if (rc)
|
||||
{
|
||||
|
|
|
@ -468,20 +468,40 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce,
|
|||
|
||||
|
||||
|
||||
/* Apply a new passphrase to the key S_SKEY and store it. */
|
||||
int
|
||||
agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey)
|
||||
/* Apply a new passphrase to the key S_SKEY and store it. If
|
||||
PASSPHRASE_ADDR and *PASSPHRASE_ADDR are not NULL, use that
|
||||
passphrase. If PASSPHRASE_ADDR is not NULL store a newly entered
|
||||
passphrase at that address. */
|
||||
gpg_error_t
|
||||
agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
||||
char **passphrase_addr)
|
||||
{
|
||||
int rc;
|
||||
char *passphrase;
|
||||
gpg_error_t err;
|
||||
|
||||
rc = agent_ask_new_passphrase (ctrl,
|
||||
_("Please enter the new passphrase"),
|
||||
&passphrase);
|
||||
if (!rc)
|
||||
if (passphrase_addr && *passphrase_addr)
|
||||
{
|
||||
rc = store_key (s_skey, passphrase, 1);
|
||||
xfree (passphrase);
|
||||
/* Take an empty string as request not to protect the key. */
|
||||
err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1);
|
||||
}
|
||||
return rc;
|
||||
else
|
||||
{
|
||||
char *pass = NULL;
|
||||
|
||||
if (passphrase_addr)
|
||||
{
|
||||
xfree (*passphrase_addr);
|
||||
*passphrase_addr = NULL;
|
||||
}
|
||||
err = agent_ask_new_passphrase (ctrl,
|
||||
_("Please enter the new passphrase"),
|
||||
&pass);
|
||||
if (!err)
|
||||
err = store_key (s_skey, pass, 1);
|
||||
if (!err && passphrase_addr)
|
||||
*passphrase_addr = pass;
|
||||
else
|
||||
xfree (pass);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue