mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01: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
@ -225,6 +225,17 @@ typedef struct ssh_control_file_s *ssh_control_file_t;
|
|||||||
/* Forward reference for local definitions in call-scd.c. */
|
/* Forward reference for local definitions in call-scd.c. */
|
||||||
struct daemon_local_s;
|
struct daemon_local_s;
|
||||||
|
|
||||||
|
/* Object to hold ephemeral secret keys. */
|
||||||
|
struct ephemeral_private_key_s
|
||||||
|
{
|
||||||
|
struct ephemeral_private_key_s *next;
|
||||||
|
unsigned char grip[KEYGRIP_LEN];
|
||||||
|
unsigned char *keybuf; /* Canon-s-exp with the private key (malloced). */
|
||||||
|
size_t keybuflen;
|
||||||
|
};
|
||||||
|
typedef struct ephemeral_private_key_s *ephemeral_private_key_t;
|
||||||
|
|
||||||
|
|
||||||
/* Collection of data per session (aka connection). */
|
/* Collection of data per session (aka connection). */
|
||||||
struct server_control_s
|
struct server_control_s
|
||||||
{
|
{
|
||||||
@ -246,6 +257,12 @@ struct server_control_s
|
|||||||
/* Private data of the daemon (call-XXX.c). */
|
/* Private data of the daemon (call-XXX.c). */
|
||||||
struct daemon_local_s *d_local[DAEMON_MAX_TYPE];
|
struct daemon_local_s *d_local[DAEMON_MAX_TYPE];
|
||||||
|
|
||||||
|
/* Linked list with ephemeral stored private keys. */
|
||||||
|
ephemeral_private_key_t ephemeral_keys;
|
||||||
|
|
||||||
|
/* If set functions will lookup keys in the ephemeral_keys list. */
|
||||||
|
int ephemeral_mode;
|
||||||
|
|
||||||
/* Environment settings for the connection. */
|
/* Environment settings for the connection. */
|
||||||
session_env_t session_env;
|
session_env_t session_env;
|
||||||
char *lc_ctype;
|
char *lc_ctype;
|
||||||
@ -452,7 +469,8 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
|
|||||||
/*-- findkey.c --*/
|
/*-- findkey.c --*/
|
||||||
gpg_error_t agent_modify_description (const char *in, const char *comment,
|
gpg_error_t agent_modify_description (const char *in, const char *comment,
|
||||||
const gcry_sexp_t key, char **result);
|
const gcry_sexp_t key, char **result);
|
||||||
gpg_error_t agent_write_private_key (const unsigned char *grip,
|
gpg_error_t agent_write_private_key (ctrl_t ctrl,
|
||||||
|
const unsigned char *grip,
|
||||||
const void *buffer, size_t length,
|
const void *buffer, size_t length,
|
||||||
int force,
|
int force,
|
||||||
const char *serialno, const char *keyref,
|
const char *serialno, const char *keyref,
|
||||||
@ -477,7 +495,7 @@ gpg_error_t agent_ssh_key_from_file (ctrl_t ctrl,
|
|||||||
gcry_sexp_t *result, int *r_order);
|
gcry_sexp_t *result, int *r_order);
|
||||||
int agent_pk_get_algo (gcry_sexp_t s_key);
|
int agent_pk_get_algo (gcry_sexp_t s_key);
|
||||||
int agent_is_tpm2_key(gcry_sexp_t s_key);
|
int agent_is_tpm2_key(gcry_sexp_t s_key);
|
||||||
int agent_key_available (const unsigned char *grip);
|
int agent_key_available (ctrl_t ctrl, const unsigned char *grip);
|
||||||
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
||||||
int *r_keytype,
|
int *r_keytype,
|
||||||
unsigned char **r_shadow_info,
|
unsigned char **r_shadow_info,
|
||||||
@ -485,7 +503,8 @@ gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
|
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
|
||||||
const unsigned char *grip,
|
const unsigned char *grip,
|
||||||
int force, int only_stubs);
|
int force, int only_stubs);
|
||||||
gpg_error_t agent_update_private_key (const unsigned char *grip, nvc_t pk);
|
gpg_error_t agent_update_private_key (ctrl_t ctrl,
|
||||||
|
const unsigned char *grip, nvc_t pk);
|
||||||
|
|
||||||
/*-- call-pinentry.c --*/
|
/*-- call-pinentry.c --*/
|
||||||
void initialize_module_call_pinentry (void);
|
void initialize_module_call_pinentry (void);
|
||||||
@ -541,15 +560,21 @@ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
|||||||
#define CHECK_CONSTRAINTS_NOT_EMPTY 1
|
#define CHECK_CONSTRAINTS_NOT_EMPTY 1
|
||||||
#define CHECK_CONSTRAINTS_NEW_SYMKEY 2
|
#define CHECK_CONSTRAINTS_NEW_SYMKEY 2
|
||||||
|
|
||||||
|
#define GENKEY_FLAG_NO_PROTECTION 1
|
||||||
|
#define GENKEY_FLAG_PRESET 2
|
||||||
|
|
||||||
|
void clear_ephemeral_keys (ctrl_t ctrl);
|
||||||
|
|
||||||
int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
|
int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
|
||||||
unsigned int flags,
|
unsigned int flags,
|
||||||
char **failed_constraint);
|
char **failed_constraint);
|
||||||
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
||||||
char **r_passphrase);
|
char **r_passphrase);
|
||||||
int agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
int agent_genkey (ctrl_t ctrl, unsigned int flags,
|
||||||
|
const char *cache_nonce, time_t timestamp,
|
||||||
const char *keyparam, size_t keyparmlen,
|
const char *keyparam, size_t keyparmlen,
|
||||||
int no_protection, const char *override_passphrase,
|
const char *override_passphrase,
|
||||||
int preset, membuf_t *outbuf);
|
membuf_t *outbuf);
|
||||||
gpg_error_t 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);
|
char **passphrase_addr);
|
||||||
|
|
||||||
@ -587,7 +612,7 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
|
|||||||
const unsigned char *s2ksalt,
|
const unsigned char *s2ksalt,
|
||||||
unsigned int s2kcount,
|
unsigned int s2kcount,
|
||||||
unsigned char *key, size_t keylen);
|
unsigned char *key, size_t keylen);
|
||||||
gpg_error_t agent_write_shadow_key (const unsigned char *grip,
|
gpg_error_t agent_write_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
||||||
const char *serialno, const char *keyid,
|
const char *serialno, const char *keyid,
|
||||||
const unsigned char *pkbuf, int force,
|
const unsigned char *pkbuf, int force,
|
||||||
const char *dispserialno);
|
const char *dispserialno);
|
||||||
|
@ -2430,14 +2430,14 @@ card_key_available (ctrl_t ctrl, const struct card_key_info_s *keyinfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
hex2bin (keyinfo->keygrip, grip, sizeof (grip));
|
hex2bin (keyinfo->keygrip, grip, sizeof (grip));
|
||||||
if ( agent_key_available (grip) )
|
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip) )
|
||||||
{
|
{
|
||||||
char *dispserialno;
|
char *dispserialno;
|
||||||
|
|
||||||
/* (Shadow)-key is not available in our key storage. */
|
/* (Shadow)-key is not available in our key storage. */
|
||||||
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
||||||
keyinfo->keygrip);
|
keyinfo->keygrip);
|
||||||
err = agent_write_shadow_key (grip, keyinfo->serialno,
|
err = agent_write_shadow_key (ctrl, grip, keyinfo->serialno,
|
||||||
keyinfo->idstr, pkbuf, 0, dispserialno);
|
keyinfo->idstr, pkbuf, 0, dispserialno);
|
||||||
xfree (dispserialno);
|
xfree (dispserialno);
|
||||||
if (err)
|
if (err)
|
||||||
@ -3222,7 +3222,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
|
|||||||
|
|
||||||
/* Check whether the key is already in our key storage. Don't do
|
/* Check whether the key is already in our key storage. Don't do
|
||||||
anything then besides (re-)adding it to sshcontrol. */
|
anything then besides (re-)adding it to sshcontrol. */
|
||||||
if ( !agent_key_available (key_grip_raw) )
|
if ( !agent_key_available (ctrl, key_grip_raw) )
|
||||||
goto key_exists; /* Yes, key is available. */
|
goto key_exists; /* Yes, key is available. */
|
||||||
|
|
||||||
err = ssh_key_extract_comment (key, &comment);
|
err = ssh_key_extract_comment (key, &comment);
|
||||||
@ -3286,7 +3286,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
|
|||||||
|
|
||||||
/* Store this key to our key storage. We do not store a creation
|
/* Store this key to our key storage. We do not store a creation
|
||||||
* timestamp because we simply do not know. */
|
* timestamp because we simply do not know. */
|
||||||
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0,
|
err = agent_write_private_key (ctrl, key_grip_raw, buffer, buffer_n, 0,
|
||||||
NULL, NULL, NULL, 0);
|
NULL, NULL, NULL, 0);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -251,6 +251,9 @@ reset_notify (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
clear_nonce_cache (ctrl);
|
clear_nonce_cache (ctrl);
|
||||||
|
|
||||||
|
/* Note that a RESET does not clear the ephemeral store becuase
|
||||||
|
* clients are used to issue a RESET on a connection. */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,15 +646,15 @@ static const char hlp_havekey[] =
|
|||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_havekey (assuan_context_t ctx, char *line)
|
cmd_havekey (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
ctrl_t ctrl;
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
unsigned char grip[20];
|
unsigned char grip[20];
|
||||||
char *p;
|
char *p;
|
||||||
int list_mode = 0; /* Less than 0 for no limit. */
|
int list_mode = 0; /* Less than 0 for no limit. */
|
||||||
int info_mode = 0;
|
int info_mode = 0;
|
||||||
int counter;
|
int counter;
|
||||||
char *dirname;
|
char *dirname = NULL;
|
||||||
gnupg_dir_t dir;
|
gnupg_dir_t dir = NULL;
|
||||||
gnupg_dirent_t dir_entry;
|
gnupg_dirent_t dir_entry;
|
||||||
char hexgrip[41];
|
char hexgrip[41];
|
||||||
struct card_key_info_s *keyinfo_on_cards, *l;
|
struct card_key_info_s *keyinfo_on_cards, *l;
|
||||||
@ -668,14 +671,11 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
line = skip_options (line);
|
line = skip_options (line);
|
||||||
|
|
||||||
|
|
||||||
if (info_mode)
|
if (info_mode)
|
||||||
{
|
{
|
||||||
int keytype;
|
int keytype;
|
||||||
const char *infostring;
|
const char *infostring;
|
||||||
|
|
||||||
ctrl = assuan_get_pointer (ctx);
|
|
||||||
|
|
||||||
err = parse_keygrip (ctx, line, grip);
|
err = parse_keygrip (ctx, line, grip);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -706,7 +706,7 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!agent_key_available (grip))
|
if (!agent_key_available (ctrl, grip))
|
||||||
return 0; /* Found. */
|
return 0; /* Found. */
|
||||||
|
|
||||||
while (*line && *line != ' ' && *line != '\t')
|
while (*line && *line != ' ' && *line != '\t')
|
||||||
@ -724,7 +724,6 @@ cmd_havekey (assuan_context_t ctx, char *line)
|
|||||||
/* List mode. */
|
/* List mode. */
|
||||||
dir = NULL;
|
dir = NULL;
|
||||||
dirname = NULL;
|
dirname = NULL;
|
||||||
ctrl = assuan_get_pointer (ctx);
|
|
||||||
|
|
||||||
if (ctrl->restricted)
|
if (ctrl->restricted)
|
||||||
{
|
{
|
||||||
@ -1117,26 +1116,27 @@ cmd_genkey (assuan_context_t ctx, char *line)
|
|||||||
{
|
{
|
||||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
int rc;
|
int rc;
|
||||||
int no_protection;
|
|
||||||
unsigned char *value = NULL;
|
unsigned char *value = NULL;
|
||||||
size_t valuelen;
|
size_t valuelen;
|
||||||
unsigned char *newpasswd = NULL;
|
unsigned char *newpasswd = NULL;
|
||||||
membuf_t outbuf;
|
membuf_t outbuf;
|
||||||
char *cache_nonce = NULL;
|
char *cache_nonce = NULL;
|
||||||
char *passwd_nonce = NULL;
|
char *passwd_nonce = NULL;
|
||||||
int opt_preset;
|
|
||||||
int opt_inq_passwd;
|
int opt_inq_passwd;
|
||||||
size_t n;
|
size_t n;
|
||||||
char *p, *pend;
|
char *p, *pend;
|
||||||
const char *s;
|
const char *s;
|
||||||
time_t opt_timestamp;
|
time_t opt_timestamp;
|
||||||
int c;
|
int c;
|
||||||
|
unsigned int flags = 0;
|
||||||
|
|
||||||
if (ctrl->restricted)
|
if (ctrl->restricted)
|
||||||
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
||||||
|
|
||||||
no_protection = has_option (line, "--no-protection");
|
if (has_option (line, "--no-protection"))
|
||||||
opt_preset = has_option (line, "--preset");
|
flags |= GENKEY_FLAG_NO_PROTECTION;
|
||||||
|
if (has_option (line, "--preset"))
|
||||||
|
flags |= GENKEY_FLAG_PRESET;
|
||||||
opt_inq_passwd = has_option (line, "--inq-passwd");
|
opt_inq_passwd = has_option (line, "--inq-passwd");
|
||||||
passwd_nonce = option_value (line, "--passwd-nonce");
|
passwd_nonce = option_value (line, "--passwd-nonce");
|
||||||
if (passwd_nonce)
|
if (passwd_nonce)
|
||||||
@ -1191,7 +1191,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
/* If requested, ask for the password to be used for the key. If
|
/* If requested, ask for the password to be used for the key. If
|
||||||
this is not used the regular Pinentry mechanism is used. */
|
this is not used the regular Pinentry mechanism is used. */
|
||||||
if (opt_inq_passwd && !no_protection)
|
if (opt_inq_passwd && !(flags & GENKEY_FLAG_NO_PROTECTION))
|
||||||
{
|
{
|
||||||
/* (N is used as a dummy) */
|
/* (N is used as a dummy) */
|
||||||
assuan_begin_confidential (ctx);
|
assuan_begin_confidential (ctx);
|
||||||
@ -1204,16 +1204,17 @@ cmd_genkey (assuan_context_t ctx, char *line)
|
|||||||
/* Empty password given - switch to no-protection mode. */
|
/* Empty password given - switch to no-protection mode. */
|
||||||
xfree (newpasswd);
|
xfree (newpasswd);
|
||||||
newpasswd = NULL;
|
newpasswd = NULL;
|
||||||
no_protection = 1;
|
flags |= GENKEY_FLAG_NO_PROTECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (passwd_nonce)
|
else if (passwd_nonce)
|
||||||
newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
|
newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
|
||||||
|
|
||||||
rc = agent_genkey (ctrl, cache_nonce, opt_timestamp,
|
|
||||||
(char*)value, valuelen, no_protection,
|
rc = agent_genkey (ctrl, flags, cache_nonce, opt_timestamp,
|
||||||
newpasswd, opt_preset, &outbuf);
|
(char*)value, valuelen,
|
||||||
|
newpasswd, &outbuf);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (newpasswd)
|
if (newpasswd)
|
||||||
@ -1317,7 +1318,7 @@ cmd_keyattr (assuan_context_t ctx, char *line)
|
|||||||
if (!err)
|
if (!err)
|
||||||
err = nvc_set_private_key (keymeta, s_key);
|
err = nvc_set_private_key (keymeta, s_key);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = agent_update_private_key (grip, keymeta);
|
err = agent_update_private_key (ctrl, grip, keymeta);
|
||||||
}
|
}
|
||||||
|
|
||||||
nvc_release (keymeta);
|
nvc_release (keymeta);
|
||||||
@ -1327,6 +1328,8 @@ cmd_keyattr (assuan_context_t ctx, char *line)
|
|||||||
leave:
|
leave:
|
||||||
return leave_cmd (ctx, err);
|
return leave_cmd (ctx, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_readkey[] =
|
static const char hlp_readkey[] =
|
||||||
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
|
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
|
||||||
@ -1390,7 +1393,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
/* (Shadow)-key is not available in our key storage. */
|
/* (Shadow)-key is not available in our key storage. */
|
||||||
char *dispserialno;
|
char *dispserialno;
|
||||||
@ -1398,7 +1401,7 @@ cmd_readkey (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, hexgrip);
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, hexgrip);
|
||||||
rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0,
|
rc = agent_write_shadow_key (ctrl, grip, serialno, keyid, pkbuf, 0,
|
||||||
dispserialno);
|
dispserialno);
|
||||||
xfree (dispserialno);
|
xfree (dispserialno);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -2934,7 +2937,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!force && !agent_key_available (grip))
|
if (!force && !agent_key_available (ctrl, grip))
|
||||||
err = gpg_error (GPG_ERR_EEXIST);
|
err = gpg_error (GPG_ERR_EEXIST);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2956,11 +2959,11 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
|||||||
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
|
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
|
||||||
ctrl->s2k_count);
|
ctrl->s2k_count);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
|
err = agent_write_private_key (ctrl, grip, finalkey, finalkeylen, force,
|
||||||
NULL, NULL, NULL, opt_timestamp);
|
NULL, NULL, NULL, opt_timestamp);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
err = agent_write_private_key (grip, key, realkeylen, force,
|
err = agent_write_private_key (ctrl, grip, key, realkeylen, force,
|
||||||
NULL, NULL, NULL, opt_timestamp);
|
NULL, NULL, NULL, opt_timestamp);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
@ -2979,7 +2982,8 @@ cmd_import_key (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
|
|
||||||
static const char hlp_export_key[] =
|
static const char hlp_export_key[] =
|
||||||
"EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp|--mode1003] <hexkeygrip>\n"
|
"EXPORT_KEY [--cache-nonce=<nonce>] \\\n"
|
||||||
|
" [--openpgp|--mode1003] <hexkeygrip>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Export a secret key from the key store. The key will be encrypted\n"
|
"Export a secret key from the key store. The key will be encrypted\n"
|
||||||
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
|
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
|
||||||
@ -2987,8 +2991,8 @@ static const char hlp_export_key[] =
|
|||||||
"prior to using this command. The function takes the keygrip as argument.\n"
|
"prior to using this command. The function takes the keygrip as argument.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"If --openpgp is used, the secret key material will be exported in RFC 4880\n"
|
"If --openpgp is used, the secret key material will be exported in RFC 4880\n"
|
||||||
"compatible passphrase-protected form. If --mode1003 is use the secret key\n"
|
"compatible passphrase-protected form. In --mode1003 the secret key\n"
|
||||||
"is exported as s-expression as storred locally. Without those options,\n"
|
"is exported as s-expression as stored locally. Without those options,\n"
|
||||||
"the secret key material will be exported in the clear (after prompting\n"
|
"the secret key material will be exported in the clear (after prompting\n"
|
||||||
"the user to unlock it, if needed).\n";
|
"the user to unlock it, if needed).\n";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
@ -3045,7 +3049,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
|
|||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_NO_SECKEY);
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -3257,9 +3261,9 @@ cmd_keytocard (assuan_context_t ctx, char *line)
|
|||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err =gpg_error (GPG_ERR_NO_SECKEY);
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3577,7 +3581,7 @@ cmd_keytotpm (assuan_context_t ctx, char *line)
|
|||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (agent_key_available (grip))
|
if (agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err =gpg_error (GPG_ERR_NO_SECKEY);
|
err =gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -3869,6 +3873,7 @@ static const char hlp_getinfo[] =
|
|||||||
" getenv NAME - Return value of envvar NAME.\n"
|
" getenv NAME - Return value of envvar NAME.\n"
|
||||||
" connections - Return number of active connections.\n"
|
" connections - Return number of active connections.\n"
|
||||||
" jent_active - Returns OK if Libgcrypt's JENT is active.\n"
|
" jent_active - Returns OK if Libgcrypt's JENT is active.\n"
|
||||||
|
" ephemeral - Returns OK if the connection is in ephemeral mode.\n"
|
||||||
" restricted - Returns OK if the connection is in restricted mode.\n"
|
" restricted - Returns OK if the connection is in restricted mode.\n"
|
||||||
" cmd_has_option CMD OPT\n"
|
" cmd_has_option CMD OPT\n"
|
||||||
" - Returns OK if command CMD has option OPT.\n";
|
" - Returns OK if command CMD has option OPT.\n";
|
||||||
@ -3922,6 +3927,10 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
|||||||
snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
|
snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
|
||||||
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
|
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (line, "ephemeral"))
|
||||||
|
{
|
||||||
|
rc = ctrl->ephemeral_mode? 0 : gpg_error (GPG_ERR_FALSE);
|
||||||
|
}
|
||||||
else if (!strcmp (line, "restricted"))
|
else if (!strcmp (line, "restricted"))
|
||||||
{
|
{
|
||||||
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE);
|
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE);
|
||||||
@ -4078,6 +4087,10 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
|
|||||||
ctrl->server_local->allow_fully_canceled =
|
ctrl->server_local->allow_fully_canceled =
|
||||||
gnupg_compare_version (value, "2.1.0");
|
gnupg_compare_version (value, "2.1.0");
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (key, "ephemeral"))
|
||||||
|
{
|
||||||
|
ctrl->ephemeral_mode = *value? atoi (value) : 0;
|
||||||
|
}
|
||||||
else if (ctrl->restricted)
|
else if (ctrl->restricted)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_FORBIDDEN);
|
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||||
|
@ -969,7 +969,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
|
|||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if (!dontcare_exist && !from_native && !agent_key_available (grip))
|
if (!dontcare_exist && !from_native && !agent_key_available (ctrl, grip))
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_EEXIST);
|
err = gpg_error (GPG_ERR_EEXIST);
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -1147,14 +1147,16 @@ convert_from_openpgp_native (ctrl_t ctrl,
|
|||||||
if (!agent_protect (*r_key, passphrase,
|
if (!agent_protect (*r_key, passphrase,
|
||||||
&protectedkey, &protectedkeylen,
|
&protectedkey, &protectedkeylen,
|
||||||
ctrl->s2k_count))
|
ctrl->s2k_count))
|
||||||
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
|
agent_write_private_key (ctrl, grip,
|
||||||
NULL, NULL, NULL, 0);
|
protectedkey,
|
||||||
|
protectedkeylen,
|
||||||
|
1, NULL, NULL, NULL, 0);
|
||||||
xfree (protectedkey);
|
xfree (protectedkey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Empty passphrase: write key without protection. */
|
/* Empty passphrase: write key without protection. */
|
||||||
agent_write_private_key (grip,
|
agent_write_private_key (ctrl, grip,
|
||||||
*r_key,
|
*r_key,
|
||||||
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
|
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
|
||||||
1, NULL, NULL, NULL, 0);
|
1, NULL, NULL, NULL, 0);
|
||||||
|
@ -57,7 +57,7 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
|
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
|
||||||
err = agent_write_private_key (grip, shdkey, len, 1 /*force*/,
|
err = agent_write_private_key (ctrl, grip, shdkey, len, 1 /*force*/,
|
||||||
NULL, NULL, NULL, 0);
|
NULL, NULL, NULL, 0);
|
||||||
xfree (shdkey);
|
xfree (shdkey);
|
||||||
if (err)
|
if (err)
|
||||||
@ -70,7 +70,7 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
return GPG_ERR_ENOMEM;
|
return GPG_ERR_ENOMEM;
|
||||||
|
|
||||||
gcry_sexp_sprint(s_key, GCRYSEXP_FMT_CANON, pkbuf, len);
|
gcry_sexp_sprint(s_key, GCRYSEXP_FMT_CANON, pkbuf, len);
|
||||||
err1 = agent_write_private_key (grip, pkbuf, len, 1 /*force*/,
|
err1 = agent_write_private_key (ctrl, grip, pkbuf, len, 1 /*force*/,
|
||||||
NULL, NULL, NULL, 0);
|
NULL, NULL, NULL, 0);
|
||||||
xfree(pkbuf);
|
xfree(pkbuf);
|
||||||
if (err1)
|
if (err1)
|
||||||
|
380
agent/findkey.c
380
agent/findkey.c
@ -40,7 +40,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static gpg_error_t read_key_file (const unsigned char *grip,
|
static gpg_error_t read_key_file (ctrl_t ctrl, const unsigned char *grip,
|
||||||
gcry_sexp_t *result, nvc_t *r_keymeta,
|
gcry_sexp_t *result, nvc_t *r_keymeta,
|
||||||
char **r_orig_key_value);
|
char **r_orig_key_value);
|
||||||
static gpg_error_t is_shadowed_key (gcry_sexp_t s_skey);
|
static gpg_error_t is_shadowed_key (gcry_sexp_t s_skey);
|
||||||
@ -73,6 +73,30 @@ fname_from_keygrip (const unsigned char *grip, int for_new)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper until we have a "wipe" mode flag in es_fopen. */
|
||||||
|
static void
|
||||||
|
wipe_and_fclose (estream_t fp)
|
||||||
|
{
|
||||||
|
void *blob;
|
||||||
|
size_t blob_size;
|
||||||
|
|
||||||
|
if (!fp)
|
||||||
|
;
|
||||||
|
else if (es_fclose_snatch (fp, &blob, &blob_size))
|
||||||
|
{
|
||||||
|
log_error ("error wiping buffer during fclose\n");
|
||||||
|
es_fclose (fp);
|
||||||
|
}
|
||||||
|
else if (blob)
|
||||||
|
{
|
||||||
|
wipememory (blob, blob_size);
|
||||||
|
gpgrt_free (blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Replace all linefeeds in STRING by "%0A" and return a new malloced
|
/* Replace all linefeeds in STRING by "%0A" and return a new malloced
|
||||||
* string. May return NULL on memory error. */
|
* string. May return NULL on memory error. */
|
||||||
static char *
|
static char *
|
||||||
@ -110,7 +134,8 @@ linefeed_to_percent0A (const char *string)
|
|||||||
* TIMESTAMP is not zero and the key does not yet exists it will be
|
* TIMESTAMP is not zero and the key does not yet exists it will be
|
||||||
* recorded as creation date. */
|
* recorded as creation date. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_write_private_key (const unsigned char *grip,
|
agent_write_private_key (ctrl_t ctrl,
|
||||||
|
const unsigned char *grip,
|
||||||
const void *buffer, size_t length, int force,
|
const void *buffer, size_t length, int force,
|
||||||
const char *serialno, const char *keyref,
|
const char *serialno, const char *keyref,
|
||||||
const char *dispserialno,
|
const char *dispserialno,
|
||||||
@ -120,7 +145,7 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
char *fname = NULL;
|
char *fname = NULL;
|
||||||
char *tmpfname = NULL;
|
char *tmpfname = NULL;
|
||||||
estream_t fp = NULL;
|
estream_t fp = NULL;
|
||||||
int newkey;
|
int newkey = 0;
|
||||||
nvc_t pk = NULL;
|
nvc_t pk = NULL;
|
||||||
gcry_sexp_t key = NULL;
|
gcry_sexp_t key = NULL;
|
||||||
int removetmp = 0;
|
int removetmp = 0;
|
||||||
@ -134,11 +159,13 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
const char *s;
|
const char *s;
|
||||||
int force_modify = 0;
|
int force_modify = 0;
|
||||||
|
|
||||||
fname = fname_from_keygrip (grip, 0);
|
fname = (ctrl->ephemeral_mode
|
||||||
|
? xtrystrdup ("[ephemeral key store]")
|
||||||
|
: fname_from_keygrip (grip, 0));
|
||||||
if (!fname)
|
if (!fname)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
|
|
||||||
err = read_key_file (grip, &key, &pk, &orig_key_value);
|
err = read_key_file (ctrl, grip, &key, &pk, &orig_key_value);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
||||||
@ -289,43 +316,99 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a temporary file for writing. */
|
if (ctrl->ephemeral_mode)
|
||||||
tmpfname = fname_from_keygrip (grip, 1);
|
|
||||||
fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL;
|
|
||||||
if (!fp)
|
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
ephemeral_private_key_t ek;
|
||||||
log_error ("can't create '%s': %s\n", tmpfname, gpg_strerror (err));
|
void *blob;
|
||||||
goto leave;
|
size_t blobsize;
|
||||||
}
|
|
||||||
|
|
||||||
err = nvc_write (pk, fp);
|
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
|
||||||
if (!err && es_fflush (fp))
|
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
|
||||||
err = gpg_error_from_syserror ();
|
break;
|
||||||
if (err)
|
if (!ek)
|
||||||
{
|
{
|
||||||
log_error ("error writing '%s': %s\n", tmpfname, gpg_strerror (err));
|
ek = xtrycalloc (1, sizeof *ek);
|
||||||
removetmp = 1;
|
if (!ek)
|
||||||
goto leave;
|
{
|
||||||
}
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
memcpy (ek->grip, grip, KEYGRIP_LEN);
|
||||||
|
ek->next = ctrl->ephemeral_keys;
|
||||||
|
ctrl->ephemeral_keys = ek;
|
||||||
|
}
|
||||||
|
|
||||||
if (es_fclose (fp))
|
fp = es_fopenmem (0, "wb,wipe");
|
||||||
{
|
if (!fp)
|
||||||
err = gpg_error_from_syserror ();
|
{
|
||||||
log_error ("error closing '%s': %s\n", tmpfname, gpg_strerror (err));
|
err = gpg_error_from_syserror ();
|
||||||
removetmp = 1;
|
log_error ("can't open memory stream: %s\n", gpg_strerror (err));
|
||||||
goto leave;
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvc_write (pk, fp);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error writing to memory stream: %s\n",gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es_fclose_snatch (fp, &blob, &blobsize) || !blob)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error getting memory stream buffer: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
/* Closing right away so that we don't try another snatch in
|
||||||
|
* the cleanup. */
|
||||||
|
es_fclose (fp);
|
||||||
|
fp = NULL;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
fp = NULL;
|
||||||
|
xfree (ek->keybuf);
|
||||||
|
ek->keybuf = blob;
|
||||||
|
ek->keybuflen = blobsize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fp = NULL;
|
|
||||||
|
|
||||||
err = gnupg_rename_file (tmpfname, fname, &blocksigs);
|
|
||||||
if (err)
|
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
/* Create a temporary file for writing. */
|
||||||
log_error ("error renaming '%s': %s\n", tmpfname, gpg_strerror (err));
|
tmpfname = fname_from_keygrip (grip, 1);
|
||||||
removetmp = 1;
|
fp = tmpfname ? es_fopen (tmpfname, "wbx,mode=-rw") : NULL;
|
||||||
goto leave;
|
if (!fp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("can't create '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvc_write (pk, fp);
|
||||||
|
if (!err && es_fflush (fp))
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error writing '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
|
removetmp = 1;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es_fclose (fp))
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error closing '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
|
removetmp = 1;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fp = NULL;
|
||||||
|
|
||||||
|
err = gnupg_rename_file (tmpfname, fname, &blocksigs);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error renaming '%s': %s\n", tmpfname, gpg_strerror (err));
|
||||||
|
removetmp = 1;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bump_key_eventcounter ();
|
bump_key_eventcounter ();
|
||||||
@ -333,7 +416,10 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
leave:
|
leave:
|
||||||
if (blocksigs)
|
if (blocksigs)
|
||||||
gnupg_unblock_all_signals ();
|
gnupg_unblock_all_signals ();
|
||||||
es_fclose (fp);
|
if (ctrl->ephemeral_mode)
|
||||||
|
wipe_and_fclose (fp);
|
||||||
|
else
|
||||||
|
es_fclose (fp);
|
||||||
if (removetmp && tmpfname)
|
if (removetmp && tmpfname)
|
||||||
gnupg_remove (tmpfname);
|
gnupg_remove (tmpfname);
|
||||||
xfree (orig_key_value);
|
xfree (orig_key_value);
|
||||||
@ -350,7 +436,7 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
|
|
||||||
|
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
agent_update_private_key (ctrl_t ctrl, const unsigned char *grip, nvc_t pk)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char *fname0 = NULL; /* The existing file name. */
|
char *fname0 = NULL; /* The existing file name. */
|
||||||
@ -359,6 +445,57 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
|||||||
int removetmp = 0;
|
int removetmp = 0;
|
||||||
int blocksigs = 0;
|
int blocksigs = 0;
|
||||||
|
|
||||||
|
if (ctrl->ephemeral_mode)
|
||||||
|
{
|
||||||
|
ephemeral_private_key_t ek;
|
||||||
|
void *blob;
|
||||||
|
size_t blobsize;
|
||||||
|
|
||||||
|
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
|
||||||
|
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
|
||||||
|
break;
|
||||||
|
if (!ek)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_ENOENT);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = es_fopenmem (0, "wbx,wipe");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("can't open memory stream: %s\n", gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = nvc_write (pk, fp);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
log_error ("error writing to memory stream: %s\n",gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (es_fclose_snatch (fp, &blob, &blobsize) || !blob)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("error getting memory stream buffer: %s\n",
|
||||||
|
gpg_strerror (err));
|
||||||
|
/* Closing right away so that we don't try another snatch in
|
||||||
|
* the cleanup. */
|
||||||
|
es_fclose (fp);
|
||||||
|
fp = NULL;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
fp = NULL;
|
||||||
|
/* No need to revisit the linked list because the found EK is
|
||||||
|
* not expected to change due to the other syscalls above. */
|
||||||
|
xfree (ek->keybuf);
|
||||||
|
ek->keybuf = blob;
|
||||||
|
ek->keybuflen = blobsize;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fname0 = fname_from_keygrip (grip, 0);
|
fname0 = fname_from_keygrip (grip, 0);
|
||||||
if (!fname0)
|
if (!fname0)
|
||||||
{
|
{
|
||||||
@ -404,7 +541,10 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
|
|||||||
leave:
|
leave:
|
||||||
if (blocksigs)
|
if (blocksigs)
|
||||||
gnupg_unblock_all_signals ();
|
gnupg_unblock_all_signals ();
|
||||||
es_fclose (fp);
|
if (ctrl->ephemeral_mode)
|
||||||
|
wipe_and_fclose (fp);
|
||||||
|
else
|
||||||
|
es_fclose (fp);
|
||||||
if (removetmp && fname)
|
if (removetmp && fname)
|
||||||
gnupg_remove (fname);
|
gnupg_remove (fname);
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
@ -888,17 +1028,17 @@ unprotect (ctrl_t ctrl, const char *cache_nonce, const char *desc_text,
|
|||||||
* caller must free it. On failure returns an error code and stores
|
* caller must free it. On failure returns an error code and stores
|
||||||
* NULL at RESULT and R_KEYMETA. */
|
* NULL at RESULT and R_KEYMETA. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
|
read_key_file (ctrl_t ctrl, const unsigned char *grip,
|
||||||
char **r_orig_key_value)
|
gcry_sexp_t *result, nvc_t *r_keymeta, char **r_orig_key_value)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char *fname;
|
char *fname;
|
||||||
estream_t fp;
|
estream_t fp = NULL;
|
||||||
struct stat st;
|
unsigned char *buf = NULL;
|
||||||
unsigned char *buf;
|
|
||||||
size_t buflen, erroff;
|
size_t buflen, erroff;
|
||||||
gcry_sexp_t s_skey;
|
nvc_t pk = NULL;
|
||||||
char first;
|
char first;
|
||||||
|
size_t keybuflen;
|
||||||
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
if (r_keymeta)
|
if (r_keymeta)
|
||||||
@ -906,19 +1046,42 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
|
|||||||
if (r_orig_key_value)
|
if (r_orig_key_value)
|
||||||
*r_orig_key_value = NULL;
|
*r_orig_key_value = NULL;
|
||||||
|
|
||||||
fname = fname_from_keygrip (grip, 0);
|
fname = (ctrl->ephemeral_mode
|
||||||
|
? xtrystrdup ("[ephemeral key store]")
|
||||||
|
: fname_from_keygrip (grip, 0));
|
||||||
if (!fname)
|
if (!fname)
|
||||||
{
|
{
|
||||||
return gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
&& ek->keybuf && ek->keybuflen)
|
||||||
|
break;
|
||||||
|
if (!ek || !ek->keybuf || !ek->keybuflen)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_ENOENT);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
keybuflen = ek->keybuflen;
|
||||||
|
fp = es_fopenmem_init (0, "rb", ek->keybuf, ek->keybuflen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keybuflen = 0; /* Indicates that this is not ephemeral mode. */
|
||||||
|
fp = es_fopen (fname, "rb");
|
||||||
}
|
}
|
||||||
fp = es_fopen (fname, "rb");
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
if (gpg_err_code (err) != GPG_ERR_ENOENT)
|
if (gpg_err_code (err) != GPG_ERR_ENOENT)
|
||||||
log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
|
log_error ("can't open '%s': %s\n", fname, gpg_strerror (err));
|
||||||
xfree (fname);
|
goto leave;
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (es_fread (&first, 1, 1, fp) != 1)
|
if (es_fread (&first, 1, 1, fp) != 1)
|
||||||
@ -926,28 +1089,22 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
|
|||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
log_error ("error reading first byte from '%s': %s\n",
|
log_error ("error reading first byte from '%s': %s\n",
|
||||||
fname, gpg_strerror (err));
|
fname, gpg_strerror (err));
|
||||||
xfree (fname);
|
goto leave;
|
||||||
es_fclose (fp);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (es_fseek (fp, 0, SEEK_SET))
|
if (es_fseek (fp, 0, SEEK_SET))
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
log_error ("error seeking in '%s': %s\n", fname, gpg_strerror (err));
|
log_error ("error seeking in '%s': %s\n", fname, gpg_strerror (err));
|
||||||
xfree (fname);
|
goto leave;
|
||||||
es_fclose (fp);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first != '(')
|
if (first != '(')
|
||||||
{
|
{
|
||||||
/* Key is in extended format. */
|
/* Key is in extended format. */
|
||||||
nvc_t pk = NULL;
|
|
||||||
int line;
|
int line;
|
||||||
|
|
||||||
err = nvc_parse_private_key (&pk, &line, fp);
|
err = nvc_parse_private_key (&pk, &line, fp);
|
||||||
es_fclose (fp);
|
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
log_error ("error parsing '%s' line %d: %s\n",
|
log_error ("error parsing '%s' line %d: %s\n",
|
||||||
@ -969,9 +1126,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
|
|||||||
if (!*r_orig_key_value)
|
if (!*r_orig_key_value)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
nvc_release (pk);
|
goto leave;
|
||||||
xfree (fname);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -979,35 +1134,31 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!err && r_keymeta)
|
goto leave; /* Ready. */
|
||||||
*r_keymeta = pk;
|
|
||||||
else
|
|
||||||
nvc_release (pk);
|
|
||||||
xfree (fname);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fstat (es_fileno (fp), &st))
|
if (keybuflen)
|
||||||
|
buflen = keybuflen;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
struct stat st;
|
||||||
log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
|
|
||||||
xfree (fname);
|
if (fstat (es_fileno (fp), &st))
|
||||||
es_fclose (fp);
|
{
|
||||||
return err;
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error ("can't stat '%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
buflen = st.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
buflen = st.st_size;
|
|
||||||
buf = xtrymalloc (buflen+1);
|
buf = xtrymalloc (buflen+1);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
log_error ("error allocating %zu bytes for '%s': %s\n",
|
log_error ("error allocating %zu bytes for '%s': %s\n",
|
||||||
buflen, fname, gpg_strerror (err));
|
buflen, fname, gpg_strerror (err));
|
||||||
xfree (fname);
|
goto leave;
|
||||||
es_fclose (fp);
|
|
||||||
xfree (buf);
|
|
||||||
return err;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (es_fread (buf, buflen, 1, fp) != 1)
|
if (es_fread (buf, buflen, 1, fp) != 1)
|
||||||
@ -1015,25 +1166,32 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result, nvc_t *r_keymeta,
|
|||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
log_error ("error reading %zu bytes from '%s': %s\n",
|
log_error ("error reading %zu bytes from '%s': %s\n",
|
||||||
buflen, fname, gpg_strerror (err));
|
buflen, fname, gpg_strerror (err));
|
||||||
xfree (fname);
|
goto leave;
|
||||||
es_fclose (fp);
|
|
||||||
xfree (buf);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the file into a gcrypt S-expression object. */
|
/* Convert the file into a gcrypt S-expression object. */
|
||||||
err = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
|
{
|
||||||
xfree (fname);
|
gcry_sexp_t s_skey;
|
||||||
es_fclose (fp);
|
|
||||||
xfree (buf);
|
err = gcry_sexp_sscan (&s_skey, &erroff, (char*)buf, buflen);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
|
||||||
log_error ("failed to build S-Exp (off=%u): %s\n",
|
log_error ("failed to build S-Exp (off=%u): %s\n",
|
||||||
(unsigned int)erroff, gpg_strerror (err));
|
(unsigned int)erroff, gpg_strerror (err));
|
||||||
return err;
|
else
|
||||||
}
|
*result = s_skey;
|
||||||
*result = s_skey;
|
}
|
||||||
return 0;
|
|
||||||
|
leave:
|
||||||
|
if (!err && r_keymeta)
|
||||||
|
*r_keymeta = pk;
|
||||||
|
else
|
||||||
|
nvc_release (pk);
|
||||||
|
if (ctrl->ephemeral_mode)
|
||||||
|
wipe_and_fclose (fp);
|
||||||
|
else
|
||||||
|
es_fclose (fp);
|
||||||
|
xfree (fname);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1226,7 +1384,8 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
|
|||||||
if (!grip && !ctrl->have_keygrip)
|
if (!grip && !ctrl->have_keygrip)
|
||||||
return gpg_error (GPG_ERR_NO_SECKEY);
|
return gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
|
||||||
err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta, NULL);
|
err = read_key_file (ctrl, grip? grip : ctrl->keygrip,
|
||||||
|
&s_skey, &keymeta, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
||||||
@ -1485,7 +1644,7 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
|
|
||||||
err = read_key_file (grip, &s_skey, r_keymeta, NULL);
|
err = read_key_file (ctrl, grip, &s_skey, r_keymeta, NULL);
|
||||||
if (!err)
|
if (!err)
|
||||||
*result = s_skey;
|
*result = s_skey;
|
||||||
return err;
|
return err;
|
||||||
@ -1528,7 +1687,7 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
if (r_sshorder)
|
if (r_sshorder)
|
||||||
*r_sshorder = 0;
|
*r_sshorder = 0;
|
||||||
|
|
||||||
err = read_key_file (grip, &s_skey, for_ssh? &keymeta : NULL, NULL);
|
err = read_key_file (ctrl, grip, &s_skey, for_ssh? &keymeta : NULL, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
@ -1656,13 +1815,23 @@ agent_ssh_key_from_file (ctrl_t ctrl,
|
|||||||
|
|
||||||
|
|
||||||
/* Check whether the secret key identified by GRIP is available.
|
/* Check whether the secret key identified by GRIP is available.
|
||||||
Returns 0 is the key is available. */
|
Returns 0 is the key is available. */
|
||||||
int
|
int
|
||||||
agent_key_available (const unsigned char *grip)
|
agent_key_available (ctrl_t ctrl, const unsigned char *grip)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
char *fname;
|
char *fname;
|
||||||
char hexgrip[40+4+1];
|
char hexgrip[40+4+1];
|
||||||
|
ephemeral_private_key_t ek;
|
||||||
|
|
||||||
|
if (ctrl && ctrl->ephemeral_mode)
|
||||||
|
{
|
||||||
|
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
|
||||||
|
if (!memcmp (ek->grip, grip, KEYGRIP_LEN)
|
||||||
|
&& ek->keybuf && ek->keybuflen)
|
||||||
|
return 0;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
strcpy (hexgrip+40, ".key");
|
strcpy (hexgrip+40, ".key");
|
||||||
@ -1675,7 +1844,6 @@ agent_key_available (const unsigned char *grip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the information about the secret key specified by the binary
|
/* Return the information about the secret key specified by the binary
|
||||||
keygrip GRIP. If the key is a shadowed one the shadow information
|
keygrip GRIP. If the key is a shadowed one the shadow information
|
||||||
will be stored at the address R_SHADOW_INFO as an allocated
|
will be stored at the address R_SHADOW_INFO as an allocated
|
||||||
@ -1700,7 +1868,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
{
|
{
|
||||||
gcry_sexp_t sexp;
|
gcry_sexp_t sexp;
|
||||||
|
|
||||||
err = read_key_file (grip, &sexp, NULL, NULL);
|
err = read_key_file (ctrl, grip, &sexp, NULL, NULL);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
||||||
@ -1784,7 +1952,13 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
|
|||||||
char *default_desc = NULL;
|
char *default_desc = NULL;
|
||||||
int key_type;
|
int key_type;
|
||||||
|
|
||||||
err = read_key_file (grip, &s_skey, NULL, NULL);
|
if (ctrl->ephemeral_mode)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = read_key_file (ctrl, grip, &s_skey, NULL, NULL);
|
||||||
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
||||||
err = gpg_error (GPG_ERR_NO_SECKEY);
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
if (err)
|
if (err)
|
||||||
@ -1885,7 +2059,7 @@ agent_delete_key (ctrl_t ctrl, const char *desc_text,
|
|||||||
card's SERIALNO and the IDSTRING. With FORCE passed as true an
|
card's SERIALNO and the IDSTRING. With FORCE passed as true an
|
||||||
existing key with the given GRIP will get overwritten. */
|
existing key with the given GRIP will get overwritten. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_write_shadow_key (const unsigned char *grip,
|
agent_write_shadow_key (ctrl_t ctrl, const unsigned char *grip,
|
||||||
const char *serialno, const char *keyid,
|
const char *serialno, const char *keyid,
|
||||||
const unsigned char *pkbuf, int force,
|
const unsigned char *pkbuf, int force,
|
||||||
const char *dispserialno)
|
const char *dispserialno)
|
||||||
@ -1915,7 +2089,7 @@ agent_write_shadow_key (const unsigned char *grip,
|
|||||||
}
|
}
|
||||||
|
|
||||||
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
|
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
|
||||||
err = agent_write_private_key (grip, shdkey, len, force,
|
err = agent_write_private_key (ctrl, grip, shdkey, len, force,
|
||||||
serialno, keyid, dispserialno, 0);
|
serialno, keyid, dispserialno, 0);
|
||||||
xfree (shdkey);
|
xfree (shdkey);
|
||||||
if (err)
|
if (err)
|
||||||
|
156
agent/genkey.c
156
agent/genkey.c
@ -30,14 +30,36 @@
|
|||||||
#include "../common/exechelp.h"
|
#include "../common/exechelp.h"
|
||||||
#include "../common/sysutils.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)
|
unsigned long s2k_count, time_t timestamp)
|
||||||
{
|
{
|
||||||
int rc;
|
gpg_error_t err;
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char grip[20];
|
unsigned char grip[KEYGRIP_LEN];
|
||||||
|
|
||||||
if ( !gcry_pk_get_keygrip (private, grip) )
|
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);
|
log_assert (len);
|
||||||
buf = gcry_malloc_secure (len);
|
buf = gcry_malloc_secure (len);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
return out_of_core ();
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
|
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
|
||||||
log_assert (len);
|
log_assert (len);
|
||||||
|
|
||||||
@ -57,20 +82,56 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
|
|||||||
{
|
{
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
|
||||||
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
err = agent_protect (buf, passphrase, &p, &len, s2k_count);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
goto leave;
|
||||||
xfree (buf);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
xfree (buf);
|
xfree (buf);
|
||||||
buf = p;
|
buf = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = agent_write_private_key (grip, buf, len, force,
|
if (ctrl->ephemeral_mode)
|
||||||
NULL, NULL, NULL, timestamp);
|
{
|
||||||
|
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);
|
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
|
/* Generate a new keypair according to the parameters given in
|
||||||
KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
|
* 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
|
* using the cache nonce. If NO_PROTECTION is true the key will not
|
||||||
be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
|
* be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
|
||||||
passphrase will be used for the new key. If TIMESTAMP is not zero
|
* 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
|
* it will be recorded as creation date of the key (unless extended
|
||||||
format is disabled) . */
|
* 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
|
int
|
||||||
agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
agent_genkey (ctrl_t ctrl, unsigned int flags,
|
||||||
const char *keyparam, size_t keyparamlen, int no_protection,
|
const char *cache_nonce, time_t timestamp,
|
||||||
const char *override_passphrase, int preset, membuf_t *outbuf)
|
const char *keyparam, size_t keyparamlen,
|
||||||
|
const char *override_passphrase, membuf_t *outbuf)
|
||||||
{
|
{
|
||||||
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
|
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
|
||||||
char *passphrase_buffer = NULL;
|
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. */
|
/* Get the passphrase now, cause key generation may take a while. */
|
||||||
if (override_passphrase)
|
if (override_passphrase)
|
||||||
passphrase = override_passphrase;
|
passphrase = override_passphrase;
|
||||||
else if (no_protection || !cache_nonce)
|
else if ((flags & GENKEY_FLAG_NO_PROTECTION) || !cache_nonce)
|
||||||
passphrase = NULL;
|
passphrase = NULL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -486,8 +550,8 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
|
|||||||
passphrase = passphrase_buffer;
|
passphrase = passphrase_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passphrase || no_protection)
|
if (passphrase || (flags & GENKEY_FLAG_NO_PROTECTION))
|
||||||
;
|
; /* No need to ask for a passphrase. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rc = agent_ask_new_passphrase (ctrl,
|
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;
|
gcry_sexp_release (s_key); s_key = NULL;
|
||||||
|
|
||||||
/* store the secret key */
|
/* store the secret key */
|
||||||
if (DBG_CRYPTO)
|
if (opt.verbose)
|
||||||
log_debug ("storing private key\n");
|
log_info ("storing %sprivate key\n",
|
||||||
rc = store_key (s_private, passphrase, 0, ctrl->s2k_count, timestamp);
|
ctrl->ephemeral_mode?"ephemeral ":"");
|
||||||
if (!rc)
|
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)
|
if (!cache_nonce)
|
||||||
{
|
{
|
||||||
char tmpbuf[12];
|
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);
|
cache_nonce = bin2hex (tmpbuf, 12, NULL);
|
||||||
}
|
}
|
||||||
if (cache_nonce
|
if (cache_nonce
|
||||||
&& !no_protection
|
&& !(flags & GENKEY_FLAG_NO_PROTECTION)
|
||||||
&& !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
|
&& !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
|
||||||
passphrase, ctrl->cache_ttl_opt_preset))
|
passphrase, ctrl->cache_ttl_opt_preset))
|
||||||
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
|
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
|
||||||
if (preset && !no_protection)
|
if ((flags & GENKEY_FLAG_PRESET)
|
||||||
{
|
&& !(flags & GENKEY_FLAG_NO_PROTECTION))
|
||||||
unsigned char grip[20];
|
{
|
||||||
char hexgrip[40+1];
|
unsigned char grip[20];
|
||||||
if (gcry_pk_get_keygrip (s_private, grip))
|
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,
|
bin2hex(grip, 20, hexgrip);
|
||||||
|
rc = agent_put_cache (ctrl, hexgrip,
|
||||||
|
CACHE_MODE_ANY, passphrase,
|
||||||
ctrl->cache_ttl_opt_preset);
|
ctrl->cache_ttl_opt_preset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xfree (passphrase_buffer);
|
xfree (passphrase_buffer);
|
||||||
passphrase_buffer = NULL;
|
passphrase_buffer = NULL;
|
||||||
@ -607,7 +676,8 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
|||||||
if (passphrase_addr && *passphrase_addr)
|
if (passphrase_addr && *passphrase_addr)
|
||||||
{
|
{
|
||||||
/* Take an empty string as request not to protect the key. */
|
/* 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);
|
ctrl->s2k_count, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -623,7 +693,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
|
|||||||
L_("Please enter the new passphrase"),
|
L_("Please enter the new passphrase"),
|
||||||
&pass);
|
&pass);
|
||||||
if (!err)
|
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)
|
if (!err && passphrase_addr)
|
||||||
*passphrase_addr = pass;
|
*passphrase_addr = pass;
|
||||||
else
|
else
|
||||||
|
@ -1989,6 +1989,7 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
|
|||||||
{
|
{
|
||||||
unregister_progress_cb ();
|
unregister_progress_cb ();
|
||||||
session_env_release (ctrl->session_env);
|
session_env_release (ctrl->session_env);
|
||||||
|
clear_ephemeral_keys (ctrl);
|
||||||
|
|
||||||
xfree (ctrl->digest.data);
|
xfree (ctrl->digest.data);
|
||||||
ctrl->digest.data = NULL;
|
ctrl->digest.data = NULL;
|
||||||
|
@ -397,7 +397,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
|
|||||||
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
|
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
|
||||||
grip[i] = xtoi_2 (p);
|
grip[i] = xtoi_2 (p);
|
||||||
|
|
||||||
if (!force && !agent_key_available (grip))
|
if (!force && !agent_key_available (ctrl, grip))
|
||||||
continue; /* The key is already available. */
|
continue; /* The key is already available. */
|
||||||
|
|
||||||
/* Unknown key - store it. */
|
/* Unknown key - store it. */
|
||||||
@ -408,15 +408,17 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (!ctrl->ephemeral_mode)
|
||||||
char *dispserialno;
|
{
|
||||||
|
char *dispserialno;
|
||||||
|
|
||||||
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
||||||
item->hexgrip);
|
item->hexgrip);
|
||||||
rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force,
|
rc = agent_write_shadow_key (ctrl,
|
||||||
dispserialno);
|
grip, serialno, item->id, pubkey, force,
|
||||||
xfree (dispserialno);
|
dispserialno);
|
||||||
}
|
xfree (dispserialno);
|
||||||
|
}
|
||||||
xfree (pubkey);
|
xfree (pubkey);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
@ -371,13 +371,14 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyref)
|
if (keyref && !ctrl->ephemeral_mode)
|
||||||
{
|
{
|
||||||
char *dispserialno;
|
char *dispserialno;
|
||||||
|
|
||||||
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
|
||||||
hexgrip);
|
hexgrip);
|
||||||
agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf,
|
agent_write_shadow_key (ctrl,
|
||||||
|
ctrl->keygrip, serialno, keyref, pkbuf,
|
||||||
0, dispserialno);
|
0, dispserialno);
|
||||||
xfree (dispserialno);
|
xfree (dispserialno);
|
||||||
}
|
}
|
||||||
|
@ -755,8 +755,9 @@ release_passphrase (char *pw)
|
|||||||
|
|
||||||
/* Stub function. */
|
/* Stub function. */
|
||||||
int
|
int
|
||||||
agent_key_available (const unsigned char *grip)
|
agent_key_available (ctrl_t ctrl, const unsigned char *grip)
|
||||||
{
|
{
|
||||||
|
(void)ctrl;
|
||||||
(void)grip;
|
(void)grip;
|
||||||
return -1; /* Not available. */
|
return -1; /* Not available. */
|
||||||
}
|
}
|
||||||
@ -814,7 +815,7 @@ agent_askpin (ctrl_t ctrl,
|
|||||||
/* Replacement for the function in findkey.c. Here we write the key
|
/* Replacement for the function in findkey.c. Here we write the key
|
||||||
* to stdout. */
|
* to stdout. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_write_private_key (const unsigned char *grip,
|
agent_write_private_key (ctrl_t ctrl, const unsigned char *grip,
|
||||||
const void *buffer, size_t length, int force,
|
const void *buffer, size_t length, int force,
|
||||||
const char *serialno, const char *keyref,
|
const char *serialno, const char *keyref,
|
||||||
const char *dispserialno, time_t timestamp)
|
const char *dispserialno, time_t timestamp)
|
||||||
@ -822,6 +823,7 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
char hexgrip[40+4+1];
|
char hexgrip[40+4+1];
|
||||||
char *p;
|
char *p;
|
||||||
|
|
||||||
|
(void)ctrl;
|
||||||
(void)force;
|
(void)force;
|
||||||
(void)serialno;
|
(void)serialno;
|
||||||
(void)keyref;
|
(void)keyref;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user