1
0
Fork 0
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:
Werner Koch 2010-10-26 09:10:29 +00:00
parent c212133918
commit 02e4c3cb7e
18 changed files with 696 additions and 571 deletions

View file

@ -1,5 +1,24 @@
2010-10-26 Werner Koch <wk@g10code.com>
* keyedit.c (change_passphrase): Handle the passwd_nonce.
* call-agent.c (cache_nonce_parm_s): New.
(cache_nonce_status_cb): Use that new struct.
(agent_genkey, agent_import_key, agent_export_key, agent_passwd):
Adjust for that change.
2010-10-25 Werner Koch <wk@g10code.com>
* passphrase.c (gpg_format_keydesc): Fix printing of main keyid.
* keyedit.c (JNLIB_NEED_LOG_LOGV): Define.
* call-agent.c (agent_passwd): New.
2010-10-21 Werner Koch <wk@g10code.com>
* keyedit.c (keyedit_passwd): Simplify.
(change_passphrase): Return an error code and not the change
flag. Remove editing of the keyring.
* seckey-cert.c: Remove.
* Makefile.am (gpg2_SOURCES): Remove seckey-cert.c

View file

@ -86,6 +86,13 @@ struct import_key_parm_s
};
struct cache_nonce_parm_s
{
char **cache_nonce_addr;
char **passwd_nonce_addr;
};
static gpg_error_t learn_status_cb (void *opaque, const char *line);
@ -1470,7 +1477,7 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
static gpg_error_t
cache_nonce_status_cb (void *opaque, const char *line)
{
char **cache_nonce = opaque;
struct cache_nonce_parm_s *parm = opaque;
const char *keyword = line;
int keywordlen;
@ -1481,10 +1488,18 @@ cache_nonce_status_cb (void *opaque, const char *line)
if (keywordlen == 11 && !memcmp (keyword, "CACHE_NONCE", keywordlen))
{
if (cache_nonce)
if (parm->cache_nonce_addr)
{
xfree (*cache_nonce);
*cache_nonce = xtrystrdup (line);
xfree (*parm->cache_nonce_addr);
*parm->cache_nonce_addr = xtrystrdup (line);
}
}
else if (keywordlen == 12 && !memcmp (keyword, "PASSWD_NONCE", keywordlen))
{
if (parm->passwd_nonce_addr)
{
xfree (*parm->passwd_nonce_addr);
*parm->passwd_nonce_addr = xtrystrdup (line);
}
}
@ -1523,6 +1538,7 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
{
gpg_error_t err;
struct genkey_parm_s gk_parm;
struct cache_nonce_parm_s cn_parm;
membuf_t data;
size_t len;
unsigned char *buf;
@ -1546,10 +1562,12 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
no_protection? " --no-protection":"",
cache_nonce_addr && *cache_nonce_addr? " ":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"");
cn_parm.cache_nonce_addr = cache_nonce_addr;
cn_parm.passwd_nonce_addr = NULL;
err = assuan_transact (agent_ctx, line,
membuf_data_cb, &data,
inq_genkey_parms, &gk_parm,
cache_nonce_status_cb, cache_nonce_addr);
cache_nonce_status_cb, &cn_parm);
if (err)
{
xfree (get_membuf (&data, &len));
@ -1625,7 +1643,7 @@ agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
displayed if the agent needs to ask for the PIN. DIGEST and
DIGESTLEN is the hash value to sign and DIGESTALGO the algorithm id
used to compute the digest. If CACHE_NONCE is used the agent is
advised to firts try a passphrase associated with that nonce. */
advised to first try a passphrase associated with that nonce. */
gpg_error_t
agent_pksign (ctrl_t ctrl, const char *cache_nonce,
const char *keygrip, const char *desc,
@ -1890,6 +1908,7 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
{
gpg_error_t err;
struct import_key_parm_s parm;
struct cache_nonce_parm_s cn_parm;
char line[ASSUAN_LINELENGTH];
err = start_agent (ctrl, 0);
@ -1914,9 +1933,11 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
snprintf (line, sizeof line, "IMPORT_KEY%s%s",
cache_nonce_addr && *cache_nonce_addr? " ":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"");
cn_parm.cache_nonce_addr = cache_nonce_addr;
cn_parm.passwd_nonce_addr = NULL;
err = assuan_transact (agent_ctx, line,
NULL, NULL, inq_import_key_parms, &parm,
cache_nonce_status_cb, cache_nonce_addr);
cache_nonce_status_cb, &cn_parm);
return err;
}
@ -1932,6 +1953,7 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
unsigned char **r_result, size_t *r_resultlen)
{
gpg_error_t err;
struct cache_nonce_parm_s cn_parm;
membuf_t data;
size_t len;
unsigned char *buf;
@ -1958,10 +1980,12 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
hexkeygrip);
init_membuf_secure (&data, 1024);
cn_parm.cache_nonce_addr = cache_nonce_addr;
cn_parm.passwd_nonce_addr = NULL;
err = assuan_transact (agent_ctx, line,
membuf_data_cb, &data,
default_inq_cb, ctrl,
cache_nonce_status_cb, cache_nonce_addr);
cache_nonce_status_cb, &cn_parm);
if (err)
{
xfree (get_membuf (&data, &len));
@ -1974,3 +1998,49 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
*r_resultlen = len;
return 0;
}
/* Ask the agent to change the passphrase of the key identified by
HEXKEYGRIP. If DESC is not NULL, display DESC instead of the
default description message. If CACHE_NONCE_ADDR is not NULL the
agent is advised to first try a passphrase associated with that
nonce. If PASSWD_NONCE_ADDR is not NULL the agent will try to use
the passphrase associated with that nonce. */
gpg_error_t
agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
char **cache_nonce_addr, char **passwd_nonce_addr)
{
gpg_error_t err;
struct cache_nonce_parm_s cn_parm;
char line[ASSUAN_LINELENGTH];
err = start_agent (ctrl, 0);
if (err)
return err;
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
if (desc)
{
snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
return err;
}
snprintf (line, DIM(line)-1, "PASSWD %s%s %s%s %s",
cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
hexkeygrip);
cn_parm.cache_nonce_addr = cache_nonce_addr;
cn_parm.passwd_nonce_addr = passwd_nonce_addr;
err = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, ctrl,
cache_nonce_status_cb, &cn_parm);
return err;
}

