Add some basic framework code preparatory to adding key export.
[u/mdw/putty] / puttygen.c
index 689a383..af2b165 100644 (file)
@@ -18,6 +18,8 @@
 
 #define DEFAULT_KEYSIZE 1024
 
+static int requested_help;
+
 /* ----------------------------------------------------------------------
  * Progress report code. This is really horrible :-)
  */
@@ -499,6 +501,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
        IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
        IDC_BITSSTATIC, IDC_BITS,
        IDC_ABOUT,
+       IDC_GIVEHELP,
+       IDC_IMPORT, IDC_EXPORT_OPENSSH, IDC_EXPORT_SSHCOM
     };
     static const int nokey_ids[] = { IDC_NOKEY, 0 };
     static const int generating_ids[] =
@@ -518,6 +522,55 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
 
     switch (msg) {
       case WM_INITDIALOG:
+        if (help_path)
+            SetWindowLong(hwnd, GWL_EXSTYLE,
+                          GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_CONTEXTHELP);
+        else {
+            /*
+             * If we add a Help button, this is where we destroy it
+             * if the help file isn't present.
+             */
+        }
+        requested_help = FALSE;
+
+       {
+           HMENU menu, menu1;
+
+           menu = CreateMenu();
+
+           menu1 = CreateMenu();
+           AppendMenu(menu1, MF_ENABLED, IDC_GENERATE, "&Generate key pair");
+           AppendMenu(menu1, MF_ENABLED, IDC_LOAD, "&Load private key");
+           AppendMenu(menu1, MF_ENABLED, IDC_SAVEPUB, "Save p&ublic key");
+           AppendMenu(menu1, MF_ENABLED, IDC_SAVE, "&Save private key");
+
+           AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&File");
+
+#if 0
+           /*
+            * Exporting not yet supported, but when we do it we
+            * should just put this lot back in.
+            */
+           menu1 = CreateMenu();
+           AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH,
+                      "Export &OpenSSH key");
+           AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
+                      "Export &ssh.com key");
+
+           AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1,
+                      "&Export");
+#endif
+
+           menu1 = CreateMenu();
+           AppendMenu(menu1, MF_ENABLED, IDC_ABOUT, "&About");
+           if (help_path)
+               AppendMenu(menu1, MF_ENABLED, IDC_GIVEHELP, "&Help");
+
+           AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Help");
+
+           SetMenu(hwnd, menu);
+       }
+
        /*
         * Centre the window.
         */
@@ -545,8 +598,6 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
            /* Accelerators used: acglops1rbd */
 
            ctlposinit(&cp, hwnd, 4, 4, 4);
-           bartitle(&cp, "Public and private key generation for PuTTY",
-                    IDC_TITLE);
            beginbox(&cp, "Key", IDC_BOX_KEY);
            cp2 = cp;
            statictext(&cp2, "No key.", 1, IDC_NOKEY);
@@ -676,6 +727,16 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
            EnableWindow(hwnd, 1);
            SetActiveWindow(hwnd);
            return 0;
+         case IDC_GIVEHELP:
+            if (HIWORD(wParam) == BN_CLICKED ||
+                HIWORD(wParam) == BN_DOUBLECLICKED) {
+                if (help_path) {
+                    WinHelp(hwnd, help_path, HELP_COMMAND,
+                            (DWORD)"JI(`',`puttygen.general')");
+                    requested_help = TRUE;
+                }
+            }
+           return 0;
          case IDC_GENERATE:
            state =
                (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
@@ -739,12 +800,39 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
            }
            break;
          case IDC_SAVE:
