aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2010-10-26 09:10:29 +0000
committerWerner Koch <[email protected]>2010-10-26 09:10:29 +0000
commit02e4c3cb7efacee1b6f716e5b9e923e7e2ded2bf (patch)
tree7b6fa659e8f77cb41b2c8ce3cf31634376c276e2 /agent
parentRemove cruft. (diff)
downloadgnupg-02e4c3cb7efacee1b6f716e5b9e923e7e2ded2bf.tar.gz
gnupg-02e4c3cb7efacee1b6f716e5b9e923e7e2ded2bf.zip
Re-implemented GPG's --passwd command and improved it.
Diffstat (limited to 'agent')
-rw-r--r--agent/ChangeLog17
-rw-r--r--agent/agent.h3
-rw-r--r--agent/cache.c2
-rw-r--r--agent/command.c142
-rw-r--r--agent/findkey.c2
-rw-r--r--agent/genkey.c44
6 files changed, 184 insertions, 26 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index cd33bcad9..9f4bd863e 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,20 @@
+2010-10-26 Werner Koch <[email protected]>
+
+ * 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 <[email protected]>
+
+ * command.c (cmd_export_key): Free CACHE_NONCE.
+ (cmd_passwd): Add option --cache-nonce.
+
2010-10-18 Werner Koch <[email protected]>
* call-pinentry.c (start_pinentry): Print name of pinentry on
diff --git a/agent/agent.h b/agent/agent.h
index 48511c565..2700d8a91 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -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);
diff --git a/agent/cache.c b/agent/cache.c
index abbf8c653..f19e97d32 100644
--- a/agent/cache.c
+++ b/agent/cache.c
@@ -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)
diff --git a/agent/command.c b/agent/command.c
index 0a56f1218..8ae313e7a 100644
--- a/agent/command.c
+++ b/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);
diff --git a/agent/findkey.c b/agent/findkey.c
index 611a44142..91fb8c14c 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -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)
{
diff --git a/agent/genkey.c b/agent/genkey.c
index 7612f99da..2842448f2 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -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;
}