mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Add support for the OpenSSH SSH2 agent protocol.
[originally from svn r976]
This commit is contained in:
parent
deccfaa3ef
commit
1f168926d7
477
pageant.c
477
pageant.c
@ -9,6 +9,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include "putty.h" // FIXME
|
||||||
#include "ssh.h"
|
#include "ssh.h"
|
||||||
#include "tree234.h"
|
#include "tree234.h"
|
||||||
|
|
||||||
@ -33,14 +34,33 @@
|
|||||||
|
|
||||||
#define APPNAME "Pageant"
|
#define APPNAME "Pageant"
|
||||||
|
|
||||||
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
|
/*
|
||||||
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
|
* SSH1 agent messages.
|
||||||
#define SSH_AGENTC_RSA_CHALLENGE 3
|
*/
|
||||||
#define SSH_AGENT_RSA_RESPONSE 4
|
#define SSH1_AGENTC_REQUEST_RSA_IDENTITIES 1
|
||||||
|
#define SSH1_AGENT_RSA_IDENTITIES_ANSWER 2
|
||||||
|
#define SSH1_AGENTC_RSA_CHALLENGE 3
|
||||||
|
#define SSH1_AGENT_RSA_RESPONSE 4
|
||||||
|
#define SSH1_AGENTC_ADD_RSA_IDENTITY 7
|
||||||
|
#define SSH1_AGENTC_REMOVE_RSA_IDENTITY 8
|
||||||
|
#define SSH1_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 /* openssh private? */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Messages common to SSH1 and OpenSSH's SSH2.
|
||||||
|
*/
|
||||||
#define SSH_AGENT_FAILURE 5
|
#define SSH_AGENT_FAILURE 5
|
||||||
#define SSH_AGENT_SUCCESS 6
|
#define SSH_AGENT_SUCCESS 6
|
||||||
#define SSH_AGENTC_ADD_RSA_IDENTITY 7
|
|
||||||
#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8
|
/*
|
||||||
|
* OpenSSH's SSH2 agent messages.
|
||||||
|
*/
|
||||||
|
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
|
||||||
|
#define SSH2_AGENT_IDENTITIES_ANSWER 12
|
||||||
|
#define SSH2_AGENTC_SIGN_REQUEST 13
|
||||||
|
#define SSH2_AGENT_SIGN_RESPONSE 14
|
||||||
|
#define SSH2_AGENTC_ADD_IDENTITY 17
|
||||||
|
#define SSH2_AGENTC_REMOVE_IDENTITY 18
|
||||||
|
#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
|
||||||
|
|
||||||
extern char ver[];
|
extern char ver[];
|
||||||
|
|
||||||
@ -50,7 +70,7 @@ static HWND keylist;
|
|||||||
static HWND aboutbox;
|
static HWND aboutbox;
|
||||||
static HMENU systray_menu;
|
static HMENU systray_menu;
|
||||||
|
|
||||||
static tree234 *rsakeys;
|
static tree234 *rsakeys, *ssh2keys;
|
||||||
|
|
||||||
static int has_security;
|
static int has_security;
|
||||||
#ifndef NO_SECURITY
|
#ifndef NO_SECURITY
|
||||||
@ -63,9 +83,10 @@ static gsi_fn_t getsecurityinfo;
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We need this to link with the RSA code, because rsaencrypt()
|
* We need this to link with the RSA code, because rsaencrypt()
|
||||||
* pads its data with random bytes. Since we only use rsadecrypt(),
|
* pads its data with random bytes. Since we only use rsadecrypt()
|
||||||
* which is deterministic, this should never be called.
|
* and the signing functions, which are deterministic, this should
|
||||||
*
|
* never be called.
|
||||||
|
*
|
||||||
* If it _is_ called, there is a _serious_ problem, because it
|
* If it _is_ called, there is a _serious_ problem, because it
|
||||||
* won't generate true random numbers. So we must scream, panic,
|
* won't generate true random numbers. So we must scream, panic,
|
||||||
* and exit immediately if that should happen.
|
* and exit immediately if that should happen.
|
||||||
@ -75,6 +96,16 @@ int random_byte(void) {
|
|||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Blob structure for passing to the asymmetric SSH2 key compare
|
||||||
|
* function, prototyped here.
|
||||||
|
*/
|
||||||
|
struct blob {
|
||||||
|
unsigned char *blob;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
static int cmpkeys_ssh2_asymm(void *av, void *bv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is needed to link with the DES code. We need not
|
* This function is needed to link with the DES code. We need not
|
||||||
* have it do anything at all.
|
* have it do anything at all.
|
||||||
@ -164,6 +195,20 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
|
|||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
|
/*
|
||||||
|
* Centre the window.
|
||||||
|
*/
|
||||||
|
{ /* centre the window */
|
||||||
|
RECT rs, rd;
|
||||||
|
HWND hw;
|
||||||
|
|
||||||
|
hw = GetDesktopWindow();
|
||||||
|
if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
|
||||||
|
MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
|
||||||
|
(rs.bottom + rs.top + rd.top - rd.bottom)/2,
|
||||||
|
rd.right-rd.left, rd.bottom-rd.top, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
SetForegroundWindow(hwnd);
|
SetForegroundWindow(hwnd);
|
||||||
SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
|
SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
|
||||||
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
|
||||||
@ -203,23 +248,45 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
|
|||||||
* Update the visible key list.
|
* Update the visible key list.
|
||||||
*/
|
*/
|
||||||
static void keylist_update(void) {
|
static void keylist_update(void) {
|
||||||
struct RSAKey *key;
|
struct RSAKey *rkey;
|
||||||
|
struct ssh2_userkey *skey;
|
||||||
enum234 e;
|
enum234 e;
|
||||||
|
|
||||||
if (keylist) {
|
if (keylist) {
|
||||||
SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0);
|
SendDlgItemMessage(keylist, 100, LB_RESETCONTENT, 0, 0);
|
||||||
for (key = first234(rsakeys, &e); key; key = next234(&e)) {
|
for (rkey = first234(rsakeys, &e); rkey; rkey = next234(&e)) {
|
||||||
char listentry[512], *p;
|
char listentry[512], *p;
|
||||||
/*
|
/*
|
||||||
* Replace two spaces in the fingerprint with tabs, for
|
* Replace two spaces in the fingerprint with tabs, for
|
||||||
* nice alignment in the box.
|
* nice alignment in the box.
|
||||||
*/
|
*/
|
||||||
rsa_fingerprint(listentry, sizeof(listentry), key);
|
strcpy(listentry, "ssh1\t");
|
||||||
|
p = listentry+strlen(listentry);
|
||||||
|
rsa_fingerprint(p, sizeof(listentry)-(p-listentry), rkey);
|
||||||
p = strchr(listentry, ' '); if (p) *p = '\t';
|
p = strchr(listentry, ' '); if (p) *p = '\t';
|
||||||
p = strchr(listentry, ' '); if (p) *p = '\t';
|
p = strchr(listentry, ' '); if (p) *p = '\t';
|
||||||
SendDlgItemMessage (keylist, 100, LB_ADDSTRING,
|
SendDlgItemMessage (keylist, 100, LB_ADDSTRING,
|
||||||
0, (LPARAM)listentry);
|
0, (LPARAM)listentry);
|
||||||
}
|
}
|
||||||
|
for (skey = first234(ssh2keys, &e); skey; skey = next234(&e)) {
|
||||||
|
char listentry[512], *p;
|
||||||
|
int len;
|
||||||
|
/*
|
||||||
|
* Replace two spaces in the fingerprint with tabs, for
|
||||||
|
* nice alignment in the box.
|
||||||
|
*/
|
||||||
|
p = skey->alg->fingerprint(skey->data);
|
||||||
|
strncpy(listentry, p, sizeof(listentry));
|
||||||
|
p = strchr(listentry, ' '); if (p) *p = '\t';
|
||||||
|
p = strchr(listentry, ' '); if (p) *p = '\t';
|
||||||
|
len = strlen(listentry);
|
||||||
|
if (len < sizeof(listentry)-2) {
|
||||||
|
listentry[len] = '\t';
|
||||||
|
strncpy(listentry+len+1, skey->comment, sizeof(listentry)-len-1);
|
||||||
|
}
|
||||||
|
SendDlgItemMessage (keylist, 100, LB_ADDSTRING,
|
||||||
|
0, (LPARAM)listentry);
|
||||||
|
}
|
||||||
SendDlgItemMessage (keylist, 100, LB_SETCURSEL, (WPARAM) -1, 0);
|
SendDlgItemMessage (keylist, 100, LB_SETCURSEL, (WPARAM) -1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,16 +296,29 @@ static void keylist_update(void) {
|
|||||||
*/
|
*/
|
||||||
static void add_keyfile(char *filename) {
|
static void add_keyfile(char *filename) {
|
||||||
char passphrase[PASSPHRASE_MAXLEN];
|
char passphrase[PASSPHRASE_MAXLEN];
|
||||||
struct RSAKey *key;
|
struct RSAKey *rkey;
|
||||||
|
struct ssh2_userkey *skey;
|
||||||
int needs_pass;
|
int needs_pass;
|
||||||
int ret;
|
int ret;
|
||||||
int attempts;
|
int attempts;
|
||||||
char *comment;
|
char *comment;
|
||||||
struct PassphraseProcStruct pps;
|
struct PassphraseProcStruct pps;
|
||||||
|
int ver;
|
||||||
|
|
||||||
needs_pass = rsakey_encrypted(filename, &comment);
|
ver = keyfile_version(filename);
|
||||||
|
if (ver == 0) {
|
||||||
|
MessageBox(NULL, "Couldn't load private key.", APPNAME,
|
||||||
|
MB_OK | MB_ICONERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ver == 1)
|
||||||
|
needs_pass = rsakey_encrypted(filename, &comment);
|
||||||
|
else
|
||||||
|
needs_pass = ssh2_userkey_encrypted(filename, &comment);
|
||||||
attempts = 0;
|
attempts = 0;
|
||||||
key = smalloc(sizeof(*key));
|
if (ver == 1)
|
||||||
|
rkey = smalloc(sizeof(*rkey));
|
||||||
pps.passphrase = passphrase;
|
pps.passphrase = passphrase;
|
||||||
pps.comment = comment;
|
pps.comment = comment;
|
||||||
do {
|
do {
|
||||||
@ -249,23 +329,42 @@ static void add_keyfile(char *filename) {
|
|||||||
(LPARAM)&pps);
|
(LPARAM)&pps);
|
||||||
if (!dlgret) {
|
if (!dlgret) {
|
||||||
if (comment) sfree(comment);
|
if (comment) sfree(comment);
|
||||||
sfree(key);
|
if (ver == 1)
|
||||||
|
sfree(rkey);
|
||||||
return; /* operation cancelled */
|
return; /* operation cancelled */
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
*passphrase = '\0';
|
*passphrase = '\0';
|
||||||
ret = loadrsakey(filename, key, passphrase);
|
if (ver == 1)
|
||||||
|
ret = loadrsakey(filename, rkey, passphrase);
|
||||||
|
else {
|
||||||
|
skey = ssh2_load_userkey(filename, passphrase);
|
||||||
|
if (skey == SSH2_WRONG_PASSPHRASE)
|
||||||
|
ret = -1;
|
||||||
|
else if (!skey)
|
||||||
|
ret = 0;
|
||||||
|
else
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
attempts++;
|
attempts++;
|
||||||
} while (ret == -1);
|
} while (ret == -1);
|
||||||
if (comment) sfree(comment);
|
if (comment) sfree(comment);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
MessageBox(NULL, "Couldn't load private key.", APPNAME,
|
MessageBox(NULL, "Couldn't load private key.", APPNAME,
|
||||||
MB_OK | MB_ICONERROR);
|
MB_OK | MB_ICONERROR);
|
||||||
sfree(key);
|
if (ver == 1)
|
||||||
|
sfree(rkey);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (add234(rsakeys, key) != key)
|
if (ver == 1) {
|
||||||
sfree(key); /* already present, don't waste RAM */
|
if (add234(rsakeys, rkey) != rkey)
|
||||||
|
sfree(rkey); /* already present, don't waste RAM */
|
||||||
|
} else {
|
||||||
|
if (add234(ssh2keys, skey) != skey) {
|
||||||
|
skey->alg->freekey(skey->data);
|
||||||
|
sfree(skey); /* already present, don't waste RAM */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -283,9 +382,9 @@ static void answer_msg(void *msg) {
|
|||||||
|
|
||||||
p += 5;
|
p += 5;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
|
case SSH1_AGENTC_REQUEST_RSA_IDENTITIES:
|
||||||
/*
|
/*
|
||||||
* Reply with SSH_AGENT_RSA_IDENTITIES_ANSWER.
|
* Reply with SSH1_AGENT_RSA_IDENTITIES_ANSWER.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
enum234 e;
|
enum234 e;
|
||||||
@ -312,7 +411,7 @@ static void answer_msg(void *msg) {
|
|||||||
if (len > AGENT_MAX_MSGLEN)
|
if (len > AGENT_MAX_MSGLEN)
|
||||||
goto failure; /* aaargh! too much stuff! */
|
goto failure; /* aaargh! too much stuff! */
|
||||||
PUT_32BIT(ret, len-4);
|
PUT_32BIT(ret, len-4);
|
||||||
ret[4] = SSH_AGENT_RSA_IDENTITIES_ANSWER;
|
ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
|
||||||
PUT_32BIT(ret+5, nkeys);
|
PUT_32BIT(ret+5, nkeys);
|
||||||
p = ret + 5 + 4;
|
p = ret + 5 + 4;
|
||||||
for (key = first234(rsakeys, &e); key; key = next234(&e)) {
|
for (key = first234(rsakeys, &e); key; key = next234(&e)) {
|
||||||
@ -326,9 +425,57 @@ static void answer_msg(void *msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_AGENTC_RSA_CHALLENGE:
|
case SSH2_AGENTC_REQUEST_IDENTITIES:
|
||||||
/*
|
/*
|
||||||
* Reply with either SSH_AGENT_RSA_RESPONSE or
|
* Reply with SSH2_AGENT_IDENTITIES_ANSWER.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
enum234 e;
|
||||||
|
struct ssh2_userkey *key;
|
||||||
|
int len, nkeys;
|
||||||
|
unsigned char *blob;
|
||||||
|
int bloblen;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count up the number and length of keys we hold.
|
||||||
|
*/
|
||||||
|
len = nkeys = 0;
|
||||||
|
for (key = first234(ssh2keys, &e); key; key = next234(&e)) {
|
||||||
|
nkeys++;
|
||||||
|
len += 4; /* length field */
|
||||||
|
blob = key->alg->public_blob(key->data, &bloblen);
|
||||||
|
len += bloblen;
|
||||||
|
sfree(blob);
|
||||||
|
len += 4 + strlen(key->comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Packet header is the obvious five bytes, plus four
|
||||||
|
* bytes for the key count.
|
||||||
|
*/
|
||||||
|
len += 5 + 4;
|
||||||
|
if (len > AGENT_MAX_MSGLEN)
|
||||||
|
goto failure; /* aaargh! too much stuff! */
|
||||||
|
PUT_32BIT(ret, len-4);
|
||||||
|
ret[4] = SSH2_AGENT_IDENTITIES_ANSWER;
|
||||||
|
PUT_32BIT(ret+5, nkeys);
|
||||||
|
p = ret + 5 + 4;
|
||||||
|
for (key = first234(ssh2keys, &e); key; key = next234(&e)) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SSH1_AGENTC_RSA_CHALLENGE:
|
||||||
|
/*
|
||||||
|
* Reply with either SSH1_AGENT_RSA_RESPONSE or
|
||||||
* SSH_AGENT_FAILURE, depending on whether we have that key
|
* SSH_AGENT_FAILURE, depending on whether we have that key
|
||||||
* or not.
|
* or not.
|
||||||
*/
|
*/
|
||||||
@ -370,11 +517,42 @@ static void answer_msg(void *msg) {
|
|||||||
*/
|
*/
|
||||||
len = 5 + 16;
|
len = 5 + 16;
|
||||||
PUT_32BIT(ret, len-4);
|
PUT_32BIT(ret, len-4);
|
||||||
ret[4] = SSH_AGENT_RSA_RESPONSE;
|
ret[4] = SSH1_AGENT_RSA_RESPONSE;
|
||||||
memcpy(ret+5, response_md5, 16);
|
memcpy(ret+5, response_md5, 16);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_AGENTC_ADD_RSA_IDENTITY:
|
case SSH2_AGENTC_SIGN_REQUEST:
|
||||||
|
/*
|
||||||
|
* Reply with either SSH2_AGENT_RSA_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;
|
||||||
|
|
||||||
|
b.len = GET_32BIT(p);
|
||||||
|
p += 4;
|
||||||
|
b.blob = p;
|
||||||
|
p += b.len;
|
||||||
|
datalen = GET_32BIT(p);
|
||||||
|
p += 4;
|
||||||
|
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
|
* Add to the list and return SSH_AGENT_SUCCESS, or
|
||||||
* SSH_AGENT_FAILURE if the key was malformed.
|
* SSH_AGENT_FAILURE if the key was malformed.
|
||||||
@ -386,9 +564,9 @@ static void answer_msg(void *msg) {
|
|||||||
memset(key, 0, sizeof(key));
|
memset(key, 0, sizeof(key));
|
||||||
p += makekey(p, key, NULL, 1);
|
p += makekey(p, key, NULL, 1);
|
||||||
p += makeprivate(p, key);
|
p += makeprivate(p, key);
|
||||||
p += ssh1_read_bignum(p, NULL); /* p^-1 mod q */
|
p += ssh1_read_bignum(p, key->iqmp); /* p^-1 mod q */
|
||||||
p += ssh1_read_bignum(p, NULL); /* p */
|
p += ssh1_read_bignum(p, key->p); /* p */
|
||||||
p += ssh1_read_bignum(p, NULL); /* q */
|
p += ssh1_read_bignum(p, key->q); /* q */
|
||||||
comment = smalloc(GET_32BIT(p));
|
comment = smalloc(GET_32BIT(p));
|
||||||
if (comment) {
|
if (comment) {
|
||||||
memcpy(comment, p+4, GET_32BIT(p));
|
memcpy(comment, p+4, GET_32BIT(p));
|
||||||
@ -405,7 +583,57 @@ static void answer_msg(void *msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_AGENTC_REMOVE_RSA_IDENTITY:
|
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;
|
||||||
|
|
||||||
|
key = smalloc(sizeof(struct ssh2_userkey));
|
||||||
|
|
||||||
|
alglen = GET_32BIT(p); p += 4;
|
||||||
|
alg = p; p += alglen;
|
||||||
|
/* Add further algorithm names here. */
|
||||||
|
if (alglen == 7 && !memcmp(alg, "ssh-rsa", 7))
|
||||||
|
key->alg = &ssh_rsa;
|
||||||
|
else {
|
||||||
|
sfree(key);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
bloblen = GET_32BIT((unsigned char *)msg) - (p-(unsigned char *)msg-4);
|
||||||
|
key->data = key->alg->openssh_createkey(&p, &bloblen);
|
||||||
|
if (!key->data) {
|
||||||
|
sfree(key);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
commlen = GET_32BIT(p); p += 4;
|
||||||
|
|
||||||
|
comment = smalloc(commlen+1);
|
||||||
|
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
|
* Remove from the list and return SSH_AGENT_SUCCESS, or
|
||||||
* perhaps SSH_AGENT_FAILURE if it wasn't in the list to
|
* perhaps SSH_AGENT_FAILURE if it wasn't in the list to
|
||||||
@ -424,10 +652,78 @@ static void answer_msg(void *msg) {
|
|||||||
del234(rsakeys, key);
|
del234(rsakeys, key);
|
||||||
keylist_update();
|
keylist_update();
|
||||||
freersakey(key);
|
freersakey(key);
|
||||||
|
sfree(key);
|
||||||
ret[4] = SSH_AGENT_SUCCESS;
|
ret[4] = SSH_AGENT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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;
|
||||||
|
|
||||||
|
b.len = GET_32BIT(p);
|
||||||
|
p += 4;
|
||||||
|
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 SSH1 keys. Always returns success.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
struct RSAKey *rkey;
|
||||||
|
enum234 e;
|
||||||
|
|
||||||
|
while ( (rkey = first234(rsakeys, &e)) != 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 SSH2 keys. Always returns success.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
struct ssh2_userkey *skey;
|
||||||
|
enum234 e;
|
||||||
|
|
||||||
|
while ( (skey = first234(ssh2keys, &e)) != NULL ) {
|
||||||
|
del234(ssh2keys, skey);
|
||||||
|
skey->alg->freekey(skey->data);
|
||||||
|
sfree(skey);
|
||||||
|
}
|
||||||
|
keylist_update();
|
||||||
|
|
||||||
|
PUT_32BIT(ret, 1);
|
||||||
|
ret[4] = SSH_AGENT_SUCCESS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
failure:
|
failure:
|
||||||
/*
|
/*
|
||||||
@ -442,7 +738,7 @@ static void answer_msg(void *msg) {
|
|||||||
/*
|
/*
|
||||||
* Key comparison function for the 2-3-4 tree of RSA keys.
|
* Key comparison function for the 2-3-4 tree of RSA keys.
|
||||||
*/
|
*/
|
||||||
static int cmpkeys(void *av, void *bv) {
|
static int cmpkeys_rsa(void *av, void *bv) {
|
||||||
struct RSAKey *a = (struct RSAKey *)av;
|
struct RSAKey *a = (struct RSAKey *)av;
|
||||||
struct RSAKey *b = (struct RSAKey *)bv;
|
struct RSAKey *b = (struct RSAKey *)bv;
|
||||||
Bignum am, bm;
|
Bignum am, bm;
|
||||||
@ -472,6 +768,75 @@ static int cmpkeys(void *av, void *bv) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Key comparison function for the 2-3-4 tree of SSH2 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.
|
||||||
|
*/
|
||||||
|
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 SSH2 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;
|
||||||
|
}
|
||||||
|
|
||||||
static void error(char *s) {
|
static void error(char *s) {
|
||||||
MessageBox(hwnd, s, APPNAME, MB_OK | MB_ICONERROR);
|
MessageBox(hwnd, s, APPNAME, MB_OK | MB_ICONERROR);
|
||||||
}
|
}
|
||||||
@ -510,15 +875,30 @@ static void prompt_add_keyfile(void) {
|
|||||||
static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
|
static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
|
||||||
WPARAM wParam, LPARAM lParam) {
|
WPARAM wParam, LPARAM lParam) {
|
||||||
enum234 e;
|
enum234 e;
|
||||||
struct RSAKey *key;
|
struct RSAKey *rkey;
|
||||||
|
struct ssh2_userkey *skey;
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
|
/*
|
||||||
|
* Centre the window.
|
||||||
|
*/
|
||||||
|
{ /* centre the window */
|
||||||
|
RECT rs, rd;
|
||||||
|
HWND hw;
|
||||||
|
|
||||||
|
hw = GetDesktopWindow();
|
||||||
|
if (GetWindowRect (hw, &rs) && GetWindowRect (hwnd, &rd))
|
||||||
|
MoveWindow (hwnd, (rs.right + rs.left + rd.left - rd.right)/2,
|
||||||
|
(rs.bottom + rs.top + rd.top - rd.bottom)/2,
|
||||||
|
rd.right-rd.left, rd.bottom-rd.top, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
keylist = hwnd;
|
keylist = hwnd;
|
||||||
{
|
{
|
||||||
static int tabs[2] = {25, 175};
|
static int tabs[] = {35, 60, 210};
|
||||||
SendDlgItemMessage (hwnd, 100, LB_SETTABSTOPS, 2,
|
SendDlgItemMessage (hwnd, 100, LB_SETTABSTOPS,
|
||||||
(LPARAM) tabs);
|
sizeof(tabs)/sizeof(*tabs), (LPARAM) tabs);
|
||||||
}
|
}
|
||||||
keylist_update();
|
keylist_update();
|
||||||
return 0;
|
return 0;
|
||||||
@ -543,11 +923,23 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
|
|||||||
MessageBeep(0);
|
MessageBeep(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (key = first234(rsakeys, &e); key; key = next234(&e))
|
for (rkey = first234(rsakeys, &e); rkey; rkey = next234(&e))
|
||||||
if (n-- == 0)
|
if (n-- == 0)
|
||||||
break;
|
break;
|
||||||
del234(rsakeys, key);
|
if (rkey) {
|
||||||
freersakey(key); free(key);
|
del234(rsakeys, rkey);
|
||||||
|
freersakey(rkey);
|
||||||
|
sfree(rkey);
|
||||||
|
} else {
|
||||||
|
for (skey = first234(ssh2keys, &e); skey; skey = next234(&e))
|
||||||
|
if (n-- == 0)
|
||||||
|
break;
|
||||||
|
if (skey) {
|
||||||
|
del234(ssh2keys, skey);
|
||||||
|
skey->alg->freekey(skey->data);
|
||||||
|
sfree(skey);
|
||||||
|
}
|
||||||
|
}
|
||||||
keylist_update();
|
keylist_update();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -830,10 +1222,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
|
|||||||
/*
|
/*
|
||||||
* Initialise storage for RSA keys.
|
* Initialise storage for RSA keys.
|
||||||
*/
|
*/
|
||||||
rsakeys = newtree234(cmpkeys);
|
rsakeys = newtree234(cmpkeys_rsa);
|
||||||
|
ssh2keys = newtree234(cmpkeys_ssh2);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process the command line and add RSA keys as listed on it.
|
* Process the command line and add keys as listed on it.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
|
10
pageant.rc
10
pageant.rc
@ -18,16 +18,16 @@ BEGIN
|
|||||||
PUSHBUTTON "&Cancel", IDCANCEL, 80, 42, 40, 14
|
PUSHBUTTON "&Cancel", IDCANCEL, 80, 42, 40, 14
|
||||||
END
|
END
|
||||||
|
|
||||||
211 DIALOG DISCARDABLE 0, 0, 300, 200
|
211 DIALOG DISCARDABLE 0, 0, 330, 200
|
||||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
CAPTION "Pageant Key List"
|
CAPTION "Pageant Key List"
|
||||||
FONT 8, "MS Sans Serif"
|
FONT 8, "MS Sans Serif"
|
||||||
BEGIN
|
BEGIN
|
||||||
LISTBOX 100, 10, 10, 280, 155,
|
LISTBOX 100, 10, 10, 310, 155,
|
||||||
LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP
|
LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP
|
||||||
PUSHBUTTON "&Add Key", 101, 60, 162, 60, 14
|
PUSHBUTTON "&Add Key", 101, 75, 162, 60, 14
|
||||||
PUSHBUTTON "&Remove Key", 102, 180, 162, 60, 14
|
PUSHBUTTON "&Remove Key", 102, 195, 162, 60, 14
|
||||||
DEFPUSHBUTTON "&Close", IDOK, 240, 182, 50, 14
|
DEFPUSHBUTTON "&Close", IDOK, 270, 182, 50, 14
|
||||||
END
|
END
|
||||||
|
|
||||||
/* Accelerators used: cl */
|
/* Accelerators used: cl */
|
||||||
|
1
ssh.h
1
ssh.h
@ -142,6 +142,7 @@ struct ssh_signkey {
|
|||||||
unsigned char *(*private_blob)(void *key, int *len);
|
unsigned char *(*private_blob)(void *key, int *len);
|
||||||
void *(*createkey)(unsigned char *pub_blob, int pub_len,
|
void *(*createkey)(unsigned char *pub_blob, int pub_len,
|
||||||
unsigned char *priv_blob, int priv_len);
|
unsigned char *priv_blob, int priv_len);
|
||||||
|
void *(*openssh_createkey)(unsigned char **blob, int *len);
|
||||||
char *(*fingerprint)(void *key);
|
char *(*fingerprint)(void *key);
|
||||||
int (*verifysig)(void *key, char *sig, int siglen,
|
int (*verifysig)(void *key, char *sig, int siglen,
|
||||||
char *data, int datalen);
|
char *data, int datalen);
|
||||||
|
5
sshdss.c
5
sshdss.c
@ -315,6 +315,10 @@ static void *dss_createkey(unsigned char *pub_blob, int pub_len,
|
|||||||
return NULL; /* can't handle DSS private keys */
|
return NULL; /* can't handle DSS private keys */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *dss_openssh_createkey(unsigned char **blob, int *len) {
|
||||||
|
return NULL; /* can't handle DSS private keys */
|
||||||
|
}
|
||||||
|
|
||||||
unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) {
|
unsigned char *dss_sign(void *key, char *data, int datalen, int *siglen) {
|
||||||
return NULL; /* can't handle DSS private keys */
|
return NULL; /* can't handle DSS private keys */
|
||||||
}
|
}
|
||||||
@ -326,6 +330,7 @@ const struct ssh_signkey ssh_dss = {
|
|||||||
dss_public_blob,
|
dss_public_blob,
|
||||||
dss_private_blob,
|
dss_private_blob,
|
||||||
dss_createkey,
|
dss_createkey,
|
||||||
|
dss_openssh_createkey,
|
||||||
dss_fingerprint,
|
dss_fingerprint,
|
||||||
dss_verifysig,
|
dss_verifysig,
|
||||||
dss_sign,
|
dss_sign,
|
||||||
|
35
sshrsa.c
35
sshrsa.c
@ -208,7 +208,7 @@ static void *rsa2_newkey(char *data, int len) {
|
|||||||
if (!rsa) return NULL;
|
if (!rsa) return NULL;
|
||||||
getstring(&data, &len, &p, &slen);
|
getstring(&data, &len, &p, &slen);
|
||||||
|
|
||||||
if (!p || memcmp(p, "ssh-rsa", 7)) {
|
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
|
||||||
sfree(rsa);
|
sfree(rsa);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -309,6 +309,38 @@ static void *rsa2_createkey(unsigned char *pub_blob, int pub_len,
|
|||||||
return rsa;
|
return rsa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *rsa2_openssh_createkey(unsigned char **blob, int *len) {
|
||||||
|
char **b = (char **)blob;
|
||||||
|
struct RSAKey *rsa;
|
||||||
|
char *p;
|
||||||
|
int slen;
|
||||||
|
|
||||||
|
rsa = smalloc(sizeof(struct RSAKey));
|
||||||
|
if (!rsa) return NULL;
|
||||||
|
rsa->comment = NULL;
|
||||||
|
|
||||||
|
rsa->modulus = getmp(b, len);
|
||||||
|
rsa->exponent = getmp(b, len);
|
||||||
|
rsa->private_exponent = getmp(b, len);
|
||||||
|
rsa->iqmp = getmp(b, len);
|
||||||
|
rsa->p = getmp(b, len);
|
||||||
|
rsa->q = getmp(b, len);
|
||||||
|
|
||||||
|
if (!rsa->modulus || !rsa->exponent || !rsa->private_exponent ||
|
||||||
|
!rsa->iqmp || !rsa->p || !rsa->q) {
|
||||||
|
sfree(rsa->modulus);
|
||||||
|
sfree(rsa->exponent);
|
||||||
|
sfree(rsa->private_exponent);
|
||||||
|
sfree(rsa->iqmp);
|
||||||
|
sfree(rsa->p);
|
||||||
|
sfree(rsa->q);
|
||||||
|
sfree(rsa);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rsa;
|
||||||
|
}
|
||||||
|
|
||||||
static char *rsa2_fingerprint(void *key) {
|
static char *rsa2_fingerprint(void *key) {
|
||||||
struct RSAKey *rsa = (struct RSAKey *)key;
|
struct RSAKey *rsa = (struct RSAKey *)key;
|
||||||
struct MD5Context md5c;
|
struct MD5Context md5c;
|
||||||
@ -455,6 +487,7 @@ const struct ssh_signkey ssh_rsa = {
|
|||||||
rsa2_public_blob,
|
rsa2_public_blob,
|
||||||
rsa2_private_blob,
|
rsa2_private_blob,
|
||||||
rsa2_createkey,
|
rsa2_createkey,
|
||||||
|
rsa2_openssh_createkey,
|
||||||
rsa2_fingerprint,
|
rsa2_fingerprint,
|
||||||
rsa2_verifysig,
|
rsa2_verifysig,
|
||||||
rsa2_sign,
|
rsa2_sign,
|
||||||
|
Loading…
Reference in New Issue
Block a user