+          case IDC_EXPORT_OPENSSH:
+          case IDC_EXPORT_SSHCOM:
            state =
                (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
            if (state->key_exists) {
                char filename[FILENAME_MAX];
                char passphrase[PASSPHRASE_MAXLEN];
                char passphrase2[PASSPHRASE_MAXLEN];
+                int type, realtype;
+
+                if (state->ssh2)
+                    realtype = SSH_KEYTYPE_SSH2;
+                else
+                    realtype = SSH_KEYTYPE_SSH1;
+
+                if (LOWORD(wParam) == IDC_EXPORT_OPENSSH)
+                    type = SSH_KEYTYPE_OPENSSH;
+                else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
+                    type = SSH_KEYTYPE_SSHCOM;
+                else
+                    type = realtype;
+
+                if (type != realtype &&
+                    import_target_type(type) != realtype) {
+                    char msg[256];
+                    sprintf(msg, "Cannot export an SSH%d key in an SSH%d"
+                            " format", (state->ssh2 ? 2 : 1),
+                            (state->ssh2 ? 1 : 2));
+                   MessageBox(hwnd, msg,
+                               "PuTTYgen Error", MB_OK | MB_ICONERROR);
+                   break;
+                }
+
                GetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT,
                               passphrase, sizeof(passphrase));
                GetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
@@ -779,13 +867,22 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                        if (ret != IDYES)
                            break;
                    }
