]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
PuTTYgen: add an extra button to save a public key into a file
authorSimon Tatham <anakin@pobox.com>
Mon, 27 Aug 2001 17:40:03 +0000 (17:40 +0000)
committerSimon Tatham <anakin@pobox.com>
Mon, 27 Aug 2001 17:40:03 +0000 (17:40 +0000)
(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]

puttygen.c
winctrls.c
winstuff.h

index b9edf0d6ce16379be8442d75446a60fa9e8e0d12..3a02abfce4d07597386ce2a5575b4ebfdf9e611e 100644 (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);
            }
        }
        /*
index 9800c3e348d5bce5ad73c5963abc27920f8bfb9e..61821c312fe6fdb09542bb50191bcc64b9d35c93 100644 (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.
  */
index 6dcf7de139f0fd4a8e42ae123246d6e2a3f25ace..a8d696bd68d4c49ca1da6d12889ba3ba3c4685bc 100644 (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);