View file

@ -184,6 +184,9 @@ gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip,
const char *desc, char **cache_nonce_addr,
unsigned char **r_result, size_t *r_resultlen);
/* Change the passphrase of a key. */
gpg_error_t agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
char **cache_nonce_addr, char **passwd_nonce_addr);
#endif /*GNUPG_G10_CALL_AGENT_H*/

View file

@ -3657,7 +3657,7 @@ main (int argc, char **argv)
else
{
username = make_username (fname);
keyedit_passwd (username);
keyedit_passwd (ctrl, username);
xfree (username);
}
break;

View file

@ -30,6 +30,7 @@
# include <readline/readline.h>
#endif
#define JNLIB_NEED_LOG_LOGV
#include "gpg.h"
#include "options.h"
#include "packet.h"
@ -1124,44 +1125,63 @@ leave:
/*
* Change the passphrase of the primary and all secondary keys.
* We use only one passphrase for all keys.
* Change the passphrase of the primary and all secondary keys. Note
* that it is common to use only one passphrase for the primary and
* all subkeys. However, this is now (since GnuPG 2.1) all up to the
* gpg-agent. Returns 0 on success or an error code.
*/
static int
change_passphrase (KBNODE keyblock, int *r_err)
static gpg_error_t
change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
{
int rc = 0;
int changed = 0;
KBNODE node;
PKT_public_key *pksk;
char *passphrase = NULL;
int no_primary_secrets = 0;
gpg_error_t err;
kbnode_t node;
PKT_public_key *pk;
int any;
u32 keyid[2], subid[2];
char *hexgrip = NULL;
char *cache_nonce = NULL;
char *passwd_nonce = NULL;
node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
if (!node)
{
log_error ("Oops; public key missing!\n");
err = gpg_error (GPG_ERR_INTERNAL);
goto leave;
}
pksk = node->pkt->pkt.public_key;
pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, keyid);
/* Check whether it is likely that we will be able to change the
passphrase for any subkey. */
for (any = 0, node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
log_debug ("FIXME\n");
/* PKT_public_key *tmpsk = node->pkt->pkt.public_key; */
/* if (!(tmpsk->is_protected */
/* && (tmpsk->protect.s2k.mode == 1001 */
/* || tmpsk->protect.s2k.mode == 1002))) */
/* { */
/* any = 1; */
/* break; */
/* } */
char *serialno;
pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, subid);
xfree (hexgrip);
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
goto leave;
err = agent_get_keyinfo (ctrl, hexgrip, &serialno);
if (!err && serialno)
; /* Key on card. */
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
; /* Maybe stub key. */
else if (!err)
any = 1; /* Key is known. */
else
log_error ("key %s: error getting keyinfo from agent: %s\n",
keystr_with_sub (keyid, subid), gpg_strerror (err));
xfree (serialno);
}
}
err = 0;
if (!any)
{
tty_printf (_("Key has only stub or on-card key items - "
@ -1169,162 +1189,43 @@ change_passphrase (KBNODE keyblock, int *r_err)
goto leave;
}
log_debug ("FIXME\n");
/* See how to handle this key. */
/* switch (is_secret_key_protected (pksk)) */
/* { */
/* case -1: */
/* rc = G10ERR_PUBKEY_ALGO; */
/* break; */
/* case 0: */
/* tty_printf (_("This key is not protected.\n")); */
/* break; */
/* default: */
/* if (sk->protect.s2k.mode == 1001) */
/* { */
/* tty_printf (_("Secret parts of key are not available.\n")); */
/* no_primary_secrets = 1; */
/* } */
/* else if (sk->protect.s2k.mode == 1002) */
/* { */
/* tty_printf (_("Secret parts of key are stored on-card.\n")); */
/* no_primary_secrets = 1; */
/* } */
/* else */
/* { */
/* u32 keyid[2]; */
/* tty_printf (_("Key is protected.\n")); */
/* /\* Clear the passphrase cache so that the user is required */
/* to enter the old passphrase. *\/ */
/* keyid_from_pk (pksk, keyid); */
/* passphrase_clear_cache (keyid, NULL, 0); */
/* /\* rc = check_secret_key( sk, 0 ); *\/ */
/* /\* if( !rc ) *\/ */
/* /\* passphrase = get_last_passphrase(); *\/ */
/* } */
/* break; */
/* } */
/* Unprotect all subkeys (use the supplied passphrase or ask) */
for (node = keyblock; !rc && node; node = node->next)
/* Change the passphrase for all keys. */
for (any = 0, node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
log_debug ("FIXME\n");
/* PKT_pubic_key *subsk = node->pkt->pkt.public_key; */
/* if (!(subsk->is_protected */
/* && (subsk->protect.s2k.mode == 1001 */
/* || subsk->protect.s2k.mode == 1002))) */
/* { */
/* set_next_passphrase (passphrase); */
/* /\* rc = check_secret_key( subsk, 0 ); *\/ */
/* /\* if( !rc && !passphrase ) *\/ */
/* /\* passphrase = get_last_passphrase(); *\/ */
/* } */
}
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
char *desc;
pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, subid);
xfree (hexgrip);
err = hexkeygrip_from_pk (pk, &hexgrip);
if (err)
goto leave;
desc = gpg_format_keydesc (pk, 0, 1);
err = agent_passwd (ctrl, hexgrip, desc, &cache_nonce, &passwd_nonce);
xfree (desc);
if (err)
log_log ((gpg_err_code (err) == GPG_ERR_CANCELED
|| gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
? JNLIB_LOG_INFO : JNLIB_LOG_ERROR,
_("key %s: error changing passphrase: %s\n"),
keystr_with_sub (keyid, subid),
gpg_strerror (err));
if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
break;
}
}
if (rc)
tty_printf (_("Can't edit this key: %s\n"), g10_errstr (rc));
else
{
DEK *dek = NULL;
STRING2KEY *s2k = xmalloc_secure (sizeof *s2k);
const char *errtext = NULL;
tty_printf (_("Enter the new passphrase for this secret key.\n\n"));
set_next_passphrase (NULL);
for (;;)
{
int canceled;
s2k->mode = opt.s2k_mode;
s2k->hash_algo = S2K_DIGEST_ALGO;
dek = passphrase_to_dek (NULL, 0, opt.s2k_cipher_algo,
s2k, 2, errtext, &canceled);
if (!dek && canceled)
{
rc = GPG_ERR_CANCELED;
break;
}
else if (!dek)
{
errtext = N_("passphrase not correctly repeated; try again");
tty_printf ("%s.\n", _(errtext));
}
else if (!dek->keylen)
{
rc = 0;
tty_printf (_("You don't want a passphrase -"
" this is probably a *bad* idea!\n\n"));
if (cpr_get_answer_is_yes
("change_passwd.empty.okay",
_("Do you really want to do this? (y/N) ")))
{
changed++;
break;
}
}
else
{ /* okay */
rc = 0;
if (!no_primary_secrets)
{
/* sk->protect.algo = dek->algo; */
/* sk->protect.s2k = *s2k; */
rc = 0;
/* rc = protect_secret_key( sk, dek ); */
}
for (node = keyblock; !rc && node; node = node->next)
{
if (node->pkt->pkttype == PKT_SECRET_SUBKEY)
{
log_debug ("FIXME\n");
/* PKT_secret_key *subsk = node->pkt->pkt.secret_key; */
/* if (!(subsk->is_protected */
/* && (subsk->protect.s2k.mode == 1001 */
/* || subsk->protect.s2k.mode == 1002))) */
/* { */
/* subsk->protect.algo = dek->algo; */
/* subsk->protect.s2k = *s2k; */
/* #warning fixme */
/* rc = 0; */
/* /\* rc = protect_secret_key( subsk, dek ); *\/ */
/* } */
}
}
if (rc)
log_error ("protect_secret_key failed: %s\n",
g10_errstr (rc));
else
{
u32 keyid[2];
/* Clear the cahce again so that the user is
required to enter the new passphrase at the
next operation. */
/* FIXME keyid_from_sk (sk, keyid); */
passphrase_clear_cache (keyid, NULL, 0);
changed++;
}
break;
}
}
xfree (s2k);
xfree (dek);
}
leave:
xfree (passphrase);
set_next_passphrase (NULL);
if (r_err)
*r_err = rc;
return changed && !rc;
leave:
xfree (hexgrip);
xfree (cache_nonce);
xfree (passwd_nonce);
return err;
}
@ -2184,7 +2085,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
break;
case cmdPASSWD:
change_passphrase (keyblock, NULL);
change_passphrase (ctrl, keyblock);
break;
case cmdTRUST:
@ -2361,13 +2262,10 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
/* Change the passphrase of the secret key identified by USERNAME. */
void
keyedit_passwd (const char *username)
keyedit_passwd (ctrl_t ctrl, const char *username)
{
gpg_error_t err;
PKT_public_key *pk;
unsigned char fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
KEYDB_HANDLE kdh = NULL;
kbnode_t keyblock = NULL;
pk = xtrycalloc (1, sizeof *pk);
@ -2376,44 +2274,16 @@ keyedit_passwd (const char *username)
err = gpg_error_from_syserror ();
goto leave;
}
err = getkey_byname (NULL, pk, username, 1, NULL);
if (err)
goto leave;
fingerprint_from_pk (pk, fpr, &fprlen);
while (fprlen < MAX_FINGERPRINT_LEN)
fpr[fprlen++] = 0;
/* FIXME: Call an agent function instead. */
kdh = NULL /*keydb_new (1)*/;
if (!kdh)
{
err = gpg_error (GPG_ERR_GENERAL);
goto leave;
}
err = keydb_search_fpr (kdh, fpr);
if (err == -1 || gpg_err_code (err) == GPG_ERR_EOF)
err = gpg_error (GPG_ERR_NO_SECKEY);
err = getkey_byname (NULL, pk, username, 1, &keyblock);
if (err)
goto leave;
err = keydb_get_keyblock (kdh, &keyblock);
if (err)
goto leave;
if (!change_passphrase (keyblock, &err))
goto leave;
err = keydb_update_keyblock (kdh, keyblock);
if (err)
log_error (_("update secret failed: %s\n"), gpg_strerror (err));
err = change_passphrase (ctrl, keyblock);
leave:
release_kbnode (keyblock);
if (pk)
free_public_key (pk);
keydb_release (kdh);
if (err)
{
log_info ("error changing the passphrase for `%s': %s\n",

View file

@ -224,7 +224,7 @@ int delete_keys( strlist_t names, int secret, int allow_both );
/*-- keyedit.c --*/
void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
strlist_t commands, int quiet, int seckey_check );
void keyedit_passwd (const char *username);
void keyedit_passwd (ctrl_t ctrl, const char *username);
void show_basic_key_info (KBNODE keyblock);
/*-- keygen.c --*/

View file

@ -675,7 +675,7 @@ passphrase_to_dek (u32 *keyid, int pubkey_algo,
}
/* Return an allocated utf-8 string describing the key PK. IF ESCAPED
/* Return an allocated utf-8 string describing the key PK. If ESCAPED
is true spaces and control characters are percent or plus escaped.
MODE 0 is for the common prompt, MODE 1 for the import prompt. */
char *
@ -696,9 +696,9 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
orig_codeset = i18n_switchto_utf8 ();
if (pk->main_keyid[2] && pk->main_keyid[3]
&& pk->keyid[0] != pk->main_keyid[2]
&& pk->keyid[1] != pk->main_keyid[3])
if (pk->main_keyid[0] && pk->main_keyid[1]
&& pk->keyid[0] != pk->main_keyid[0]
&& pk->keyid[1] != pk->main_keyid[1])
maink = xtryasprintf (_(" (main key ID %s)"), keystr (pk->main_keyid));
else
maink = NULL;