1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Unix Pageant: -E option to load key files encrypted.

This applies to both server modes ('pageant -E key.ppk [lifetime]')
and client mode ('pageant -a -E key.ppk').

I'm not completely confident that the CLI syntax is actually right
yet, but for the moment, it's enough that it _exists_. Now I don't
have to test the encrypted-key loading via manually mocked-up agent
requests.
This commit is contained in:
Simon Tatham 2020-02-08 17:28:46 +00:00
parent 8677ee00fb
commit 55005a08ea
4 changed files with 67 additions and 12 deletions

View File

@ -1604,7 +1604,7 @@ void *pageant_get_keylist2(int *length)
}
int pageant_add_keyfile(Filename *filename, const char *passphrase,
char **retstr)
char **retstr, bool add_encrypted)
{
RSAKey *rkey = NULL;
ssh2_userkey *skey = NULL;
@ -1629,6 +1629,11 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
return PAGEANT_ACTION_FAILURE;
}
if (add_encrypted && type == SSH_KEYTYPE_SSH1) {
*retstr = dupprintf("Can't add SSH-1 keys in encrypted form");
return PAGEANT_ACTION_FAILURE;
}
/*
* See if the key is already loaded (in the primary Pageant,
* which may or may not be us).
@ -1747,6 +1752,38 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
strbuf_free(blob);
}
if (add_encrypted) {
const char *load_error;
LoadedFile *lf = lf_load_keyfile(filename, &load_error);
if (!lf) {
*retstr = dupstr(load_error);
return PAGEANT_ACTION_FAILURE;
}
strbuf *request = strbuf_new_for_agent_query();
put_byte(request, SSH2_AGENTC_EXTENSION);
put_stringpl(request, PUTTYEXT("add-ppk"));
put_string(request, lf->data, lf->len);
lf_free(lf);
void *vresponse;
int resplen;
pageant_client_query(request, &vresponse, &resplen);
strbuf_free(request);
unsigned char *response = vresponse;
if (resplen < 5 || response[4] != SSH_AGENT_SUCCESS) {
*retstr = dupstr("The already running Pageant "
"refused to add the key.");
sfree(response);
return PAGEANT_ACTION_FAILURE;
}
sfree(response);
return PAGEANT_ACTION_OK;
}
error = NULL;
if (type == SSH_KEYTYPE_SSH1)
needs_pass = rsa1_encrypted_f(filename, &comment);

View File

@ -220,7 +220,7 @@ enum {
PAGEANT_ACTION_NEED_PP /* need passphrase: *retstr is key comment */
};
int pageant_add_keyfile(Filename *filename, const char *passphrase,
char **retstr);
char **retstr, bool add_encrypted);
void pageant_forget_passphrases(void);
struct pageant_pubkey {

View File

@ -312,7 +312,10 @@ static void tty_life_timer(void *ctx, unsigned long now)
typedef enum {
KEYACT_AGENT_LOAD,
KEYACT_CLIENT_ADD,
KEYACT_AGENT_LOAD_ENCRYPTED,
KEYACT_CLIENT_BASE,
KEYACT_CLIENT_ADD = KEYACT_CLIENT_BASE,
KEYACT_CLIENT_ADD_ENCRYPTED,
KEYACT_CLIENT_DEL,
KEYACT_CLIENT_DEL_ALL,
KEYACT_CLIENT_LIST,
@ -327,7 +330,7 @@ struct cmdline_key_action {
bool is_agent_action(keyact action)
{
return action == KEYACT_AGENT_LOAD;
return action < KEYACT_CLIENT_BASE;
}
static struct cmdline_key_action *keyact_head = NULL, *keyact_tail = NULL;
@ -438,7 +441,7 @@ static char *askpass(const char *prompt)
}
}
static bool unix_add_keyfile(const char *filename_str)
static bool unix_add_keyfile(const char *filename_str, bool add_encrypted)
{
Filename *filename = filename_from_str(filename_str);
int status;
@ -450,7 +453,7 @@ static bool unix_add_keyfile(const char *filename_str)
/*
* Try without a passphrase.
*/
status = pageant_add_keyfile(filename, NULL, &err);
status = pageant_add_keyfile(filename, NULL, &err, add_encrypted);
if (status == PAGEANT_ACTION_OK) {
goto cleanup;
} else if (status == PAGEANT_ACTION_FAILURE) {
@ -472,7 +475,8 @@ static bool unix_add_keyfile(const char *filename_str)
if (!passphrase)
break;
status = pageant_add_keyfile(filename, passphrase, &err);
status = pageant_add_keyfile(filename, passphrase, &err,
add_encrypted);
smemclr(passphrase, strlen(passphrase));
sfree(passphrase);
@ -692,7 +696,9 @@ void run_client(void)
for (act = keyact_head; act; act = act->next) {
switch (act->action) {
case KEYACT_CLIENT_ADD:
if (!unix_add_keyfile(act->filename))
case KEYACT_CLIENT_ADD_ENCRYPTED:
if (!unix_add_keyfile(act->filename,
act->action == KEYACT_CLIENT_ADD_ENCRYPTED))
errors = true;
break;
case KEYACT_CLIENT_LIST:
@ -875,8 +881,10 @@ void run_agent(FILE *logfp, const char *symlink_path)
* Start by loading any keys provided on the command line.
*/
for (act = keyact_head; act; act = act->next) {
assert(act->action == KEYACT_AGENT_LOAD);
if (!unix_add_keyfile(act->filename))
assert(act->action == KEYACT_AGENT_LOAD ||
act->action == KEYACT_AGENT_LOAD_ENCRYPTED);
if (!unix_add_keyfile(act->filename,
act->action == KEYACT_AGENT_LOAD_ENCRYPTED))
errors = true;
}
if (errors)
@ -1097,6 +1105,16 @@ int main(int argc, char **argv)
life = LIFE_X11;
} else if (!strcmp(p, "-T")) {
life = LIFE_TTY;
} else if (!strcmp(p, "-E")) {
if (curr_keyact == KEYACT_AGENT_LOAD)
curr_keyact = KEYACT_AGENT_LOAD_ENCRYPTED;
else if (curr_keyact == KEYACT_CLIENT_ADD)
curr_keyact = KEYACT_CLIENT_ADD_ENCRYPTED;
else {
fprintf(stderr, "pageant: unexpected -E while not adding "
"keys\n");
exit(1);
}
} else if (!strcmp(p, "--debug")) {
life = LIFE_DEBUG;
} else if (!strcmp(p, "--permanent")) {

View File

@ -373,7 +373,7 @@ static void win_add_keyfile(Filename *filename)
* _new_ passphrase; pageant_add_keyfile will take care of trying
* all the passphrases we've already stored.)
*/
ret = pageant_add_keyfile(filename, NULL, &err);
ret = pageant_add_keyfile(filename, NULL, &err, false);
if (ret == PAGEANT_ACTION_OK) {
goto done;
} else if (ret == PAGEANT_ACTION_FAILURE) {
@ -401,7 +401,7 @@ static void win_add_keyfile(Filename *filename)
assert(passphrase != NULL);
ret = pageant_add_keyfile(filename, passphrase, &err);
ret = pageant_add_keyfile(filename, passphrase, &err, false);
if (ret == PAGEANT_ACTION_OK) {
goto done;
} else if (ret == PAGEANT_ACTION_FAILURE) {