mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-07-01 03:22:48 -05:00
Move half of Pageant out into a cross-platform source file.
I'm aiming for windows/winpgnt.c to only contain the parts of Windows Pageant that are actually to do with handling the Windows API, and for all the actual agent logic to be cross-platform. This commit is a start: I've moved every function and internal variable that was easy to move. But it doesn't get all the way there - there's still a lot of logic in add_keyfile() and get_keylist*() that would be good to move out to cross-platform code, but it's harder because that code is currently quite intertwined with details of Windows OS interfacing such as printing message boxes and passphrase prompts and calling back out to agent_query if the Pageant doing that job isn't the primary one.
This commit is contained in:
@ -15,6 +15,7 @@
|
||||
#include "misc.h"
|
||||
#include "tree234.h"
|
||||
#include "winsecur.h"
|
||||
#include "pageant.h"
|
||||
|
||||
#include <shellapi.h>
|
||||
|
||||
@ -34,11 +35,6 @@
|
||||
|
||||
#define AGENT_COPYDATA_ID 0x804e50ba /* random goop */
|
||||
|
||||
/*
|
||||
* FIXME: maybe some day we can sort this out ...
|
||||
*/
|
||||
#define AGENT_MAX_MSGLEN 8192
|
||||
|
||||
/* From MSDN: In the WM_SYSCOMMAND message, the four low-order bits of
|
||||
* wParam are used by Windows, and should be masked off, so we shouldn't
|
||||
* attempt to store information in them. Hence all these identifiers have
|
||||
@ -114,46 +110,14 @@ static void unmungestr(char *in, char *out, int outlen)
|
||||
return;
|
||||
}
|
||||
|
||||
static tree234 *rsakeys, *ssh2keys;
|
||||
|
||||
static int has_security;
|
||||
|
||||
/*
|
||||
* Forward references
|
||||
*/
|
||||
static void *make_keylist1(int *length);
|
||||
static void *make_keylist2(int *length);
|
||||
static void *get_keylist1(int *length);
|
||||
static void *get_keylist2(int *length);
|
||||
|
||||
/*
|
||||
* We need this to link with the RSA code, because rsaencrypt()
|
||||
* pads its data with random bytes. Since we only use rsadecrypt()
|
||||
* and the signing functions, which are deterministic, this should
|
||||
* never be called.
|
||||
*
|
||||
* If it _is_ called, there is a _serious_ problem, because it
|
||||
* won't generate true random numbers. So we must scream, panic,
|
||||
* and exit immediately if that should happen.
|
||||
*/
|
||||
int random_byte(void)
|
||||
{
|
||||
MessageBox(hwnd, "Internal Error", APPNAME, MB_OK | MB_ICONERROR);
|
||||
exit(0);
|
||||
/* this line can't be reached but it placates MSVC's warnings :-) */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Blob structure for passing to the asymmetric SSH-2 key compare
|
||||
* function, prototyped here.
|
||||
*/
|
||||
struct blob {
|
||||
unsigned char *blob;
|
||||
int len;
|
||||
};
|
||||
static int cmpkeys_ssh2_asymm(void *av, void *bv);
|
||||
|
||||
struct PassphraseProcStruct {
|
||||
char **passphrase;
|
||||
char *comment;
|
||||
@ -321,7 +285,7 @@ void old_keyfile_warning(void)
|
||||
/*
|
||||
* Update the visible key list.
|
||||
*/
|
||||
static void keylist_update(void)
|
||||
void keylist_update(void)
|
||||
{
|
||||
struct RSAKey *rkey;
|
||||
struct ssh2_userkey *skey;
|
||||
@ -329,7 +293,7 @@ static void keylist_update(void)
|
||||
|
||||
if (keylist) {
|
||||
SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0);
|
||||
for (i = 0; NULL != (rkey = index234(rsakeys, i)); i++) {
|
||||
for (i = 0; NULL != (rkey = pageant_nth_ssh1_key(i)); i++) {
|
||||
char listentry[512], *p;
|
||||
/*
|
||||
* Replace two spaces in the fingerprint with tabs, for
|
||||
@ -347,7 +311,7 @@ static void keylist_update(void)
|
||||
SendDlgItemMessage(keylist, 100, LB_ADDSTRING,
|
||||
0, (LPARAM) listentry);
|
||||
}
|
||||
for (i = 0; NULL != (skey = index234(ssh2keys, i)); i++) {
|
||||
for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) {
|
||||
char *listentry, *p;
|
||||
int pos, fp_len;
|
||||
/*
|
||||
@ -639,7 +603,7 @@ static void add_keyfile(Filename *filename)
|
||||
sfree(request);
|
||||
sfree(response);
|
||||
} else {
|
||||
if (add234(rsakeys, rkey) != rkey)
|
||||
if (!pageant_add_ssh1_key(rkey))
|
||||
sfree(rkey); /* already present, don't waste RAM */
|
||||
}
|
||||
} else {
|
||||
@ -686,7 +650,7 @@ static void add_keyfile(Filename *filename)
|
||||
sfree(request);
|
||||
sfree(response);
|
||||
} else {
|
||||
if (add234(ssh2keys, skey) != skey) {
|
||||
if (!pageant_add_ssh2_key(skey)) {
|
||||
skey->alg->freekey(skey->data);
|
||||
sfree(skey); /* already present, don't waste RAM */
|
||||
}
|
||||
@ -694,105 +658,10 @@ static void add_keyfile(Filename *filename)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an SSH-1 key list in a malloc'ed buffer; return its
|
||||
* length.
|
||||
*/
|
||||
static void *make_keylist1(int *length)
|
||||
{
|
||||
int i, nkeys, len;
|
||||
struct RSAKey *key;
|
||||
unsigned char *blob, *p, *ret;
|
||||
int bloblen;
|
||||
|
||||
/*
|
||||
* Count up the number and length of keys we hold.
|
||||
*/
|
||||
len = 4;
|
||||
nkeys = 0;
|
||||
for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
|
||||
nkeys++;
|
||||
blob = rsa_public_blob(key, &bloblen);
|
||||
len += bloblen;
|
||||
sfree(blob);
|
||||
len += 4 + strlen(key->comment);
|
||||
}
|
||||
|
||||
/* Allocate the buffer. */
|
||||
p = ret = snewn(len, unsigned char);
|
||||
if (length) *length = len;
|
||||
|
||||
PUT_32BIT(p, nkeys);
|
||||
p += 4;
|
||||
for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
|
||||
blob = rsa_public_blob(key, &bloblen);
|
||||
memcpy(p, blob, bloblen);
|
||||
p += bloblen;
|
||||
sfree(blob);
|
||||
PUT_32BIT(p, strlen(key->comment));
|
||||
memcpy(p + 4, key->comment, strlen(key->comment));
|
||||
p += 4 + strlen(key->comment);
|
||||
}
|
||||
|
||||
assert(p - ret == len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an SSH-2 key list in a malloc'ed buffer; return its
|
||||
* length.
|
||||
*/
|
||||
static void *make_keylist2(int *length)
|
||||
{
|
||||
struct ssh2_userkey *key;
|
||||
int i, len, nkeys;
|
||||
unsigned char *blob, *p, *ret;
|
||||
int bloblen;
|
||||
|
||||
/*
|
||||
* Count up the number and length of keys we hold.
|
||||
*/
|
||||
len = 4;
|
||||
nkeys = 0;
|
||||
for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
|
||||
nkeys++;
|
||||
len += 4; /* length field */
|
||||
blob = key->alg->public_blob(key->data, &bloblen);
|
||||
len += bloblen;
|
||||
sfree(blob);
|
||||
len += 4 + strlen(key->comment);
|
||||
}
|
||||
|
||||
/* Allocate the buffer. */
|
||||
p = ret = snewn(len, unsigned char);
|
||||
if (length) *length = len;
|
||||
|
||||
/*
|
||||
* Packet header is the obvious five bytes, plus four
|
||||
* bytes for the key count.
|
||||
*/
|
||||
PUT_32BIT(p, nkeys);
|
||||
p += 4;
|
||||
for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
|
||||
blob = key->alg->public_blob(key->data, &bloblen);
|
||||
PUT_32BIT(p, bloblen);
|
||||
p += 4;
|
||||
memcpy(p, blob, bloblen);
|
||||
p += bloblen;
|
||||
sfree(blob);
|
||||
PUT_32BIT(p, strlen(key->comment));
|
||||
memcpy(p + 4, key->comment, strlen(key->comment));
|
||||
p += 4 + strlen(key->comment);
|
||||
}
|
||||
|
||||
assert(p - ret == len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Acquire a keylist1 from the primary Pageant; this means either
|
||||
* calling make_keylist1 (if that's us) or sending a message to the
|
||||
* primary Pageant (if it's not).
|
||||
* calling pageant_make_keylist1 (if that's us) or sending a message
|
||||
* to the primary Pageant (if it's not).
|
||||
*/
|
||||
static void *get_keylist1(int *length)
|
||||
{
|
||||
@ -820,15 +689,15 @@ static void *get_keylist1(int *length)
|
||||
if (length)
|
||||
*length = resplen-5;
|
||||
} else {
|
||||
ret = make_keylist1(length);
|
||||
ret = pageant_make_keylist1(length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Acquire a keylist2 from the primary Pageant; this means either
|
||||
* calling make_keylist2 (if that's us) or sending a message to the
|
||||
* primary Pageant (if it's not).
|
||||
* calling pageant_make_keylist2 (if that's us) or sending a message
|
||||
* to the primary Pageant (if it's not).
|
||||
*/
|
||||
static void *get_keylist2(int *length)
|
||||
{
|
||||
@ -857,575 +726,37 @@ static void *get_keylist2(int *length)
|
||||
if (length)
|
||||
*length = resplen-5;
|
||||
} else {
|
||||
ret = make_keylist2(length);
|
||||
ret = pageant_make_keylist2(length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main agent function that answers messages.
|
||||
*/
|
||||
static void answer_msg(void *msg)
|
||||
static void answer_msg(void *msgv)
|
||||
{
|
||||
unsigned char *p = msg;
|
||||
unsigned char *ret = msg;
|
||||
unsigned char *msgend;
|
||||
int type;
|
||||
unsigned char *msg = (unsigned char *)msgv;
|
||||
unsigned msglen;
|
||||
void *reply;
|
||||
int replylen;
|
||||
|
||||
/*
|
||||
* Get the message length.
|
||||
*/
|
||||
msgend = p + 4 + GET_32BIT(p);
|
||||
|
||||
/*
|
||||
* Get the message type.
|
||||
*/
|
||||
if (msgend < p+5)
|
||||
goto failure;
|
||||
type = p[4];
|
||||
|
||||
p += 5;
|
||||
switch (type) {
|
||||
case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
|
||||
/*
|
||||
* Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
|
||||
*/
|
||||
{
|
||||
int len;
|
||||
void *keylist;
|
||||
|
||||
ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
|
||||
keylist = make_keylist1(&len);
|
||||
if (len + 5 > AGENT_MAX_MSGLEN) {
|
||||
sfree(keylist);
|
||||
goto failure;
|
||||
}
|
||||
PUT_32BIT(ret, len + 1);
|
||||
memcpy(ret + 5, keylist, len);
|
||||
sfree(keylist);
|
||||
}
|
||||
break;
|
||||
case SSH2_AGENTC_REQUEST_IDENTITIES:
|
||||
/*
|
||||
* Reply with SSH2_AGENT_IDENTITIES_ANSWER.
|
||||
*/
|
||||
{
|
||||
int len;
|
||||
void *keylist;
|
||||
|
||||
ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
|
||||
keylist = make_keylist2(&len);
|
||||
if (len + 5 > AGENT_MAX_MSGLEN) {
|
||||
sfree(keylist);
|
||||
goto failure;
|
||||
}
|
||||
PUT_32BIT(ret, len + 1);
|
||||
memcpy(ret + 5, keylist, len);
|
||||
sfree(keylist);
|
||||
}
|
||||
break;
|
||||
case SSH1_AGENTC_RSA_CHALLENGE:
|
||||
/*
|
||||
* Reply with either SSH1_AGENT_RSA_RESPONSE or
|
||||
* SSH_AGENT_FAILURE, depending on whether we have that key
|
||||
* or not.
|
||||
*/
|
||||
{
|
||||
struct RSAKey reqkey, *key;
|
||||
Bignum challenge, response;
|
||||
unsigned char response_source[48], response_md5[16];
|
||||
struct MD5Context md5c;
|
||||
int i, len;
|
||||
|
||||
p += 4;
|
||||
i = ssh1_read_bignum(p, msgend - p, &reqkey.exponent);
|
||||
if (i < 0)
|
||||
goto failure;
|
||||
p += i;
|
||||
i = ssh1_read_bignum(p, msgend - p, &reqkey.modulus);
|
||||
if (i < 0) {
|
||||
freebn(reqkey.exponent);
|
||||
goto failure;
|
||||
}
|
||||
p += i;
|
||||
i = ssh1_read_bignum(p, msgend - p, &challenge);
|
||||
if (i < 0) {
|
||||
freebn(reqkey.exponent);
|
||||
freebn(reqkey.modulus);
|
||||
goto failure;
|
||||
}
|
||||
p += i;
|
||||
if (msgend < p+16) {
|
||||
freebn(reqkey.exponent);
|
||||
freebn(reqkey.modulus);
|
||||
freebn(challenge);
|
||||
goto failure;
|
||||
}
|
||||
memcpy(response_source + 32, p, 16);
|
||||
p += 16;
|
||||
if (msgend < p+4 ||
|
||||
GET_32BIT(p) != 1 ||
|
||||
(key = find234(rsakeys, &reqkey, NULL)) == NULL) {
|
||||
freebn(reqkey.exponent);
|
||||
freebn(reqkey.modulus);
|
||||
freebn(challenge);
|
||||
goto failure;
|
||||
}
|
||||
response = rsadecrypt(challenge, key);
|
||||
for (i = 0; i < 32; i++)
|
||||
response_source[i] = bignum_byte(response, 31 - i);
|
||||
|
||||
MD5Init(&md5c);
|
||||
MD5Update(&md5c, response_source, 48);
|
||||
MD5Final(response_md5, &md5c);
|
||||
smemclr(response_source, 48); /* burn the evidence */
|
||||
freebn(response); /* and that evidence */
|
||||
freebn(challenge); /* yes, and that evidence */
|
||||
freebn(reqkey.exponent); /* and free some memory ... */
|
||||
freebn(reqkey.modulus); /* ... while we're at it. */
|
||||
|
||||
/*
|
||||
* Packet is the obvious five byte header, plus sixteen
|
||||
* bytes of MD5.
|
||||
*/
|
||||
len = 5 + 16;
|
||||
PUT_32BIT(ret, len - 4);
|
||||
ret[4] = SSH1_AGENT_RSA_RESPONSE;
|
||||
memcpy(ret + 5, response_md5, 16);
|
||||
}
|
||||
break;
|
||||
case SSH2_AGENTC_SIGN_REQUEST:
|
||||
/*
|
||||
* Reply with either SSH2_AGENT_SIGN_RESPONSE or
|
||||
* SSH_AGENT_FAILURE, depending on whether we have that key
|
||||
* or not.
|
||||
*/
|
||||
{
|
||||
struct ssh2_userkey *key;
|
||||
struct blob b;
|
||||
unsigned char *data, *signature;
|
||||
int datalen, siglen, len;
|
||||
|
||||
if (msgend < p+4)
|
||||
goto failure;
|
||||
b.len = toint(GET_32BIT(p));
|
||||
if (b.len < 0 || b.len > msgend - (p+4))
|
||||
goto failure;
|
||||
p += 4;
|
||||
b.blob = p;
|
||||
p += b.len;
|
||||
if (msgend < p+4)
|
||||
goto failure;
|
||||
datalen = toint(GET_32BIT(p));
|
||||
p += 4;
|
||||
if (datalen < 0 || datalen > msgend - p)
|
||||
goto failure;
|
||||
data = p;
|
||||
key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
|
||||
if (!key)
|
||||
goto failure;
|
||||
signature = key->alg->sign(key->data, data, datalen, &siglen);
|
||||
len = 5 + 4 + siglen;
|
||||
PUT_32BIT(ret, len - 4);
|
||||
ret[4] = SSH2_AGENT_SIGN_RESPONSE;
|
||||
PUT_32BIT(ret + 5, siglen);
|
||||
memcpy(ret + 5 + 4, signature, siglen);
|
||||
sfree(signature);
|
||||
}
|
||||
break;
|
||||
case SSH1_AGENTC_ADD_RSA_IDENTITY:
|
||||
/*
|
||||
* Add to the list and return SSH_AGENT_SUCCESS, or
|
||||
* SSH_AGENT_FAILURE if the key was malformed.
|
||||
*/
|
||||
{
|
||||
struct RSAKey *key;
|
||||
char *comment;
|
||||
int n, commentlen;
|
||||
|
||||
key = snew(struct RSAKey);
|
||||
memset(key, 0, sizeof(struct RSAKey));
|
||||
|
||||
n = makekey(p, msgend - p, key, NULL, 1);
|
||||
if (n < 0) {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
p += n;
|
||||
|
||||
n = makeprivate(p, msgend - p, key);
|
||||
if (n < 0) {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
p += n;
|
||||
|
||||
n = ssh1_read_bignum(p, msgend - p, &key->iqmp); /* p^-1 mod q */
|
||||
if (n < 0) {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
p += n;
|
||||
|
||||
n = ssh1_read_bignum(p, msgend - p, &key->p); /* p */
|
||||
if (n < 0) {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
p += n;
|
||||
|
||||
n = ssh1_read_bignum(p, msgend - p, &key->q); /* q */
|
||||
if (n < 0) {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
p += n;
|
||||
|
||||
if (msgend < p+4) {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
commentlen = toint(GET_32BIT(p));
|
||||
|
||||
if (commentlen < 0 || commentlen > msgend - p) {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
comment = snewn(commentlen+1, char);
|
||||
if (comment) {
|
||||
memcpy(comment, p + 4, commentlen);
|
||||
comment[commentlen] = '\0';
|
||||
key->comment = comment;
|
||||
}
|
||||
PUT_32BIT(ret, 1);
|
||||
ret[4] = SSH_AGENT_FAILURE;
|
||||
if (add234(rsakeys, key) == key) {
|
||||
keylist_update();
|
||||
ret[4] = SSH_AGENT_SUCCESS;
|
||||
} else {
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH2_AGENTC_ADD_IDENTITY:
|
||||
/*
|
||||
* Add to the list and return SSH_AGENT_SUCCESS, or
|
||||
* SSH_AGENT_FAILURE if the key was malformed.
|
||||
*/
|
||||
{
|
||||
struct ssh2_userkey *key;
|
||||
char *comment, *alg;
|
||||
int alglen, commlen;
|
||||
int bloblen;
|
||||
|
||||
|
||||
if (msgend < p+4)
|
||||
goto failure;
|
||||
alglen = toint(GET_32BIT(p));
|
||||
p += 4;
|
||||
if (alglen < 0 || alglen > msgend - p)
|
||||
goto failure;
|
||||
alg = p;
|
||||
p += alglen;
|
||||
|
||||
key = snew(struct ssh2_userkey);
|
||||
/* Add further algorithm names here. */
|
||||
if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7))
|
||||
key->alg = &ssh_rsa;
|
||||
else if (alglen == 7 && !memcmp(alg, "ssh-dss", 7))
|
||||
key->alg = &ssh_dss;
|
||||
else if (alglen == 19 && memcmp(alg, "ecdsa-sha2-nistp256", 19))
|
||||
key->alg = &ssh_ecdsa_nistp256;
|
||||
else if (alglen == 19 && memcmp(alg, "ecdsa-sha2-nistp384", 19))
|
||||
key->alg = &ssh_ecdsa_nistp384;
|
||||
else if (alglen == 19 && memcmp(alg, "ecdsa-sha2-nistp521", 19))
|
||||
key->alg = &ssh_ecdsa_nistp521;
|
||||
else {
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
bloblen = msgend - p;
|
||||
key->data = key->alg->openssh_createkey(&p, &bloblen);
|
||||
if (!key->data) {
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/*
|
||||
* p has been advanced by openssh_createkey, but
|
||||
* certainly not _beyond_ the end of the buffer.
|
||||
*/
|
||||
assert(p <= msgend);
|
||||
|
||||
if (msgend < p+4) {
|
||||
key->alg->freekey(key->data);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
commlen = toint(GET_32BIT(p));
|
||||
p += 4;
|
||||
|
||||
if (commlen < 0 || commlen > msgend - p) {
|
||||
key->alg->freekey(key->data);
|
||||
sfree(key);
|
||||
goto failure;
|
||||
}
|
||||
comment = snewn(commlen + 1, char);
|
||||
if (comment) {
|
||||
memcpy(comment, p, commlen);
|
||||
comment[commlen] = '\0';
|
||||
}
|
||||
key->comment = comment;
|
||||
|
||||
PUT_32BIT(ret, 1);
|
||||
ret[4] = SSH_AGENT_FAILURE;
|
||||
if (add234(ssh2keys, key) == key) {
|
||||
keylist_update();
|
||||
ret[4] = SSH_AGENT_SUCCESS;
|
||||
} else {
|
||||
key->alg->freekey(key->data);
|
||||
sfree(key->comment);
|
||||
sfree(key);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH1_AGENTC_REMOVE_RSA_IDENTITY:
|
||||
/*
|
||||
* Remove from the list and return SSH_AGENT_SUCCESS, or
|
||||
* perhaps SSH_AGENT_FAILURE if it wasn't in the list to
|
||||
* start with.
|
||||
*/
|
||||
{
|
||||
struct RSAKey reqkey, *key;
|
||||
int n;
|
||||
|
||||
n = makekey(p, msgend - p, &reqkey, NULL, 0);
|
||||
if (n < 0)
|
||||
goto failure;
|
||||
|
||||
key = find234(rsakeys, &reqkey, NULL);
|
||||
freebn(reqkey.exponent);
|
||||
freebn(reqkey.modulus);
|
||||
PUT_32BIT(ret, 1);
|
||||
ret[4] = SSH_AGENT_FAILURE;
|
||||
if (key) {
|
||||
del234(rsakeys, key);
|
||||
keylist_update();
|
||||
freersakey(key);
|
||||
sfree(key);
|
||||
ret[4] = SSH_AGENT_SUCCESS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH2_AGENTC_REMOVE_IDENTITY:
|
||||
/*
|
||||
* Remove from the list and return SSH_AGENT_SUCCESS, or
|
||||
* perhaps SSH_AGENT_FAILURE if it wasn't in the list to
|
||||
* start with.
|
||||
*/
|
||||
{
|
||||
struct ssh2_userkey *key;
|
||||
struct blob b;
|
||||
|
||||
if (msgend < p+4)
|
||||
goto failure;
|
||||
b.len = toint(GET_32BIT(p));
|
||||
p += 4;
|
||||
|
||||
if (b.len < 0 || b.len > msgend - p)
|
||||
goto failure;
|
||||
b.blob = p;
|
||||
p += b.len;
|
||||
|
||||
key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm);
|
||||
if (!key)
|
||||
goto failure;
|
||||
|
||||
PUT_32BIT(ret, 1);
|
||||
ret[4] = SSH_AGENT_FAILURE;
|
||||
if (key) {
|
||||
del234(ssh2keys, key);
|
||||
keylist_update();
|
||||
key->alg->freekey(key->data);
|
||||
sfree(key);
|
||||
ret[4] = SSH_AGENT_SUCCESS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
|
||||
/*
|
||||
* Remove all SSH-1 keys. Always returns success.
|
||||
*/
|
||||
{
|
||||
struct RSAKey *rkey;
|
||||
|
||||
while ((rkey = index234(rsakeys, 0)) != NULL) {
|
||||
del234(rsakeys, rkey);
|
||||
freersakey(rkey);
|
||||
sfree(rkey);
|
||||
}
|
||||
keylist_update();
|
||||
|
||||
PUT_32BIT(ret, 1);
|
||||
ret[4] = SSH_AGENT_SUCCESS;
|
||||
}
|
||||
break;
|
||||
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
|
||||
/*
|
||||
* Remove all SSH-2 keys. Always returns success.
|
||||
*/
|
||||
{
|
||||
struct ssh2_userkey *skey;
|
||||
|
||||
while ((skey = index234(ssh2keys, 0)) != NULL) {
|
||||
del234(ssh2keys, skey);
|
||||
skey->alg->freekey(skey->data);
|
||||
sfree(skey);
|
||||
}
|
||||
keylist_update();
|
||||
|
||||
PUT_32BIT(ret, 1);
|
||||
ret[4] = SSH_AGENT_SUCCESS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
failure:
|
||||
/*
|
||||
* Unrecognised message. Return SSH_AGENT_FAILURE.
|
||||
*/
|
||||
PUT_32BIT(ret, 1);
|
||||
ret[4] = SSH_AGENT_FAILURE;
|
||||
break;
|
||||
msglen = GET_32BIT(msg);
|
||||
if (msglen > AGENT_MAX_MSGLEN) {
|
||||
reply = pageant_failure_msg(&replylen);
|
||||
} else {
|
||||
reply = pageant_handle_msg(msg + 4, msglen, &replylen);
|
||||
if (replylen > AGENT_MAX_MSGLEN) {
|
||||
smemclr(reply, replylen);
|
||||
sfree(reply);
|
||||
reply = pageant_failure_msg(&replylen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Key comparison function for the 2-3-4 tree of RSA keys.
|
||||
*/
|
||||
static int cmpkeys_rsa(void *av, void *bv)
|
||||
{
|
||||
struct RSAKey *a = (struct RSAKey *) av;
|
||||
struct RSAKey *b = (struct RSAKey *) bv;
|
||||
Bignum am, bm;
|
||||
int alen, blen;
|
||||
|
||||
am = a->modulus;
|
||||
bm = b->modulus;
|
||||
/*
|
||||
* Compare by length of moduli.
|
||||
*/
|
||||
alen = bignum_bitcount(am);
|
||||
blen = bignum_bitcount(bm);
|
||||
if (alen > blen)
|
||||
return +1;
|
||||
else if (alen < blen)
|
||||
return -1;
|
||||
/*
|
||||
* Now compare by moduli themselves.
|
||||
*/
|
||||
alen = (alen + 7) / 8; /* byte count */
|
||||
while (alen-- > 0) {
|
||||
int abyte, bbyte;
|
||||
abyte = bignum_byte(am, alen);
|
||||
bbyte = bignum_byte(bm, alen);
|
||||
if (abyte > bbyte)
|
||||
return +1;
|
||||
else if (abyte < bbyte)
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Give up.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Key comparison function for the 2-3-4 tree of SSH-2 keys.
|
||||
*/
|
||||
static int cmpkeys_ssh2(void *av, void *bv)
|
||||
{
|
||||
struct ssh2_userkey *a = (struct ssh2_userkey *) av;
|
||||
struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
|
||||
int i;
|
||||
int alen, blen;
|
||||
unsigned char *ablob, *bblob;
|
||||
int c;
|
||||
|
||||
/*
|
||||
* Compare purely by public blob.
|
||||
* Windows Pageant answers messages in place, by overwriting the
|
||||
* input message buffer.
|
||||
*/
|
||||
ablob = a->alg->public_blob(a->data, &alen);
|
||||
bblob = b->alg->public_blob(b->data, &blen);
|
||||
|
||||
c = 0;
|
||||
for (i = 0; i < alen && i < blen; i++) {
|
||||
if (ablob[i] < bblob[i]) {
|
||||
c = -1;
|
||||
break;
|
||||
} else if (ablob[i] > bblob[i]) {
|
||||
c = +1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == 0 && i < alen)
|
||||
c = +1; /* a is longer */
|
||||
if (c == 0 && i < blen)
|
||||
c = -1; /* a is longer */
|
||||
|
||||
sfree(ablob);
|
||||
sfree(bblob);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
* Key comparison function for looking up a blob in the 2-3-4 tree
|
||||
* of SSH-2 keys.
|
||||
*/
|
||||
static int cmpkeys_ssh2_asymm(void *av, void *bv)
|
||||
{
|
||||
struct blob *a = (struct blob *) av;
|
||||
struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
|
||||
int i;
|
||||
int alen, blen;
|
||||
unsigned char *ablob, *bblob;
|
||||
int c;
|
||||
|
||||
/*
|
||||
* Compare purely by public blob.
|
||||
*/
|
||||
ablob = a->blob;
|
||||
alen = a->len;
|
||||
bblob = b->alg->public_blob(b->data, &blen);
|
||||
|
||||
c = 0;
|
||||
for (i = 0; i < alen && i < blen; i++) {
|
||||
if (ablob[i] < bblob[i]) {
|
||||
c = -1;
|
||||
break;
|
||||
} else if (ablob[i] > bblob[i]) {
|
||||
c = +1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c == 0 && i < alen)
|
||||
c = +1; /* a is longer */
|
||||
if (c == 0 && i < blen)
|
||||
c = -1; /* a is longer */
|
||||
|
||||
sfree(bblob);
|
||||
|
||||
return c;
|
||||
memcpy(msg, reply, replylen);
|
||||
smemclr(reply, replylen);
|
||||
sfree(reply);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1567,35 +898,35 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
|
||||
numSelected, (WPARAM)selectedArray);
|
||||
|
||||
itemNum = numSelected - 1;
|
||||
rCount = count234(rsakeys);
|
||||
sCount = count234(ssh2keys);
|
||||
rCount = pageant_count_ssh1_keys();
|
||||
sCount = pageant_count_ssh2_keys();
|
||||
|
||||
/* go through the non-rsakeys until we've covered them all,
|
||||
* and/or we're out of selected items to check. note that
|
||||
* we go *backwards*, to avoid complications from deleting
|
||||
* things hence altering the offset of subsequent items
|
||||
*/
|
||||
for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) {
|
||||
skey = index234(ssh2keys, i);
|
||||
for (i = sCount - 1; (itemNum >= 0) && (i >= 0); i--) {
|
||||
skey = pageant_nth_ssh2_key(i);
|
||||
|
||||
if (selectedArray[itemNum] == rCount + i) {
|
||||
del234(ssh2keys, skey);
|
||||
skey->alg->freekey(skey->data);
|
||||
sfree(skey);
|
||||
itemNum--;
|
||||
}
|
||||
if (selectedArray[itemNum] == rCount + i) {
|
||||
pageant_delete_ssh2_key(skey);
|
||||
skey->alg->freekey(skey->data);
|
||||
sfree(skey);
|
||||
itemNum--;
|
||||
}
|
||||
}
|
||||
|
||||
/* do the same for the rsa keys */
|
||||
for (i = rCount - 1; (itemNum >= 0) && (i >= 0); i--) {
|
||||
rkey = index234(rsakeys, i);
|
||||
rkey = pageant_nth_ssh1_key(i);
|
||||
|
||||
if(selectedArray[itemNum] == i) {
|
||||
del234(rsakeys, rkey);
|
||||
freersakey(rkey);
|
||||
sfree(rkey);
|
||||
itemNum--;
|
||||
}
|
||||
if(selectedArray[itemNum] == i) {
|
||||
pageant_delete_ssh1_key(rkey);
|
||||
freersakey(rkey);
|
||||
sfree(rkey);
|
||||
itemNum--;
|
||||
}
|
||||
}
|
||||
|
||||
sfree(selectedArray);
|
||||
@ -2116,11 +1447,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
||||
already_running = agent_exists();
|
||||
|
||||
/*
|
||||
* Initialise storage for RSA keys.
|
||||
* Initialise the cross-platform Pageant code.
|
||||
*/
|
||||
if (!already_running) {
|
||||
rsakeys = newtree234(cmpkeys_rsa);
|
||||
ssh2keys = newtree234(cmpkeys_ssh2);
|
||||
pageant_init();
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user