+
                    if (state->ssh2) {
-                       ret = ssh2_save_userkey(filename, &state->ssh2key,
-                                               *passphrase ? passphrase :
-                                               NULL);
+                        if (type != realtype)
+                            ret = export_ssh2(filename, type, &state->ssh2key,
+                                              *passphrase ? passphrase : NULL);
+                        else
+                            ret = ssh2_save_userkey(filename, &state->ssh2key,
+                                                    *passphrase ? passphrase :
+                                                    NULL);
                    } else {
-                       ret = saversakey(filename, &state->key,
-                                        *passphrase ? passphrase : NULL);
+                        if (type != realtype)
+                            ret = export_ssh1(filename, type, &state->key,
+                                              *passphrase ? passphrase : NULL);
+                        else
+                            ret = saversakey(filename, &state->key,
+                                             *passphrase ? passphrase : NULL);
                    }
                    if (ret <= 0) {
                        MessageBox(hwnd, "Unable to save key file",
@@ -833,26 +930,40 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                if (prompt_keyfile(hwnd, "Load private key:", filename, 0)) {
                    char passphrase[PASSPHRASE_MAXLEN];
                    int needs_pass;
-                   int ver;
+                   int type, realtype;
                    int ret;
                    char *comment;
                    struct PassphraseProcStruct pps;
                    struct RSAKey newkey1;
                    struct ssh2_userkey *newkey2 = NULL;
 
-                   ver = keyfile_version(filename);
-                   if (ver == 0) {
-                       MessageBox(NULL, "Couldn't load private key.",
+                   type = realtype = key_type(filename);
+                   if (type != SSH_KEYTYPE_SSH1 &&
+                       type != SSH_KEYTYPE_SSH2 &&
+                       !import_possible(type)) {
+                       char msg[256];
+                       sprintf(msg, "Couldn't load private key (%s)",
+                               key_type_to_str(type));
+                       MessageBox(NULL, msg,
                                   "PuTTYgen Error", MB_OK | MB_ICONERROR);
                        break;
                    }
 
+                   if (type != SSH_KEYTYPE_SSH1 &&
+                       type != SSH_KEYTYPE_SSH2) {
+                       realtype = type;
+                       type = import_target_type(type);
+                   }
+
                    comment = NULL;
-                   if (ver == 1)
+                   if (realtype == SSH_KEYTYPE_SSH1)
                        needs_pass = rsakey_encrypted(filename, &comment);
-                   else
+                   else if (realtype == SSH_KEYTYPE_SSH2)
                        needs_pass =
                            ssh2_userkey_encrypted(filename, &comment);
+                   else
+                       needs_pass = import_encrypted(filename, realtype,
+                                                     &comment);
                    pps.passphrase = passphrase;
                    pps.comment = comment;
                    do {
@@ -868,12 +979,20 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                            }
                        } else
                            *passphrase = '\0';
-                       if (ver == 1)
-                           ret =
-                               loadrsakey(filename, &newkey1, passphrase);
-                       else {
-                           newkey2 =
-                               ssh2_load_userkey(filename, passphrase);
+                       if (type == SSH_KEYTYPE_SSH1) {
+                           if (realtype == type)
+                               ret = loadrsakey(filename, &newkey1,
+                                                passphrase);
+                           else
+                               ret = import_ssh1(filename, realtype,
+                                                 &newkey1, passphrase);
+                       } else {
+                           if (realtype == type)
+                               newkey2 = ssh2_load_userkey(filename,
+                                                           passphrase);
+                           else
+                               newkey2 = import_ssh2(filename, realtype,
+                                                     passphrase);
                            if (newkey2 == SSH2_WRONG_PASSPHRASE)
                                ret = -1;
                            else if (!newkey2)
@@ -905,7 +1024,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                                           passphrase);
                            SetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT,
                                           passphrase);
-                           if (ver == 1) {
+                           if (type == SSH_KEYTYPE_SSH1) {
                                char buf[128];
                                char *savecomment;
 
@@ -1067,19 +1186,95 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
        hidemany(hwnd, generating_ids, TRUE);
        hidemany(hwnd, gotkey_ids, FALSE);
        break;
+      case WM_HELP:
+        if (help_path) {
+            int id = ((LPHELPINFO)lParam)->iCtrlId;
+            char *cmd = NULL;
+            switch (id) {
+              case IDC_GENERATING:
+              case IDC_PROGRESS:
+              case IDC_GENSTATIC:
+              case IDC_GENERATE:
+                cmd = "JI(`',`puttygen.generate')"; break;
+              case IDC_PKSTATIC:
+              case IDC_KEYDISPLAY:
+                cmd = "JI(`',`puttygen.pastekey')"; break;
+              case IDC_FPSTATIC:
+              case IDC_FINGERPRINT:
+                cmd = "JI(`',`puttygen.fingerprint')"; break;
+              case IDC_COMMENTSTATIC:
+              case IDC_COMMENTEDIT:
+                cmd = "JI(`',`puttygen.comment')"; break;
+              case IDC_PASSPHRASE1STATIC:
+              case IDC_PASSPHRASE1EDIT:
+              case IDC_PASSPHRASE2STATIC:
+              case IDC_PASSPHRASE2EDIT:
+                cmd = "JI(`',`puttygen.passphrase')"; break;
+              case IDC_LOADSTATIC:
+              case IDC_LOAD:
+                cmd = "JI(`',`puttygen.load')"; break;
+              case IDC_SAVESTATIC:
+              case IDC_SAVE:
+                cmd = "JI(`',`puttygen.savepriv')"; break;
+              case IDC_SAVEPUB:
+                cmd = "JI(`',`puttygen.savepub')"; break;
+              case IDC_TYPESTATIC:
+              case IDC_KEYSSH1:
+              case IDC_KEYSSH2RSA:
+              case IDC_KEYSSH2DSA:
+                cmd = "JI(`',`puttygen.keytype')"; break;
+              case IDC_BITSSTATIC:
+              case IDC_BITS:
+                cmd = "JI(`',`puttygen.bits')"; break;
+            }
+            if (cmd) {
+                WinHelp(hwnd, help_path, HELP_COMMAND, (DWORD)cmd);
+                requested_help = TRUE;
+            } else {
+                MessageBeep(0);
+            }
+        }
+        break;
       case WM_CLOSE:
        state = (struct MainDlgState *) GetWindowLong(hwnd, GWL_USERDATA);
        sfree(state);
+        if (requested_help) {
+            WinHelp(hwnd, help_path, HELP_QUIT, 0);
+            requested_help = FALSE;
+        }
        EndDialog(hwnd, 1);
        return 0;
     }
     return 0;
 }
 
+void cleanup_exit(int code) { exit(code); }
+
 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 {
     InitCommonControls();
     hinst = inst;
+
+    /*
+     * See if we can find our Help file.
+     */
+    {
+        char b[2048], *p, *q, *r;
+        FILE *fp;
+        GetModuleFileName(NULL, b, sizeof(b) - 1);
+        r = b;
+        p = strrchr(b, '\\');
+        if (p && p >= r) r = p+1;
+        q = strrchr(b, ':');
+        if (q && q >= r) r = q+1;
+        strcpy(r, "putty.hlp");
+        if ( (fp = fopen(b, "r")) != NULL) {
+            help_path = dupstr(b);
+            fclose(fp);
+        } else
+            help_path = NULL;
+    }
+
     random_init();
     return DialogBox(hinst, MAKEINTRESOURCE(201), NULL,
                     MainDlgProc) != IDOK;