mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Rework parsing of agent key list.
Now, in both SSH-1 and SSH-2, we go through the whole response from the SSH agent, parse out the public blob and comment of every key, and stash them in a data structure to iterate through later. Previously, we were iterating through the agent response _in situ_, while it was still stored in the s->agent_response memory buffer in the form the agent sent it, and had the ongoing s->asrc BinarySource pointing at it. This led to a remotely triggerable stale-pointer bug: as soon as we send a _second_ agent request trying to authenticate with one of the keys, it causes s->agent_response to be freed. In normal usage this doesn't happen, because if a server sends PK_OK (or an RSA1 challenge) then it's going to accept our response, so we never go back to iterating over the rest of the agent's key list. But if a server sends PK_OK or an RSA1 challenge and _then_ rejects authentication after we go to the effort of responding, we'll go back to iterating over the agent's key list and cause a crash. So now, we extract everything we need from the key-list agent response, and by the time we're making further agent requests, we don't need it any more.
This commit is contained in:
parent
4510a622ea
commit
45287b627d
272
ssh1login.c
272
ssh1login.c
@ -12,6 +12,12 @@
|
|||||||
#include "sshppl.h"
|
#include "sshppl.h"
|
||||||
#include "sshcr.h"
|
#include "sshcr.h"
|
||||||
|
|
||||||
|
typedef struct agent_key {
|
||||||
|
RSAKey key;
|
||||||
|
strbuf *comment;
|
||||||
|
ptrlen blob; /* only used during initial parsing of agent response */
|
||||||
|
} agent_key;
|
||||||
|
|
||||||
struct ssh1_login_state {
|
struct ssh1_login_state {
|
||||||
int crState;
|
int crState;
|
||||||
|
|
||||||
@ -47,11 +53,11 @@ struct ssh1_login_state {
|
|||||||
void *agent_response_to_free;
|
void *agent_response_to_free;
|
||||||
ptrlen agent_response;
|
ptrlen agent_response;
|
||||||
BinarySource asrc[1]; /* response from SSH agent */
|
BinarySource asrc[1]; /* response from SSH agent */
|
||||||
int keyi, nkeys;
|
size_t agent_keys_len;
|
||||||
|
agent_key *agent_keys;
|
||||||
|
size_t agent_key_index, agent_key_limit;
|
||||||
bool authed;
|
bool authed;
|
||||||
RSAKey key;
|
RSAKey key;
|
||||||
mp_int *challenge;
|
|
||||||
strbuf *agent_comment;
|
|
||||||
int dlgret;
|
int dlgret;
|
||||||
Filename *keyfile;
|
Filename *keyfile;
|
||||||
RSAKey servkey, hostkey;
|
RSAKey servkey, hostkey;
|
||||||
@ -99,7 +105,6 @@ PacketProtocolLayer *ssh1_login_new(
|
|||||||
s->savedhost = dupstr(host);
|
s->savedhost = dupstr(host);
|
||||||
s->savedport = port;
|
s->savedport = port;
|
||||||
s->successor_layer = successor_layer;
|
s->successor_layer = successor_layer;
|
||||||
s->agent_comment = strbuf_new();
|
|
||||||
return &s->ppl;
|
return &s->ppl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,9 +123,15 @@ static void ssh1_login_free(PacketProtocolLayer *ppl)
|
|||||||
if (s->publickey_blob)
|
if (s->publickey_blob)
|
||||||
strbuf_free(s->publickey_blob);
|
strbuf_free(s->publickey_blob);
|
||||||
sfree(s->publickey_comment);
|
sfree(s->publickey_comment);
|
||||||
strbuf_free(s->agent_comment);
|
|
||||||
if (s->cur_prompt)
|
if (s->cur_prompt)
|
||||||
free_prompts(s->cur_prompt);
|
free_prompts(s->cur_prompt);
|
||||||
|
if (s->agent_keys) {
|
||||||
|
for (size_t i = 0; i < s->agent_keys_len; i++) {
|
||||||
|
freersakey(&s->agent_keys[i].key);
|
||||||
|
strbuf_free(s->agent_keys[i].comment);
|
||||||
|
}
|
||||||
|
sfree(s->agent_keys);
|
||||||
|
}
|
||||||
sfree(s->agent_response_to_free);
|
sfree(s->agent_response_to_free);
|
||||||
if (s->auth_agent_query)
|
if (s->auth_agent_query)
|
||||||
agent_cancel_query(s->auth_agent_query);
|
agent_cancel_query(s->auth_agent_query);
|
||||||
@ -504,122 +515,165 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl)
|
|||||||
|
|
||||||
get_uint32(s->asrc); /* skip length field */
|
get_uint32(s->asrc); /* skip length field */
|
||||||
if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
|
if (get_byte(s->asrc) == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
|
||||||
s->nkeys = toint(get_uint32(s->asrc));
|
size_t nkeys = get_uint32(s->asrc);
|
||||||
if (s->nkeys < 0) {
|
size_t origpos = s->asrc->pos;
|
||||||
ppl_logevent("Pageant reported negative key count %d",
|
|
||||||
s->nkeys);
|
|
||||||
s->nkeys = 0;
|
|
||||||
}
|
|
||||||
ppl_logevent("Pageant has %d SSH-1 keys", s->nkeys);
|
|
||||||
for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {
|
|
||||||
size_t start, end;
|
|
||||||
start = s->asrc->pos;
|
|
||||||
get_rsa_ssh1_pub(s->asrc, &s->key,
|
|
||||||
RSA_SSH1_EXPONENT_FIRST);
|
|
||||||
end = s->asrc->pos;
|
|
||||||
strbuf_clear(s->agent_comment);
|
|
||||||
put_datapl(s->agent_comment, get_string(s->asrc));
|
|
||||||
if (get_err(s->asrc)) {
|
|
||||||
ppl_logevent("Pageant key list packet was truncated");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (s->publickey_blob) {
|
|
||||||
ptrlen keystr = make_ptrlen(
|
|
||||||
(const char *)s->asrc->data + start, end - start);
|
|
||||||
|
|
||||||
if (keystr.len == s->publickey_blob->len &&
|
/*
|
||||||
!memcmp(keystr.ptr, s->publickey_blob->s,
|
* Check that the agent response is well formed.
|
||||||
s->publickey_blob->len)) {
|
*/
|
||||||
ppl_logevent("Pageant key #%d matches "
|
for (size_t i = 0; i < nkeys; i++) {
|
||||||
"configured key file", s->keyi);
|
get_rsa_ssh1_pub(s->asrc, NULL, RSA_SSH1_EXPONENT_FIRST);
|
||||||
s->tried_publickey = true;
|
get_string(s->asrc); /* comment */
|
||||||
} else
|
if (get_err(s->asrc)) {
|
||||||
/* Skip non-configured key */
|
ppl_logevent("Pageant's response was truncated");
|
||||||
continue;
|
goto parsed_agent_query;
|
||||||
}
|
}
|
||||||
ppl_logevent("Trying Pageant key #%d", s->keyi);
|
}
|
||||||
pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA);
|
|
||||||
put_mp_ssh1(pkt, s->key.modulus);
|
/*
|
||||||
pq_push(s->ppl.out_pq, pkt);
|
* Copy the list of public-key blobs out of the Pageant
|
||||||
crMaybeWaitUntilV((pktin = ssh1_login_pop(s))
|
* response.
|
||||||
!= NULL);
|
*/
|
||||||
if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
|
BinarySource_REWIND_TO(s->asrc, origpos);
|
||||||
ppl_logevent("Key refused");
|
s->agent_keys_len = nkeys;
|
||||||
continue;
|
s->agent_keys = snewn(s->agent_keys_len, agent_key);
|
||||||
|
for (size_t i = 0; i < nkeys; i++) {
|
||||||
|
memset(&s->agent_keys[i].key, 0,
|
||||||
|
sizeof(s->agent_keys[i].key));
|
||||||
|
|
||||||
|
const char *blobstart = get_ptr(s->asrc);
|
||||||
|
get_rsa_ssh1_pub(s->asrc, &s->agent_keys[i].key,
|
||||||
|
RSA_SSH1_EXPONENT_FIRST);
|
||||||
|
const char *blobend = get_ptr(s->asrc);
|
||||||
|
|
||||||
|
s->agent_keys[i].comment = strbuf_new();
|
||||||
|
put_datapl(s->agent_keys[i].comment, get_string(s->asrc));
|
||||||
|
|
||||||
|
s->agent_keys[i].blob = make_ptrlen(
|
||||||
|
blobstart, blobend - blobstart);
|
||||||
|
}
|
||||||
|
|
||||||
|
ppl_logevent("Pageant has %"SIZEu" SSH-1 keys", nkeys);
|
||||||
|
|
||||||
|
if (s->publickey_blob) {
|
||||||
|
/*
|
||||||
|
* If we've been given a specific public key blob,
|
||||||
|
* filter the list of keys to try from the agent
|
||||||
|
* down to only that one, or none if it's not
|
||||||
|
* there.
|
||||||
|
*/
|
||||||
|
ptrlen our_blob = ptrlen_from_strbuf(s->publickey_blob);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < nkeys; i++) {
|
||||||
|
if (ptrlen_eq_ptrlen(our_blob, s->agent_keys[i].blob))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ppl_logevent("Received RSA challenge");
|
|
||||||
s->challenge = get_mp_ssh1(pktin);
|
if (i < nkeys) {
|
||||||
|
ppl_logevent("Pageant key #%"SIZEu" matches "
|
||||||
|
"configured key file", i);
|
||||||
|
s->agent_key_index = i;
|
||||||
|
s->agent_key_limit = i+1;
|
||||||
|
} else {
|
||||||
|
ppl_logevent("Configured key file not in Pageant");
|
||||||
|
s->agent_key_index = 0;
|
||||||
|
s->agent_key_limit = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Otherwise, try them all.
|
||||||
|
*/
|
||||||
|
s->agent_key_index = 0;
|
||||||
|
s->agent_key_limit = nkeys;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ppl_logevent("Failed to get reply from Pageant");
|
||||||
|
}
|
||||||
|
parsed_agent_query:;
|
||||||
|
|
||||||
|
for (; s->agent_key_index < s->agent_key_limit;
|
||||||
|
s->agent_key_index++) {
|
||||||
|
ppl_logevent("Trying Pageant key #%"SIZEu, s->agent_key_index);
|
||||||
|
pkt = ssh_bpp_new_pktout(s->ppl.bpp, SSH1_CMSG_AUTH_RSA);
|
||||||
|
put_mp_ssh1(pkt,
|
||||||
|
s->agent_keys[s->agent_key_index].key.modulus);
|
||||||
|
pq_push(s->ppl.out_pq, pkt);
|
||||||
|
crMaybeWaitUntilV((pktin = ssh1_login_pop(s))
|
||||||
|
!= NULL);
|
||||||
|
if (pktin->type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
|
||||||
|
ppl_logevent("Key refused");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ppl_logevent("Received RSA challenge");
|
||||||
|
|
||||||
|
{
|
||||||
|
mp_int *challenge = get_mp_ssh1(pktin);
|
||||||
if (get_err(pktin)) {
|
if (get_err(pktin)) {
|
||||||
mp_free(s->challenge);
|
mp_free(challenge);
|
||||||
ssh_proto_error(s->ppl.ssh, "Server's RSA challenge "
|
ssh_proto_error(s->ppl.ssh, "Server's RSA challenge "
|
||||||
"was badly formatted");
|
"was badly formatted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
strbuf *agentreq = strbuf_new_for_agent_query();
|
||||||
strbuf *agentreq;
|
put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE);
|
||||||
const char *ret;
|
|
||||||
|
|
||||||
agentreq = strbuf_new_for_agent_query();
|
rsa_ssh1_public_blob(
|
||||||
put_byte(agentreq, SSH1_AGENTC_RSA_CHALLENGE);
|
BinarySink_UPCAST(agentreq),
|
||||||
put_uint32(agentreq, mp_get_nbits(s->key.modulus));
|
&s->agent_keys[s->agent_key_index].key,
|
||||||
put_mp_ssh1(agentreq, s->key.exponent);
|
RSA_SSH1_EXPONENT_FIRST);
|
||||||
put_mp_ssh1(agentreq, s->key.modulus);
|
|
||||||
put_mp_ssh1(agentreq, s->challenge);
|
|
||||||
put_data(agentreq, s->session_id, 16);
|
|
||||||
put_uint32(agentreq, 1); /* response format */
|
|
||||||
ssh1_login_agent_query(s, agentreq);
|
|
||||||
strbuf_free(agentreq);
|
|
||||||
crMaybeWaitUntilV(!s->auth_agent_query);
|
|
||||||
|
|
||||||
ret = s->agent_response.ptr;
|
put_mp_ssh1(agentreq, challenge);
|
||||||
if (ret) {
|
mp_free(challenge);
|
||||||
if (s->agent_response.len >= 5+16 &&
|
|
||||||
ret[4] == SSH1_AGENT_RSA_RESPONSE) {
|
put_data(agentreq, s->session_id, 16);
|
||||||
ppl_logevent("Sending Pageant's response");
|
put_uint32(agentreq, 1); /* response format */
|
||||||
pkt = ssh_bpp_new_pktout(
|
ssh1_login_agent_query(s, agentreq);
|
||||||
s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE);
|
strbuf_free(agentreq);
|
||||||
put_data(pkt, ret + 5, 16);
|
crMaybeWaitUntilV(!s->auth_agent_query);
|
||||||
pq_push(s->ppl.out_pq, pkt);
|
|
||||||
crMaybeWaitUntilV(
|
|
||||||
(pktin = ssh1_login_pop(s))
|
|
||||||
!= NULL);
|
|
||||||
if (pktin->type == SSH1_SMSG_SUCCESS) {
|
|
||||||
ppl_logevent("Pageant's response "
|
|
||||||
"accepted");
|
|
||||||
if (flags & FLAG_VERBOSE) {
|
|
||||||
ptrlen comment = ptrlen_from_strbuf(
|
|
||||||
s->agent_comment);
|
|
||||||
ppl_printf("Authenticated using RSA "
|
|
||||||
"key \"%.*s\" from "
|
|
||||||
"agent\r\n",
|
|
||||||
PTRLEN_PRINTF(comment));
|
|
||||||
}
|
|
||||||
s->authed = true;
|
|
||||||
} else
|
|
||||||
ppl_logevent("Pageant's response not "
|
|
||||||
"accepted");
|
|
||||||
} else {
|
|
||||||
ppl_logevent("Pageant failed to answer "
|
|
||||||
"challenge");
|
|
||||||
sfree((char *)ret);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ppl_logevent("No reply received from Pageant");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mp_free(s->key.exponent);
|
|
||||||
mp_free(s->key.modulus);
|
|
||||||
mp_free(s->challenge);
|
|
||||||
if (s->authed)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
sfree(s->agent_response_to_free);
|
|
||||||
s->agent_response_to_free = NULL;
|
{
|
||||||
if (s->publickey_blob && !s->tried_publickey)
|
const unsigned char *ret = s->agent_response.ptr;
|
||||||
ppl_logevent("Configured key file not in Pageant");
|
if (ret) {
|
||||||
} else {
|
if (s->agent_response.len >= 5+16 &&
|
||||||
ppl_logevent("Failed to get reply from Pageant");
|
ret[4] == SSH1_AGENT_RSA_RESPONSE) {
|
||||||
|
ppl_logevent("Sending Pageant's response");
|
||||||
|
pkt = ssh_bpp_new_pktout(
|
||||||
|
s->ppl.bpp, SSH1_CMSG_AUTH_RSA_RESPONSE);
|
||||||
|
put_data(pkt, ret + 5, 16);
|
||||||
|
pq_push(s->ppl.out_pq, pkt);
|
||||||
|
crMaybeWaitUntilV(
|
||||||
|
(pktin = ssh1_login_pop(s))
|
||||||
|
!= NULL);
|
||||||
|
if (pktin->type == SSH1_SMSG_SUCCESS) {
|
||||||
|
ppl_logevent("Pageant's response "
|
||||||
|
"accepted");
|
||||||
|
if (flags & FLAG_VERBOSE) {
|
||||||
|
ptrlen comment = ptrlen_from_strbuf(
|
||||||
|
s->agent_keys[s->agent_key_index].
|
||||||
|
comment);
|
||||||
|
ppl_printf("Authenticated using RSA "
|
||||||
|
"key \"%.*s\" from "
|
||||||
|
"agent\r\n",
|
||||||
|
PTRLEN_PRINTF(comment));
|
||||||
|
}
|
||||||
|
s->authed = true;
|
||||||
|
} else
|
||||||
|
ppl_logevent("Pageant's response not "
|
||||||
|
"accepted");
|
||||||
|
} else {
|
||||||
|
ppl_logevent("Pageant failed to answer "
|
||||||
|
"challenge");
|
||||||
|
sfree((char *)ret);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ppl_logevent("No reply received from Pageant");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (s->authed)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (s->authed)
|
if (s->authed)
|
||||||
break;
|
break;
|
||||||
|
171
ssh2userauth.c
171
ssh2userauth.c
@ -18,6 +18,11 @@
|
|||||||
|
|
||||||
#define BANNER_LIMIT 131072
|
#define BANNER_LIMIT 131072
|
||||||
|
|
||||||
|
typedef struct agent_key {
|
||||||
|
strbuf *blob, *comment;
|
||||||
|
ptrlen algorithm;
|
||||||
|
} agent_key;
|
||||||
|
|
||||||
struct ssh2_userauth_state {
|
struct ssh2_userauth_state {
|
||||||
int crState;
|
int crState;
|
||||||
|
|
||||||
@ -69,9 +74,9 @@ struct ssh2_userauth_state {
|
|||||||
void *agent_response_to_free;
|
void *agent_response_to_free;
|
||||||
ptrlen agent_response;
|
ptrlen agent_response;
|
||||||
BinarySource asrc[1]; /* for reading SSH agent response */
|
BinarySource asrc[1]; /* for reading SSH agent response */
|
||||||
size_t pkblob_pos_in_agent;
|
size_t agent_keys_len;
|
||||||
int keyi, nkeys;
|
agent_key *agent_keys;
|
||||||
ptrlen pk, alg, comment;
|
size_t agent_key_index, agent_key_limit;
|
||||||
int len;
|
int len;
|
||||||
PktOut *pktout;
|
PktOut *pktout;
|
||||||
bool want_user_input;
|
bool want_user_input;
|
||||||
@ -173,6 +178,13 @@ static void ssh2_userauth_free(PacketProtocolLayer *ppl)
|
|||||||
if (s->successor_layer)
|
if (s->successor_layer)
|
||||||
ssh_ppl_free(s->successor_layer);
|
ssh_ppl_free(s->successor_layer);
|
||||||
|
|
||||||
|
if (s->agent_keys) {
|
||||||
|
for (size_t i = 0; i < s->agent_keys_len; i++) {
|
||||||
|
strbuf_free(s->agent_keys[i].blob);
|
||||||
|
strbuf_free(s->agent_keys[i].comment);
|
||||||
|
}
|
||||||
|
sfree(s->agent_keys);
|
||||||
|
}
|
||||||
sfree(s->agent_response_to_free);
|
sfree(s->agent_response_to_free);
|
||||||
if (s->auth_agent_query)
|
if (s->auth_agent_query)
|
||||||
agent_cancel_query(s->auth_agent_query);
|
agent_cancel_query(s->auth_agent_query);
|
||||||
@ -300,8 +312,6 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
* Find out about any keys Pageant has (but if there's a public
|
* Find out about any keys Pageant has (but if there's a public
|
||||||
* key configured, filter out all others).
|
* key configured, filter out all others).
|
||||||
*/
|
*/
|
||||||
s->nkeys = 0;
|
|
||||||
s->pkblob_pos_in_agent = 0;
|
|
||||||
if (s->tryagent && agent_exists()) {
|
if (s->tryagent && agent_exists()) {
|
||||||
ppl_logevent("Pageant is running. Requesting keys.");
|
ppl_logevent("Pageant is running. Requesting keys.");
|
||||||
|
|
||||||
@ -317,48 +327,75 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
|
|
||||||
get_uint32(s->asrc); /* skip length field */
|
get_uint32(s->asrc); /* skip length field */
|
||||||
if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) {
|
if (get_byte(s->asrc) == SSH2_AGENT_IDENTITIES_ANSWER) {
|
||||||
int keyi;
|
size_t nkeys = get_uint32(s->asrc);
|
||||||
|
size_t origpos = s->asrc->pos;
|
||||||
s->nkeys = toint(get_uint32(s->asrc));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vet the Pageant response to ensure that the key count
|
* Check that the agent response is well formed.
|
||||||
* and blob lengths make sense.
|
|
||||||
*/
|
*/
|
||||||
if (s->nkeys < 0) {
|
for (size_t i = 0; i < nkeys; i++) {
|
||||||
ppl_logevent("Pageant response contained a negative"
|
get_string(s->asrc); /* blob */
|
||||||
" key count %d", s->nkeys);
|
get_string(s->asrc); /* comment */
|
||||||
s->nkeys = 0;
|
if (get_err(s->asrc)) {
|
||||||
goto done_agent_query;
|
ppl_logevent("Pageant's response was truncated");
|
||||||
} else {
|
goto done_agent_query;
|
||||||
ppl_logevent("Pageant has %d SSH-2 keys", s->nkeys);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* See if configured key is in agent. */
|
/*
|
||||||
for (keyi = 0; keyi < s->nkeys; keyi++) {
|
* Copy the list of public-key blobs out of the Pageant
|
||||||
size_t pos = s->asrc->pos;
|
* response.
|
||||||
ptrlen blob = get_string(s->asrc);
|
*/
|
||||||
get_string(s->asrc); /* skip comment */
|
BinarySource_REWIND_TO(s->asrc, origpos);
|
||||||
if (get_err(s->asrc)) {
|
s->agent_keys_len = nkeys;
|
||||||
ppl_logevent("Pageant response was truncated");
|
s->agent_keys = snewn(s->agent_keys_len, agent_key);
|
||||||
s->nkeys = 0;
|
for (size_t i = 0; i < nkeys; i++) {
|
||||||
goto done_agent_query;
|
s->agent_keys[i].blob = strbuf_new();
|
||||||
}
|
put_datapl(s->agent_keys[i].blob, get_string(s->asrc));
|
||||||
|
s->agent_keys[i].comment = strbuf_new();
|
||||||
|
put_datapl(s->agent_keys[i].comment, get_string(s->asrc));
|
||||||
|
|
||||||
if (s->publickey_blob &&
|
/* Also, extract the algorithm string from the start
|
||||||
blob.len == s->publickey_blob->len &&
|
* of the public-key blob. */
|
||||||
!memcmp(blob.ptr, s->publickey_blob->s,
|
BinarySource src[1];
|
||||||
s->publickey_blob->len)) {
|
BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
|
||||||
ppl_logevent("Pageant key #%d matches "
|
s->agent_keys[i].blob));
|
||||||
"configured key file", keyi);
|
s->agent_keys[i].algorithm = get_string(src);
|
||||||
s->keyi = keyi;
|
}
|
||||||
s->pkblob_pos_in_agent = pos;
|
|
||||||
|
ppl_logevent("Pageant has %"SIZEu" SSH-2 keys", nkeys);
|
||||||
|
|
||||||
|
if (s->publickey_blob) {
|
||||||
|
/*
|
||||||
|
* If we've been given a specific public key blob,
|
||||||
|
* filter the list of keys to try from the agent down
|
||||||
|
* to only that one, or none if it's not there.
|
||||||
|
*/
|
||||||
|
ptrlen our_blob = ptrlen_from_strbuf(s->publickey_blob);
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < nkeys; i++) {
|
||||||
|
if (ptrlen_eq_ptrlen(our_blob, ptrlen_from_strbuf(
|
||||||
|
s->agent_keys[i].blob)))
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (s->publickey_blob && !s->pkblob_pos_in_agent) {
|
|
||||||
|
if (i < nkeys) {
|
||||||
|
ppl_logevent("Pageant key #%"SIZEu" matches "
|
||||||
|
"configured key file", i);
|
||||||
|
s->agent_key_index = i;
|
||||||
|
s->agent_key_limit = i+1;
|
||||||
|
} else {
|
||||||
ppl_logevent("Configured key file not in Pageant");
|
ppl_logevent("Configured key file not in Pageant");
|
||||||
s->nkeys = 0;
|
s->agent_key_index = 0;
|
||||||
|
s->agent_key_limit = 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Otherwise, try them all.
|
||||||
|
*/
|
||||||
|
s->agent_key_index = 0;
|
||||||
|
s->agent_key_limit = nkeys;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ppl_logevent("Failed to get reply from Pageant");
|
ppl_logevent("Failed to get reply from Pageant");
|
||||||
@ -457,17 +494,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
|
|
||||||
s->tried_pubkey_config = false;
|
s->tried_pubkey_config = false;
|
||||||
s->kbd_inter_refused = false;
|
s->kbd_inter_refused = false;
|
||||||
|
|
||||||
/* Reset agent request state. */
|
|
||||||
s->done_agent = false;
|
s->done_agent = false;
|
||||||
if (s->agent_response.ptr) {
|
|
||||||
if (s->pkblob_pos_in_agent) {
|
|
||||||
s->asrc->pos = s->pkblob_pos_in_agent;
|
|
||||||
} else {
|
|
||||||
s->asrc->pos = 9; /* skip length + type + key count */
|
|
||||||
s->keyi = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/*
|
/*
|
||||||
@ -688,7 +715,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
} else
|
} else
|
||||||
#endif /* NO_GSSAPI */
|
#endif /* NO_GSSAPI */
|
||||||
|
|
||||||
if (s->can_pubkey && !s->done_agent && s->nkeys) {
|
if (s->can_pubkey && !s->done_agent &&
|
||||||
|
s->agent_key_index < s->agent_key_limit) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt public-key authentication using a key from Pageant.
|
* Attempt public-key authentication using a key from Pageant.
|
||||||
@ -696,16 +724,7 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
|
|
||||||
s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
|
s->ppl.bpp->pls->actx = SSH2_PKTCTX_PUBLICKEY;
|
||||||
|
|
||||||
ppl_logevent("Trying Pageant key #%d", s->keyi);
|
ppl_logevent("Trying Pageant key #%"SIZEu, s->agent_key_index);
|
||||||
|
|
||||||
/* Unpack key from agent response */
|
|
||||||
s->pk = get_string(s->asrc);
|
|
||||||
s->comment = get_string(s->asrc);
|
|
||||||
{
|
|
||||||
BinarySource src[1];
|
|
||||||
BinarySource_BARE_INIT_PL(src, s->pk);
|
|
||||||
s->alg = get_string(src);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See if server will accept it */
|
/* See if server will accept it */
|
||||||
s->pktout = ssh_bpp_new_pktout(
|
s->pktout = ssh_bpp_new_pktout(
|
||||||
@ -715,8 +734,10 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
put_stringz(s->pktout, "publickey");
|
put_stringz(s->pktout, "publickey");
|
||||||
/* method */
|
/* method */
|
||||||
put_bool(s->pktout, false); /* no signature included */
|
put_bool(s->pktout, false); /* no signature included */
|
||||||
put_stringpl(s->pktout, s->alg);
|
put_stringpl(s->pktout,
|
||||||
put_stringpl(s->pktout, s->pk);
|
s->agent_keys[s->agent_key_index].algorithm);
|
||||||
|
put_stringpl(s->pktout, ptrlen_from_strbuf(
|
||||||
|
s->agent_keys[s->agent_key_index].blob));
|
||||||
pq_push(s->ppl.out_pq, s->pktout);
|
pq_push(s->ppl.out_pq, s->pktout);
|
||||||
s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;
|
s->type = AUTH_TYPE_PUBLICKEY_OFFER_QUIET;
|
||||||
|
|
||||||
@ -729,11 +750,13 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
strbuf *agentreq, *sigdata;
|
strbuf *agentreq, *sigdata;
|
||||||
|
ptrlen comment = ptrlen_from_strbuf(
|
||||||
|
s->agent_keys[s->agent_key_index].comment);
|
||||||
|
|
||||||
if (flags & FLAG_VERBOSE)
|
if (flags & FLAG_VERBOSE)
|
||||||
ppl_printf("Authenticating with public key "
|
ppl_printf("Authenticating with public key "
|
||||||
"\"%.*s\" from agent\r\n",
|
"\"%.*s\" from agent\r\n",
|
||||||
PTRLEN_PRINTF(s->comment));
|
PTRLEN_PRINTF(comment));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Server is willing to accept the key.
|
* Server is willing to accept the key.
|
||||||
@ -746,13 +769,16 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
put_stringz(s->pktout, "publickey");
|
put_stringz(s->pktout, "publickey");
|
||||||
/* method */
|
/* method */
|
||||||
put_bool(s->pktout, true); /* signature included */
|
put_bool(s->pktout, true); /* signature included */
|
||||||
put_stringpl(s->pktout, s->alg);
|
put_stringpl(s->pktout,
|
||||||
put_stringpl(s->pktout, s->pk);
|
s->agent_keys[s->agent_key_index].algorithm);
|
||||||
|
put_stringpl(s->pktout, ptrlen_from_strbuf(
|
||||||
|
s->agent_keys[s->agent_key_index].blob));
|
||||||
|
|
||||||
/* Ask agent for signature. */
|
/* Ask agent for signature. */
|
||||||
agentreq = strbuf_new_for_agent_query();
|
agentreq = strbuf_new_for_agent_query();
|
||||||
put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST);
|
put_byte(agentreq, SSH2_AGENTC_SIGN_REQUEST);
|
||||||
put_stringpl(agentreq, s->pk);
|
put_stringpl(agentreq, ptrlen_from_strbuf(
|
||||||
|
s->agent_keys[s->agent_key_index].blob));
|
||||||
/* Now the data to be signed... */
|
/* Now the data to be signed... */
|
||||||
sigdata = strbuf_new();
|
sigdata = strbuf_new();
|
||||||
ssh2_userauth_add_session_id(s, sigdata);
|
ssh2_userauth_add_session_id(s, sigdata);
|
||||||
@ -774,8 +800,11 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE &&
|
if (get_byte(src) == SSH2_AGENT_SIGN_RESPONSE &&
|
||||||
(sigblob = get_string(src), !get_err(src))) {
|
(sigblob = get_string(src), !get_err(src))) {
|
||||||
ppl_logevent("Sending Pageant's response");
|
ppl_logevent("Sending Pageant's response");
|
||||||
ssh2_userauth_add_sigblob(s, s->pktout,
|
ssh2_userauth_add_sigblob(
|
||||||
s->pk, sigblob);
|
s, s->pktout,
|
||||||
|
ptrlen_from_strbuf(
|
||||||
|
s->agent_keys[s->agent_key_index].blob),
|
||||||
|
sigblob);
|
||||||
pq_push(s->ppl.out_pq, s->pktout);
|
pq_push(s->ppl.out_pq, s->pktout);
|
||||||
s->type = AUTH_TYPE_PUBLICKEY;
|
s->type = AUTH_TYPE_PUBLICKEY;
|
||||||
} else {
|
} else {
|
||||||
@ -796,14 +825,8 @@ static void ssh2_userauth_process_queue(PacketProtocolLayer *ppl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Do we have any keys left to try? */
|
/* Do we have any keys left to try? */
|
||||||
if (s->pkblob_pos_in_agent) {
|
if (++s->agent_key_index >= s->agent_key_limit)
|
||||||
s->done_agent = true;
|
s->done_agent = true;
|
||||||
s->tried_pubkey_config = true;
|
|
||||||
} else {
|
|
||||||
s->keyi++;
|
|
||||||
if (s->keyi >= s->nkeys)
|
|
||||||
s->done_agent = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (s->can_pubkey && s->publickey_blob &&
|
} else if (s->can_pubkey && s->publickey_blob &&
|
||||||
s->privatekey_available && !s->tried_pubkey_config) {
|
s->privatekey_available && !s->tried_pubkey_config) {
|
||||||
|
Loading…
Reference in New Issue
Block a user