Skip to content
This repository has been archived by the owner on Oct 20, 2023. It is now read-only.

Commit

Permalink
PuTTYgen: add an extra button to save a public key into a file
Browse files Browse the repository at this point in the history
(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]
  • Loading branch information
sgtatham committed Aug 27, 2001
1 parent 5c646f3 commit 493d34c
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 14 deletions.
147 changes: 133 additions & 14 deletions puttygen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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.
*/
Expand All @@ -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,
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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,
Expand All @@ -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:
Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
/*
Expand Down
42 changes: 42 additions & 0 deletions winctrls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
2 changes: 2 additions & 0 deletions winstuff.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 493d34c

Please sign in to comment.