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

Add support for the OpenSSH SSH2 agent protocol.

[originally from svn r976]
This commit is contained in:
Simon Tatham 2001-03-03 15:31:35 +00:00
parent deccfaa3ef
commit 1f168926d7
5 changed files with 480 additions and 48 deletions

477
pageant.c
View File

@ -9,6 +9,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "putty.h" // FIXME
#include "ssh.h"
#include "tree234.h"
@ -33,14 +34,33 @@
#define APPNAME "Pageant"
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
#define SSH_AGENTC_RSA_CHALLENGE 3
#define SSH_AGENT_RSA_RESPONSE 4
/*
* SSH1 agent messages.
*/
#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_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[];
@ -50,7 +70,7 @@ static HWND keylist;
static HWND aboutbox;
static HMENU systray_menu;
static tree234 *rsakeys;
static tree234 *rsakeys, *ssh2keys;
static int has_security;
#ifndef NO_SECURITY
@ -63,9 +83,10 @@ static gsi_fn_t getsecurityinfo;
/*
* We need this to link with the RSA code, because rsaencrypt()
* pads its data with random bytes. Since we only use rsadecrypt(),
* which is deterministic, this should never be called.
*
* 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.
@ -75,6 +96,16 @@ int random_byte(void) {
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
* have it do anything at all.
@ -164,6 +195,20 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
switch (msg) {
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);
SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
@ -203,23 +248,45 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg,
* Update the visible key list.
*/
static void keylist_update(void) {
struct RSAKey *key;
struct RSAKey *rkey;
struct ssh2_userkey *skey;
enum234 e;
if (keylist) {
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;
/*
* Replace two spaces in the fingerprint with tabs, for
* 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';
SendDlgItemMessage (keylist, 100, LB_ADDSTRING,
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);
}
}
@ -229,16 +296,29 @@ static void keylist_update(void) {
*/
static void add_keyfile(char *filename) {
char passphrase[PASSPHRASE_MAXLEN];
struct RSAKey *key;
struct RSAKey *rkey;
struct ssh2_userkey *skey;
int needs_pass;
int ret;
int attempts;
char *comment;
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;
key = smalloc(sizeof(*key));
if (ver == 1)
rkey = smalloc(sizeof(*rkey));
pps.passphrase = passphrase;
pps.comment = comment;
do {
@ -249,23 +329,42 @@ static void add_keyfile(char *filename) {
(LPARAM)&pps);
if (!dlgret) {
if (comment) sfree(comment);
sfree(key);
if (ver == 1)
sfree(rkey);
return; /* operation cancelled */
}
} else
*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++;
} while (ret == -1);
if (comment) sfree(comment);
if (ret == 0) {
MessageBox(NULL, "Couldn't load private key.", APPNAME,
MB_OK | MB_ICONERROR);
sfree(key);
if (ver == 1)
sfree(rkey);
return;
}
if (add234(rsakeys, key) != key)
sfree(key); /* already present, don't waste RAM */
if (ver == 1) {
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;
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;
@ -312,7 +411,7 @@ static void answer_msg(void *msg) {
if (len > AGENT_MAX_MSGLEN)
goto failure; /* aaargh! too much stuff! */
PUT_32BIT(ret, len-4);
ret[4] = SSH_AGENT_RSA_IDENTITIES_ANSWER;
ret[4] = SSH1_AGENT_RSA_IDENTITIES_ANSWER;
PUT_32BIT(ret+5, nkeys);
p = ret + 5 + 4;
for (key = first234(rsakeys, &e); key; key = next234(&e)) {
@ -326,9 +425,57 @@ static void answer_msg(void *msg) {
}
}
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
* or not.
*/
@ -370,11 +517,42 @@ static void answer_msg(void *msg) {
*/
len = 5 + 16;
PUT_32BIT(ret, len-4);
ret[4] = SSH_AGENT_RSA_RESPONSE;
ret[4] = SSH1_AGENT_RSA_RESPONSE;
memcpy(ret+5, response_md5, 16);
}
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
* SSH_AGENT_FAILURE if the key was malformed.
@ -386,9 +564,9 @@ static void answer_msg(void *msg) {
memset(key, 0, sizeof(key));
p += makekey(p, key, NULL, 1);
p += makeprivate(p, key);
p += ssh1_read_bignum(p, NULL); /* p^-1 mod q */
p += ssh1_read_bignum(p, NULL); /* p */
p += ssh1_read_bignum(p, NULL); /* q */
p += ssh1_read_bignum(p, key->iqmp); /* p^-1 mod q */
p += ssh1_read_bignum(p, key->p); /* p */
p += ssh1_read_bignum(p, key->q); /* q */
comment = smalloc(GET_32BIT(p));
if (comment) {
memcpy(comment, p+4, GET_32BIT(p));
@ -405,7 +583,57 @@ static void answer_msg(void *msg) {
}
}
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
* 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);
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;
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:
failure:
/*
@ -442,7 +738,7 @@ static void answer_msg(void *msg) {
/*
* 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 *b = (struct RSAKey *)bv;
Bignum am, bm;
@ -472,6 +768,75 @@ static int cmpkeys(void *av, void *bv) {
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) {
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,
WPARAM wParam, LPARAM lParam) {
enum234 e;
struct RSAKey *key;
struct RSAKey *rkey;
struct ssh2_userkey *skey;
switch (msg) {
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;
{
static int tabs[2] = {25, 175};
SendDlgItemMessage (hwnd, 100, LB_SETTABSTOPS, 2,
(LPARAM) tabs);
static int tabs[] = {35, 60, 210};
SendDlgItemMessage (hwnd, 100, LB_SETTABSTOPS,
sizeof(tabs)/sizeof(*tabs), (LPARAM) tabs);
}
keylist_update();
return 0;
@ -543,11 +923,23 @@ static int CALLBACK KeyListProc(HWND hwnd, UINT msg,
MessageBeep(0);
break;
}
for (key = first234(rsakeys, &e); key; key = next234(&e))
for (rkey = first234(rsakeys, &e); rkey; rkey = next234(&e))
if (n-- == 0)
break;
del234(rsakeys, key);
freersakey(key); free(key);
if (rkey) {
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();
}
return 0;
@ -830,10 +1222,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
/*
* 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;

View File

@ -18,16 +18,16 @@ BEGIN
PUSHBUTTON "&Cancel", IDCANCEL, 80, 42, 40, 14
END
211 DIALOG DISCARDABLE 0, 0, 300, 200
211 DIALOG DISCARDABLE 0, 0, 330, 200
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Pageant Key List"
FONT 8, "MS Sans Serif"
BEGIN
LISTBOX 100, 10, 10, 280, 155,
LISTBOX 100, 10, 10, 310, 155,
LBS_HASSTRINGS | LBS_USETABSTOPS | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "&Add Key", 101, 60, 162, 60, 14
PUSHBUTTON "&Remove Key", 102, 180, 162, 60, 14
DEFPUSHBUTTON "&Close", IDOK, 240, 182, 50, 14
PUSHBUTTON "&Add Key", 101, 75, 162, 60, 14
PUSHBUTTON "&Remove Key", 102, 195, 162, 60, 14
DEFPUSHBUTTON "&Close", IDOK, 270, 182, 50, 14
END
/* Accelerators used: cl */

1
ssh.h
View File

@ -142,6 +142,7 @@ struct ssh_signkey {
unsigned char *(*private_blob)(void *key, int *len);
void *(*createkey)(unsigned char *pub_blob, int pub_len,
unsigned char *priv_blob, int priv_len);
void *(*openssh_createkey)(unsigned char **blob, int *len);
char *(*fingerprint)(void *key);
int (*verifysig)(void *key, char *sig, int siglen,
char *data, int datalen);

View File

@ -315,6 +315,10 @@ static void *dss_createkey(unsigned char *pub_blob, int pub_len,
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) {
return NULL; /* can't handle DSS private keys */
}
@ -326,6 +330,7 @@ const struct ssh_signkey ssh_dss = {
dss_public_blob,
dss_private_blob,
dss_createkey,
dss_openssh_createkey,
dss_fingerprint,
dss_verifysig,
dss_sign,

View File

@ -208,7 +208,7 @@ static void *rsa2_newkey(char *data, int len) {
if (!rsa) return NULL;
getstring(&data, &len, &p, &slen);
if (!p || memcmp(p, "ssh-rsa", 7)) {
if (!p || slen != 7 || memcmp(p, "ssh-rsa", 7)) {
sfree(rsa);
return NULL;
}
@ -309,6 +309,38 @@ static void *rsa2_createkey(unsigned char *pub_blob, int pub_len,
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) {
struct RSAKey *rsa = (struct RSAKey *)key;
struct MD5Context md5c;
@ -455,6 +487,7 @@ const struct ssh_signkey ssh_rsa = {
rsa2_public_blob,
rsa2_private_blob,
rsa2_createkey,
rsa2_openssh_createkey,
rsa2_fingerprint,
rsa2_verifysig,
rsa2_sign,