mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02:00
agent: Add "ephemeral" Assuan option.
* agent/agent.h (struct ephemeral_private_key_s): New. (struct server_control_s): Add ephemeral_mode and ephemeral_keys. (GENKEY_FLAG_NO_PROTECTION, GENKEY_FLAG_PRESET): New. * agent/genkey.c (clear_ephemeral_keys): New. (store_key): Add arg ctrl and implement ephemeral_mode. Change all callers. (agent_genkey): Replace args no_protection and preset by a generic new flags arg. * agent/findkey.c (wipe_and_fclose): New. (agent_write_private_key): Add arg ctrl and implement ephemeral_mode. Change all callers. (agent_update_private_key): Ditto (read_key_file): Ditto. (agent_key_available): Ditto. * agent/command-ssh.c (card_key_available): Do not update display s/n in ephemeral mode. This is however enver triggred. * agent/gpg-agent.c (agent_deinit_default_ctrl): Cleanup ephemeral keys. * agent/command.c (cmd_genkey): Use the new flags instead of separate vars. (cmd_readkey): Create a shadow key only in non-ephemeral_mode. (cmd_getinfo): Add sub-command "ephemeral". (option_handler): Add option "ephemeral". -- The idea here that a session can be switched in an ephemeral mode which does not store or read keys from disk but keeps them local to the session. GnuPG-bug-id: 6944
This commit is contained in:
parent
18320d692c
commit
434a641d40
11 changed files with 496 additions and 206 deletions
156
agent/genkey.c
156
agent/genkey.c
|
@ -30,14 +30,36 @@
|
|||
#include "../common/exechelp.h"
|
||||
#include "../common/sysutils.h"
|
||||
|
||||
static int
|
||||
store_key (gcry_sexp_t private, const char *passphrase, int force,
|
||||
|
||||
void
|
||||
clear_ephemeral_keys (ctrl_t ctrl)
|
||||
{
|
||||
while (ctrl->ephemeral_keys)
|
||||
{
|
||||
ephemeral_private_key_t next = ctrl->ephemeral_keys->next;
|
||||
if (ctrl->ephemeral_keys->keybuf)
|
||||
{
|
||||
wipememory (ctrl->ephemeral_keys->keybuf,
|
||||
ctrl->ephemeral_keys->keybuflen);
|
||||
xfree (ctrl->ephemeral_keys->keybuf);
|
||||
}
|
||||
xfree (ctrl->ephemeral_keys);
|
||||
ctrl->ephemeral_keys = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Store the key either to a file, or in ctrl->ephemeral_mode in the
|
||||
* session data. */
|
||||
static gpg_error_t
|
||||
store_key (ctrl_t ctrl, gcry_sexp_t private,
|
||||
const char *passphrase, int force,
|
||||
unsigned long s2k_count, time_t timestamp)
|
||||
{
|
||||
int rc;
|
||||
gpg_error_t err;
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
unsigned char grip[20];
|
||||
unsigned char grip[KEYGRIP_LEN];
|
||||
|
||||
if ( !gcry_pk_get_keygrip (private, grip) )
|
||||
{
|
||||
|
@ -49,7 +71,10 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
|
|||
log_assert (len);
|
||||
buf = gcry_malloc_secure (len);
|
||||
if (!buf)
|
||||
return out_of_core ();
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
|
||||
log_assert (len);
|
||||
|
||||
|
@ -57,20 +82,56 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
|
|||
{
|
||||
unsigned char *p;
|
||||
|
||||
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
||||
if (rc)
|
||||
{
|
||||
xfree (buf);
|
||||
return rc;
|
||||
}
|
||||
err = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
||||
if (err)
|
||||
goto leave;
|
||||
xfree (buf);
|
||||
buf = p;
|
||||
}
|
||||
|
||||
rc = agent_write_private_key (grip, buf, len, force,
|
||||
NULL, NULL, NULL, timestamp);
|
||||
if (ctrl->ephemeral_mode)
|
||||
{
|
||||
ephemeral_private_key_t ek;
|
||||
|
||||
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
|
||||
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
|
||||
break;
|
||||
if (!ek)
|
||||
{
|
||||
ek = xtrycalloc (1, sizeof *ek);
|
||||
if (!ek)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
memcpy (ek->grip, grip, KEYGRIP_LEN);
|
||||
ek->next = ctrl->ephemeral_keys;
|
||||
ctrl->ephemeral_keys = ek;
|
||||
}
|
||||
if (ek->keybuf)
|
||||
{
|
||||
wipememory (ek->keybuf, ek->keybuflen);
|
||||
xfree (ek->keybuf);
|
||||
}
|
||||
ek->keybuf = buf;
|
||||
buf = NULL;
|
||||
ek->keybuflen = len;
|
||||
}
|
||||
else
|
||||
err = agent_write_private_key (ctrl, grip, buf, len, force,
|
||||
NULL, NULL, NULL, timestamp);
|
||||
|
||||
if (!err)
|
||||
{
|
||||
char hexgrip[2*KEYGRIP_LEN+1];
|
||||
|
||||
bin2hex (grip, KEYGRIP_LEN, hexgrip);
|
||||
agent_write_status (ctrl, "KEYGRIP", hexgrip, NULL);
|
||||
}
|
||||
|
||||
leave:
|
||||
xfree (buf);
|
||||
return rc;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
@ -450,16 +511,19 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
|||
|
||||
|
||||
/* Generate a new keypair according to the parameters given in
|
||||
KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
|
||||
using the cache nonce. If NO_PROTECTION is true the key will not
|
||||
be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
|
||||
passphrase will be used for the new key. If TIMESTAMP is not zero
|
||||
it will be recorded as creation date of the key (unless extended
|
||||
format is disabled) . */
|
||||
* KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
|
||||
* using the cache nonce. If NO_PROTECTION is true the key will not
|
||||
* be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
|
||||
* passphrase will be used for the new key. If TIMESTAMP is not zero
|
||||
* it will be recorded as creation date of the key (unless extended
|
||||
* format is disabled). In ctrl_ephemeral_mode the key is stored in
|
||||
* the session data and an identifier is returned using a status
|
||||
* line. */
|
||||
int
|
||||
agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
||||
const char *keyparam, size_t keyparamlen, int no_protection,
|
||||
const char *override_passphrase, int preset, membuf_t *outbuf)
|
||||
agent_genkey (ctrl_t ctrl, unsigned int flags,
|
||||
const char *cache_nonce, time_t timestamp,
|
||||
const char *keyparam, size_t keyparamlen,
|
||||
const char *override_passphrase, membuf_t *outbuf)
|
||||
{
|
||||
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
|
||||
char *passphrase_buffer = NULL;
|
||||
|
@ -478,7 +542,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
|||
/* Get the passphrase now, cause key generation may take a while. */
|
||||
if (override_passphrase)
|
||||
passphrase = override_passphrase;
|
||||
else if (no_protection || !cache_nonce)
|
||||
else if ((flags & GENKEY_FLAG_NO_PROTECTION) || !cache_nonce)
|
||||
passphrase = NULL;
|
||||
else
|
||||
{
|
||||
|
@ -486,8 +550,8 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
|||
passphrase = passphrase_buffer;
|
||||
}
|
||||
|
||||
if (passphrase || no_protection)
|
||||
;
|
||||
if (passphrase || (flags & GENKEY_FLAG_NO_PROTECTION))
|
||||
; /* No need to ask for a passphrase. */
|
||||
else
|
||||
{
|
||||
rc = agent_ask_new_passphrase (ctrl,
|
||||
|
@ -532,11 +596,14 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
|||
gcry_sexp_release (s_key); s_key = NULL;
|
||||
|
||||
/* store the secret key */
|
||||
if (DBG_CRYPTO)
|
||||
log_debug ("storing private key\n");
|
||||
rc = store_key (s_private, passphrase, 0, ctrl->s2k_count, timestamp);
|
||||
if (!rc)
|
||||
if (opt.verbose)
|
||||
log_info ("storing %sprivate key\n",
|
||||
ctrl->ephemeral_mode?"ephemeral ":"");
|
||||
rc = store_key (ctrl, s_private, passphrase, 0, ctrl->s2k_count, timestamp);
|
||||
if (!rc && !ctrl->ephemeral_mode)
|
||||
{
|
||||
/* FIXME: or does it make sense to also cache passphrases in
|
||||
* ephemeral mode using a dedicated cache? */
|
||||
if (!cache_nonce)
|
||||
{
|
||||
char tmpbuf[12];
|
||||
|
@ -544,21 +611,23 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
|||
cache_nonce = bin2hex (tmpbuf, 12, NULL);
|
||||
}
|
||||
if (cache_nonce
|
||||
&& !no_protection
|
||||
&& !(flags & GENKEY_FLAG_NO_PROTECTION)
|
||||
&& !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
|
||||
passphrase, ctrl->cache_ttl_opt_preset))
|
||||
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
|
||||
if (preset && !no_protection)
|
||||
{
|
||||
unsigned char grip[20];
|
||||
char hexgrip[40+1];
|
||||
if (gcry_pk_get_keygrip (s_private, grip))
|
||||
{
|
||||
bin2hex(grip, 20, hexgrip);
|
||||
rc = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, passphrase,
|
||||
if ((flags & GENKEY_FLAG_PRESET)
|
||||
&& !(flags & GENKEY_FLAG_NO_PROTECTION))
|
||||
{
|
||||
unsigned char grip[20];
|
||||
char hexgrip[40+1];
|
||||
if (gcry_pk_get_keygrip (s_private, grip))
|
||||
{
|
||||
bin2hex(grip, 20, hexgrip);
|
||||
rc = agent_put_cache (ctrl, hexgrip,
|
||||
CACHE_MODE_ANY, passphrase,
|
||||
ctrl->cache_ttl_opt_preset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xfree (passphrase_buffer);
|
||||
passphrase_buffer = NULL;
|
||||
|
@ -607,7 +676,8 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
|||
if (passphrase_addr && *passphrase_addr)
|
||||
{
|
||||
/* Take an empty string as request not to protect the key. */
|
||||
err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
|
||||
err = store_key (ctrl, s_skey,
|
||||
**passphrase_addr? *passphrase_addr:NULL, 1,
|
||||
ctrl->s2k_count, 0);
|
||||
}
|
||||
else
|
||||
|
@ -623,7 +693,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
|||
L_("Please enter the new passphrase"),
|
||||
&pass);
|
||||
if (!err)
|
||||
err = store_key (s_skey, pass, 1, ctrl->s2k_count, 0);
|
||||
err = store_key (ctrl, s_skey, pass, 1, ctrl->s2k_count, 0);
|
||||
if (!err && passphrase_addr)
|
||||
*passphrase_addr = pass;
|
||||
else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue