1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00

PuTTYgen: add an extra button to save a public key into a file

(as well as showing it for cut and paste). For SSH1, this feature is
largely cosmetic and added for orthogonality; it comes into its own
in SSH2, where it saves the Official One True Public Key Format as
specified in the draft spec, and more particularly as used by
ssh.com's product for authentication. Now that ssh-3.0.1 supports
RSA user keys, this is suddenly actually useful.

[originally from svn r1217]
This commit is contained in:
Simon Tatham 2001-08-27 17:40:03 +00:00
parent 5c646f3270
commit 493d34c655
3 changed files with 177 additions and 14 deletions

View File

@ -328,7 +328,7 @@ static void hidemany(HWND hwnd, const int *ids, int hideit)
}
}
static void setupbigedit1(HWND hwnd, int id, struct RSAKey *key)
static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key)
{
char *buffer;
char *dec1, *dec2;
@ -340,12 +340,15 @@ static void setupbigedit1(HWND hwnd, int id, struct RSAKey *key)
sprintf(buffer, "%d %s %s %s",
bignum_bitcount(key->modulus), dec1, dec2, key->comment);
SetDlgItemText(hwnd, id, buffer);
SetDlgItemText(hwnd, idstatic,
"&Public key for pasting into authorized_keys file:");
sfree(dec1);
sfree(dec2);
sfree(buffer);
}
static void setupbigedit2(HWND hwnd, int id, struct ssh2_userkey *key)
static void setupbigedit2(HWND hwnd, int id, int idstatic,
struct ssh2_userkey *key)
{
unsigned char *pub_blob;
char *buffer, *p;
@ -368,10 +371,77 @@ static void setupbigedit2(HWND hwnd, int id, struct ssh2_userkey *key)
*p++ = ' ';
strcpy(p, key->comment);
SetDlgItemText(hwnd, id, buffer);
SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
"OpenSSH authorized_keys2 file:");
sfree(pub_blob);
sfree(buffer);
}
static int save_ssh1_pubkey(char *filename, struct RSAKey *key)
{
char *dec1, *dec2;
FILE *fp;
dec1 = bignum_decimal(key->exponent);
dec2 = bignum_decimal(key->modulus);
fp = fopen(filename, "wb");
if (!fp)
return 0;
fprintf(fp, "%d %s %s %s\n",
bignum_bitcount(key->modulus), dec1, dec2, key->comment);
fclose(fp);
sfree(dec1);
sfree(dec2);
return 1;
}
static int save_ssh2_pubkey(char *filename, struct ssh2_userkey *key)
{
unsigned char *pub_blob;
char *p;
int pub_len;
int i, column;
FILE *fp;
pub_blob = key->alg->public_blob(key->data, &pub_len);
fp = fopen(filename, "wb");
if (!fp)
return 0;
fprintf(fp, "---- BEGIN SSH2 PUBLIC KEY ----\n");
fprintf(fp, "Comment: \"");
for (p = key->comment; *p; p++) {
if (*p == '\\' || *p == '\"')
fputc('\\', fp);
fputc(*p, fp);
}
fprintf(fp, "\"\n");
i = 0;
column = 0;
while (i < pub_len) {
char buf[5];
int n = (pub_len - i < 3 ? pub_len - i : 3);
base64_encode_atom(pub_blob + i, n, buf);
i += n;
buf[4] = '\0';
fputs(buf, fp);
if (++column >= 16) {
fputc('\n', fp);
column = 0;
}
}
if (column > 0)
fputc('\n', fp);
fprintf(fp, "---- END SSH2 PUBLIC KEY ----\n");
fclose(fp);
sfree(pub_blob);
return 1;
}
/*
* Dialog-box function for the main PuTTYgen dialog box.
*/
@ -393,7 +463,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
IDC_BOX_ACTIONS,
IDC_GENSTATIC, IDC_GENERATE,
IDC_LOADSTATIC, IDC_LOAD,
IDC_SAVESTATIC, IDC_SAVE,
IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
IDC_BOX_PARAMS,
IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA,
IDC_BITSSTATIC, IDC_BITS,
@ -441,7 +511,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
{
struct ctlpos cp, cp2;
/* Accelerators used: acglops */
/* Accelerators used: acglops1rb */
ctlposinit(&cp, hwnd, 10, 10, 10);
bartitle(&cp, "Public and private key generation for PuTTY",
@ -472,8 +542,9 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
IDC_GENSTATIC, "&Generate", IDC_GENERATE);
staticbtn(&cp, "Load an existing private key file",
IDC_LOADSTATIC, "&Load", IDC_LOAD);
staticbtn(&cp, "Save the generated key to a new file",
IDC_SAVESTATIC, "&Save", IDC_SAVE);
static2btn(&cp, "Save the generated key", IDC_SAVESTATIC,
"Save p&ublic key", IDC_SAVEPUB,
"&Save private key", IDC_SAVE);
endbox(&cp);
beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 2,
@ -489,13 +560,14 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
/*
* Initially, hide the progress bar and the key display,
* and show the no-key display. Also disable the Save
* button, because with no key we obviously can't save
* buttons, because with no key we obviously can't save
* anything.
*/
hidemany(hwnd, nokey_ids, FALSE);
hidemany(hwnd, generating_ids, TRUE);
hidemany(hwnd, gotkey_ids, TRUE);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
return 1;
case WM_MOUSEMOVE:
@ -555,10 +627,11 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
*state->commentptr = smalloc(len + 1);
GetWindowText(editctl, *state->commentptr, len + 1);
if (state->ssh2) {
setupbigedit2(hwnd, IDC_KEYDISPLAY,
setupbigedit2(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
&state->ssh2key);
} else {
setupbigedit1(hwnd, IDC_KEYDISPLAY, &state->key);
setupbigedit1(hwnd, IDC_KEYDISPLAY, IDC_PKSTATIC,
&state->key);
}
}
}
@ -597,6 +670,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 0);
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 0);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 0);
EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 0);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
state->key_exists = FALSE;
SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
state->collecting_entropy = TRUE;
@ -681,6 +758,37 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
}
}
break;
case IDC_SAVEPUB:
state =
(struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
if (state->key_exists) {
char filename[FILENAME_MAX];
if (prompt_keyfile(hwnd, "Save public key as:",
filename, 1)) {
int ret;
FILE *fp = fopen(filename, "r");
if (fp) {
char buffer[FILENAME_MAX + 80];
fclose(fp);
sprintf(buffer, "Overwrite existing file\n%.*s?",
FILENAME_MAX, filename);
ret = MessageBox(hwnd, buffer, "PuTTYgen Warning",
MB_YESNO | MB_ICONWARNING);
if (ret != IDYES)
break;
}
if (state->ssh2) {
ret = save_ssh2_pubkey(filename, &state->ssh2key);
} else {
ret = save_ssh1_pubkey(filename, &state->key);
}
if (ret <= 0) {
MessageBox(hwnd, "Unable to save key file",
"PuTTYgen Error", MB_OK | MB_ICONERROR);
}
}
}
break;
case IDC_LOAD:
state =
(struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
@ -747,6 +855,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
/*
* Now update the key controls with all the
* key data.
@ -780,7 +892,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
* .ssh/authorized_keys on a Unix box.
*/
setupbigedit1(hwnd, IDC_KEYDISPLAY,
&state->key);
IDC_PKSTATIC, &state->key);
} else {
char *fp;
char *savecomment;
@ -802,7 +914,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
sfree(fp);
setupbigedit2(hwnd, IDC_KEYDISPLAY,
&state->ssh2key);
IDC_PKSTATIC, &state->ssh2key);
}
SetDlgItemText(hwnd, IDC_COMMENTEDIT,
*state->commentptr);
@ -830,6 +942,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
EnableWindow(GetDlgItem(hwnd, IDC_GENERATE), 1);
EnableWindow(GetDlgItem(hwnd, IDC_LOAD), 1);
EnableWindow(GetDlgItem(hwnd, IDC_SAVE), 1);
EnableWindow(GetDlgItem(hwnd, IDC_SAVEPUB), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1);
EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
if (state->ssh2) {
state->ssh2key.data = &state->key;
state->ssh2key.alg = &ssh_rsa;
@ -886,12 +1002,15 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
*state->commentptr = savecomment;
/*
* Construct a decimal representation of the key, for
* pasting into .ssh/authorized_keys on a Unix box.
* pasting into .ssh/authorized_keys or
* .ssh/authorized_keys2 on a Unix box.
*/
if (state->ssh2) {
setupbigedit2(hwnd, IDC_KEYDISPLAY, &state->ssh2key);
setupbigedit2(hwnd, IDC_KEYDISPLAY,
IDC_PKSTATIC, &state->ssh2key);
} else {
setupbigedit1(hwnd, IDC_KEYDISPLAY, &state->key);
setupbigedit1(hwnd, IDC_KEYDISPLAY,
IDC_PKSTATIC, &state->key);
}
}
/*

View File

@ -361,6 +361,48 @@ void staticbtn(struct ctlpos *cp, char *stext, int sid,
cp->ypos += height + GAPBETWEEN;
}
/*
* Like staticbtn, but two buttons.
*/
void static2btn(struct ctlpos *cp, char *stext, int sid,
char *btext1, int bid1, char *btext2, int bid2)
{
const int height = (PUSHBTNHEIGHT > STATICHEIGHT ?
PUSHBTNHEIGHT : STATICHEIGHT);
RECT r;
int lwid, rwid1, rwid2, rpos1, rpos2;
rpos1 = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
rpos2 = GAPBETWEEN + 3 * (cp->width + GAPBETWEEN) / 4;
lwid = rpos1 - 2 * GAPBETWEEN;
rwid1 = rpos2 - rpos1 - GAPBETWEEN;
rwid2 = cp->width + GAPBETWEEN - rpos2;
r.left = GAPBETWEEN;
r.top = cp->ypos + (height - STATICHEIGHT) / 2;
r.right = lwid;
r.bottom = STATICHEIGHT;
doctl(cp, r, "STATIC", WS_CHILD | WS_VISIBLE, 0, stext, sid);
r.left = rpos1;
r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
r.right = rwid1;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
0, btext1, bid1);
r.left = rpos2;
r.top = cp->ypos + (height - PUSHBTNHEIGHT) / 2;
r.right = rwid2;
r.bottom = PUSHBTNHEIGHT;
doctl(cp, r, "BUTTON",
WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON,
0, btext2, bid2);
cp->ypos += height + GAPBETWEEN;
}
/*
* An edit control on the right hand side, with a static to its left.
*/

View File

@ -55,6 +55,8 @@ void checkbox(struct ctlpos *cp, char *text, int id);
void statictext(struct ctlpos *cp, char *text, int id);
void staticbtn(struct ctlpos *cp, char *stext, int sid,
char *btext, int bid);
void static2btn(struct ctlpos *cp, char *stext, int sid,
char *btext1, int bid1, char *btext2, int bid2);
void staticedit(struct ctlpos *cp, char *stext,
int sid, int eid, int percentedit);
void dropdownlist(struct ctlpos *cp, char *text, int staticid, int listid);