diff options
author | Werner Koch <[email protected]> | 2010-10-26 09:10:29 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2010-10-26 09:10:29 +0000 |
commit | 02e4c3cb7efacee1b6f716e5b9e923e7e2ded2bf (patch) | |
tree | 7b6fa659e8f77cb41b2c8ce3cf31634376c276e2 /agent | |
parent | Remove cruft. (diff) | |
download | gnupg-02e4c3cb7efacee1b6f716e5b9e923e7e2ded2bf.tar.gz gnupg-02e4c3cb7efacee1b6f716e5b9e923e7e2ded2bf.zip |
Re-implemented GPG's --passwd command and improved it.
Diffstat (limited to 'agent')
-rw-r--r-- | agent/ChangeLog | 17 | ||||
-rw-r--r-- | agent/agent.h | 3 | ||||
-rw-r--r-- | agent/cache.c | 2 | ||||
-rw-r--r-- | agent/command.c | 142 | ||||
-rw-r--r-- | agent/findkey.c | 2 | ||||
-rw-r--r-- | agent/genkey.c | 44 |
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; } |