gpg: Re-enable secret key deletion.

* g10/call-agent.c (agent_delete_key): New.
* g10/keydb.h (FORMAT_KEYDESC_DELKEY): New.
* g10/passphrase.c (gpg_format_keydesc): Support new format.
* g10/delkey.c (do_delete_key): Add secret key deletion.
This commit is contained in:
Werner Koch 2014-04-15 16:40:48 +02:00
parent d25d00b89e
commit db3b528239
7 changed files with 121 additions and 6 deletions

View File

@ -818,6 +818,7 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
- 1 :: No such key
- 2 :: Must delete secret key first
- 3 :: Ambigious specification
- 4 :: Key is stored on a smartcard.
*** PROGRESS <what> <char> <cur> <total>
Used by the primegen and Public key functions to indicate

View File

@ -2126,6 +2126,44 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
}
/* Ask the agent to delete the key identified by HEXKEYGRIP. If DESC
is not NULL, display DESC instead of the default description
message. */
gpg_error_t
agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
struct default_inq_parm_s dfltparm;
memset (&dfltparm, 0, sizeof dfltparm);
dfltparm.ctrl = ctrl;
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, "DELETE_KEY %s", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, &dfltparm,
NULL, NULL);
return err;
}
/* Ask the agent to change the passphrase of the key identified by
HEXKEYGRIP. If DESC is not NULL, display DESC instead of the

View File

@ -185,6 +185,10 @@ 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);
/* Delete a key from the agent. */
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *hexkeygrip,
const char *desc);
/* 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);

View File

@ -40,6 +40,7 @@
#include "ttyio.h"
#include "status.h"
#include "i18n.h"
#include "call-agent.h"
/****************
@ -52,7 +53,7 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
{
gpg_error_t err;
kbnode_t keyblock = NULL;
kbnode_t node;
kbnode_t node, kbctx;
KEYDB_HANDLE hd;
PKT_public_key *pk = NULL;
u32 keyid[2];
@ -156,9 +157,47 @@ do_delete_key( const char *username, int secret, int force, int *r_sec_avail )
{
if (secret)
{
log_error (_("deleting secret key not implemented\n"));
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */
goto leave;
char *prompt;
gpg_error_t firsterr = 0;
char *hexgrip;
setup_main_keyids (keyblock);
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
continue;
if (agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
continue; /* No secret key for that public (sub)key. */
prompt = gpg_format_keydesc (node->pkt->pkt.public_key,
FORMAT_KEYDESC_DELKEY, 1);
err = hexkeygrip_from_pk (node->pkt->pkt.public_key, &hexgrip);
if (!err)
err = agent_delete_key (NULL, hexgrip, prompt);
xfree (prompt);
xfree (hexgrip);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_KEY_ON_CARD)
write_status_text (STATUS_DELETE_PROBLEM, "1");
log_error (_("deleting secret %s failed: %s\n"),
(node->pkt->pkttype == PKT_PUBLIC_KEY
? _("key"):_("subkey")),
gpg_strerror (err));
if (!firsterr)
firsterr = err;
if (gpg_err_code (err) == GPG_ERR_CANCELED
|| gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
break;
}
}
err = firsterr;
if (firsterr)
goto leave;
}
else
{

View File

@ -1237,6 +1237,38 @@ getkey_end (getkey_ctx_t ctx)
************* Merging stuff ********************
************************************************/
/* Set the mainkey_id fields for all keys in KEYBLOCK. This is
usually done by merge_selfsigs but at some places we only need the
main_kid but the the full merging. The function also guarantees
that all pk->keyids are computed. */
void
setup_main_keyids (kbnode_t keyblock)
{
u32 kid[2], mainkid[2];
kbnode_t kbctx, node;
PKT_public_key *pk;
if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
BUG ();
pk = keyblock->pkt->pkt.public_key;
keyid_from_pk (pk, mainkid);
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
continue;
pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, kid); /* Make sure pk->keyid is set. */
if (!pk->main_keyid[0] && !pk->main_keyid[1])
{
pk->main_keyid[0] = mainkid[0];
pk->main_keyid[1] = mainkid[1];
}
}
}
/* Merge all self-signatures with the keys. */
void
merge_keys_and_selfsig (KBNODE keyblock)

View File

@ -201,7 +201,7 @@ void emit_status_need_passphrase (u32 *keyid, u32 *mainkeyid, int pubkey_algo);
#define FORMAT_KEYDESC_NORMAL 0
#define FORMAT_KEYDESC_IMPORT 1
#define FORMAT_KEYDESC_EXPORT 2
#define FORMAT_KEYDESC_DELKEY 3
char *gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped);
@ -248,6 +248,7 @@ void getkey_end (getkey_ctx_t ctx);
gpg_error_t enum_secret_keys (void **context, PKT_public_key *pk);
void setup_main_keyids (kbnode_t keyblock);
void merge_keys_and_selfsig( KBNODE keyblock );
char*get_user_id_string( u32 *keyid );
char*get_user_id_string_native( u32 *keyid );

View File

@ -702,7 +702,7 @@ gpg_format_keydesc (PKT_public_key *pk, int mode, int escaped)
(int)uidlen, uid,
nbits_from_pk (pk), algo_name,
keystr (pk->keyid), timestr,
maink?maink:"", trailer );
maink?maink:"", trailer);
xfree (maink);
xfree (uid);