]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - windows/winpgen.c
Giant const-correctness patch of doom!
[PuTTY.git] / windows / winpgen.c
index 8f263efcbe3b421de14e1be74b492511a24dbd2e..e67a55af2f238287968d2a27fd07e7fd2c7c2f6f 100644 (file)
@@ -27,7 +27,7 @@ static char *cmdline_keyfile = NULL;
 /*
  * Print a modal (Really Bad) message box and perform a fatal exit.
  */
-void modalfatalbox(char *fmt, ...)
+void modalfatalbox(const char *fmt, ...)
 {
     va_list ap;
     char *stuff;
@@ -44,7 +44,7 @@ void modalfatalbox(char *fmt, ...)
 /*
  * Print a non-fatal message box and do not exit.
  */
-void nonfatal(char *fmt, ...)
+void nonfatal(const char *fmt, ...)
 {
     va_list ap;
     char *stuff;
@@ -315,7 +315,7 @@ static int CALLBACK AboutProc(HWND hwnd, UINT msg,
     return 0;
 }
 
-typedef enum {RSA, DSA, ECDSA} keytype;
+typedef enum {RSA, DSA, ECDSA, ED25519} keytype;
 
 /*
  * Thread to generate a key.
@@ -344,6 +344,8 @@ static DWORD WINAPI generate_rsa_key_thread(void *param)
        dsa_generate(params->dsskey, params->keysize, progress_update, &prog);
     else if (params->keytype == ECDSA)
         ec_generate(params->eckey, params->keysize, progress_update, &prog);
+    else if (params->keytype == ED25519)
+        ec_edgenerate(params->eckey, params->keysize, progress_update, &prog);
     else
        rsa_generate(params->key, params->keysize, progress_update, &prog);
 
@@ -381,69 +383,23 @@ static void hidemany(HWND hwnd, const int *ids, int hideit)
 
 static void setupbigedit1(HWND hwnd, int id, int idstatic, struct RSAKey *key)
 {
-    char *buffer;
-    char *dec1, *dec2;
-
-    dec1 = bignum_decimal(key->exponent);
-    dec2 = bignum_decimal(key->modulus);
-    buffer = dupprintf("%d %s %s %s", bignum_bitcount(key->modulus),
-                      dec1, dec2, key->comment);
+    char *buffer = ssh1_pubkey_str(key);
     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, int idstatic,
                          struct ssh2_userkey *key)
 {
-    unsigned char *pub_blob;
-    char *buffer, *p;
-    int pub_len;
-    int i;
-
-    pub_blob = key->alg->public_blob(key->data, &pub_len);
-    buffer = snewn(strlen(key->alg->name) + 4 * ((pub_len + 2) / 3) +
-                  strlen(key->comment) + 3, char);
-    strcpy(buffer, key->alg->name);
-    p = buffer + strlen(buffer);
-    *p++ = ' ';
-    i = 0;
-    while (i < pub_len) {
-       int n = (pub_len - i < 3 ? pub_len - i : 3);
-       base64_encode_atom(pub_blob + i, n, p);
-       i += n;
-       p += 4;
-    }
-    *p++ = ' ';
-    strcpy(p, key->comment);
+    char *buffer = ssh2_pubkey_openssh_str(key);
     SetDlgItemText(hwnd, id, buffer);
     SetDlgItemText(hwnd, idstatic, "&Public key for pasting into "
                   "OpenSSH authorized_keys file:");
-    sfree(pub_blob);
     sfree(buffer);
 }
 
-static int save_ssh1_pubkey(char *filename, struct RSAKey *key)
-{
-    char *dec1, *dec2;
-    FILE *fp;
-
-    fp = fopen(filename, "wb");
-    if (!fp)
-       return 0;
-    dec1 = bignum_decimal(key->exponent);
-    dec2 = bignum_decimal(key->modulus);
-    fprintf(fp, "%d %s %s %s\n",
-           bignum_bitcount(key->modulus), dec1, dec2, key->comment);
-    fclose(fp);
-    sfree(dec1);
-    sfree(dec2);
-    return 1;
-}
-
 /*
  * Warn about the obsolescent key file format.
  */
@@ -464,53 +420,6 @@ void old_keyfile_warning(void)
     MessageBox(NULL, message, mbtitle, MB_OK);
 }
 
-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;
-}
-
 enum {
     controlidstart = 100,
     IDC_QUIT,
@@ -530,11 +439,13 @@ enum {
     IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB,
     IDC_BOX_PARAMS,
     IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA,
-    IDC_KEYSSH2ECDSA,
+    IDC_KEYSSH2ECDSA, IDC_KEYSSH2ED25519,
     IDC_BITSSTATIC, IDC_BITS,
     IDC_ABOUT,
     IDC_GIVEHELP,
-    IDC_IMPORT, IDC_EXPORT_OPENSSH, IDC_EXPORT_SSHCOM
+    IDC_IMPORT,
+    IDC_EXPORT_OPENSSH_AUTO, IDC_EXPORT_OPENSSH_NEW,
+    IDC_EXPORT_SSHCOM
 };
 
 static const int nokey_ids[] = { IDC_NOKEY, 0 };
@@ -568,6 +479,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
         EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
+        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
        EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
        EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
        EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
@@ -578,8 +490,12 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
        EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND);
         EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
                        MF_ENABLED|MF_BYCOMMAND);
+        EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
+                       MF_ENABLED|MF_BYCOMMAND);
        EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
-       EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH,
+       EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
+                      MF_GRAYED|MF_BYCOMMAND);
+       EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
                       MF_GRAYED|MF_BYCOMMAND);
        EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
                       MF_GRAYED|MF_BYCOMMAND);
@@ -596,6 +512,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0);
        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0);
         EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 0);
+        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 0);
        EnableWindow(GetDlgItem(hwnd, IDC_BITS), 0);
        EnableMenuItem(state->filemenu, IDC_LOAD, MF_GRAYED|MF_BYCOMMAND);
        EnableMenuItem(state->filemenu, IDC_SAVE, MF_GRAYED|MF_BYCOMMAND);
@@ -606,8 +523,12 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
        EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND);
         EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
                        MF_GRAYED|MF_BYCOMMAND);
+        EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
+                       MF_GRAYED|MF_BYCOMMAND);
        EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND);
-       EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH,
+       EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_AUTO,
+                      MF_GRAYED|MF_BYCOMMAND);
+       EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH_NEW,
                       MF_GRAYED|MF_BYCOMMAND);
        EnableMenuItem(state->cvtmenu, IDC_EXPORT_SSHCOM,
                       MF_GRAYED|MF_BYCOMMAND);
@@ -624,6 +545,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1);
        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1);
         EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 1);
+        EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ED25519), 1);
        EnableWindow(GetDlgItem(hwnd, IDC_BITS), 1);
        EnableMenuItem(state->filemenu, IDC_LOAD, MF_ENABLED|MF_BYCOMMAND);
        EnableMenuItem(state->filemenu, IDC_SAVE, MF_ENABLED|MF_BYCOMMAND);
@@ -634,6 +556,8 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
        EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND);
         EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA,
                        MF_ENABLED|MF_BYCOMMAND);
+        EnableMenuItem(state->keymenu, IDC_KEYSSH2ED25519,
+                       MF_ENABLED|MF_BYCOMMAND);
        EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND);
        /*
         * Enable export menu items if and only if the key type
@@ -643,7 +567,8 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status)
 #define do_export_menuitem(x,y) \
     EnableMenuItem(state->cvtmenu, x, MF_BYCOMMAND | \
                       (import_target_type(y)==type?MF_ENABLED:MF_GRAYED))
-       do_export_menuitem(IDC_EXPORT_OPENSSH, SSH_KEYTYPE_OPENSSH);
+       do_export_menuitem(IDC_EXPORT_OPENSSH_AUTO, SSH_KEYTYPE_OPENSSH_AUTO);
+       do_export_menuitem(IDC_EXPORT_OPENSSH_NEW, SSH_KEYTYPE_OPENSSH_NEW);
        do_export_menuitem(IDC_EXPORT_SSHCOM, SSH_KEYTYPE_SSHCOM);
 #undef do_export_menuitem
        break;
@@ -781,9 +706,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state,
 
                savecomment = state->ssh2key.comment;
                state->ssh2key.comment = NULL;
-               fp =
-                   state->ssh2key.alg->
-                   fingerprint(state->ssh2key.data);
+               fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data);
                state->ssh2key.comment = savecomment;
 
                SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
@@ -877,14 +800,17 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
            AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2RSA, "SSH-2 &RSA key");
            AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2DSA, "SSH-2 &DSA key");
             AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ECDSA, "SSH-2 &ECDSA key");
+            AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH2ED25519, "SSH-2 ED&25519 key");
            AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key");
            state->keymenu = menu1;
 
            menu1 = CreateMenu();
            AppendMenu(menu1, MF_ENABLED, IDC_IMPORT, "&Import key");
            AppendMenu(menu1, MF_SEPARATOR, 0, 0);
-           AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH,
+           AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_AUTO,
                       "Export &OpenSSH key");
+           AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_OPENSSH_NEW,
+                      "Export &OpenSSH key (force new file format)");
            AppendMenu(menu1, MF_ENABLED, IDC_EXPORT_SSHCOM,
                       "Export &ssh.com key");
            AppendMenu(menu, MF_POPUP | MF_ENABLED, (UINT) menu1,
@@ -952,11 +878,13 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                       "&Save private key", IDC_SAVE);
            endbox(&cp);
            beginbox(&cp, "Parameters", IDC_BOX_PARAMS);
-           radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 4,
+           radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 5,
+                     "&RSA", IDC_KEYSSH2RSA,
+                      "&DSA", IDC_KEYSSH2DSA,
+                      "&ECDSA", IDC_KEYSSH2ECDSA,
+                      "ED&25519", IDC_KEYSSH2ED25519,
                      "SSH-&1 (RSA)", IDC_KEYSSH1,
-                     "SSH-2 &RSA", IDC_KEYSSH2RSA,
-                      "SSH-2 &DSA", IDC_KEYSSH2DSA,
-                      "SSH-2 &ECDSA", IDC_KEYSSH2ECDSA, NULL);
+                      NULL);
            staticedit(&cp, "Number of &bits in a generated key:",
                       IDC_BITSSTATIC, IDC_BITS, 20);
            endbox(&cp);
@@ -1035,6 +963,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
          case IDC_KEYSSH2RSA:
          case IDC_KEYSSH2DSA:
           case IDC_KEYSSH2ECDSA:
+          case IDC_KEYSSH2ED25519:
            {
                state = (struct MainDlgState *)
                    GetWindowLongPtr(hwnd, GWLP_USERDATA);
@@ -1104,6 +1033,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                     state->keytype = DSA;
                 } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) {
                     state->keytype = ECDSA;
+                } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ED25519)) {
+                    state->keytype = ED25519;
                 }
                if (state->keysize < 256) {
                    int ret = MessageBox(hwnd,
@@ -1131,6 +1062,18 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                     state->keysize = 256;
                     SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
                 }
+                if (state->keytype == ED25519 && state->keysize != 256) {
+                    int ret = MessageBox(hwnd,
+                                         "Only 256 bit Edwards elliptic"
+                                         " curves are supported.\n"
+                                         "Key length reset to 256. Continue?",
+                                         "PuTTYgen Warning",
+                                         MB_ICONWARNING | MB_OKCANCEL);
+                    if (ret != IDOK)
+                        break;
+                    state->keysize = 256;
+                    SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE);
+                }
                ui_set_state(hwnd, state, 1);
                SetDlgItemText(hwnd, IDC_GENERATING, entropy_msg);
                state->key_exists = FALSE;
@@ -1161,7 +1104,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
            }
            break;
          case IDC_SAVE:
-          case IDC_EXPORT_OPENSSH:
+          case IDC_EXPORT_OPENSSH_AUTO:
+          case IDC_EXPORT_OPENSSH_NEW:
           case IDC_EXPORT_SSHCOM:
            if (HIWORD(wParam) != BN_CLICKED)
                break;
@@ -1177,8 +1121,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                 else
                     realtype = SSH_KEYTYPE_SSH1;
 
-                if (LOWORD(wParam) == IDC_EXPORT_OPENSSH)
-                    type = SSH_KEYTYPE_OPENSSH;
+                if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_AUTO)
+                    type = SSH_KEYTYPE_OPENSSH_AUTO;
+                else if (LOWORD(wParam) == IDC_EXPORT_OPENSSH_NEW)
+                    type = SSH_KEYTYPE_OPENSSH_NEW;
                 else if (LOWORD(wParam) == IDC_EXPORT_SSHCOM)
                     type = SSH_KEYTYPE_SSHCOM;
                 else
@@ -1286,15 +1232,27 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                        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);
-                   }
+                    fp = fopen(filename, "w");
+                    if (!fp) {
+                        MessageBox(hwnd, "Unable to open key file",
+                                   "PuTTYgen Error", MB_OK | MB_ICONERROR);
+                    } else {
+                        if (state->ssh2) {
+                            int bloblen;
+                            unsigned char *blob;
+                            blob = state->ssh2key.alg->public_blob
+                                (state->ssh2key.data, &bloblen);
+                            ssh2_write_pubkey(fp, state->ssh2key.comment,
+                                              blob, bloblen,
+                                              SSH_KEYTYPE_SSH2_PUBLIC_RFC4716);
+                        } else {
+                            ssh1_write_pubkey(fp, &state->key);
+                        }
+                        if (fclose(fp) < 0) {
+                            MessageBox(hwnd, "Unable to save key file",
+                                       "PuTTYgen Error", MB_OK | MB_ICONERROR);
+                        }
+                    }
                }
            }
            break;
@@ -1329,12 +1287,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                state->ssh2key.alg = &ssh_dss;
             } else if (state->keytype == ECDSA) {
                 state->ssh2key.data = &state->eckey;
-                if (state->eckey.publicKey.curve->fieldBits == 256)
-                    state->ssh2key.alg = &ssh_ecdsa_nistp256;
-                else if (state->eckey.publicKey.curve->fieldBits == 384)
-                    state->ssh2key.alg = &ssh_ecdsa_nistp384;
-                else
-                    state->ssh2key.alg = &ssh_ecdsa_nistp521;
+                state->ssh2key.alg = state->eckey.signalg;
+            } else if (state->keytype == ED25519) {
+                state->ssh2key.data = &state->eckey;
+                state->ssh2key.alg = &ssh_ecdsa_ed25519;
            } else {
                state->ssh2key.data = &state->key;
                state->ssh2key.alg = &ssh_rsa;
@@ -1357,6 +1313,8 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
                strftime(*state->commentptr, 30, "dsa-key-%Y%m%d", &tm);
             else if (state->keytype == ECDSA)
                 strftime(*state->commentptr, 30, "ecdsa-key-%Y%m%d", &tm);
+            else if (state->keytype == ED25519)
+                strftime(*state->commentptr, 30, "ed25519-key-%Y%m%d", &tm);
            else
                strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm);
        }
@@ -1384,7 +1342,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
            *state->commentptr = NULL;
            if (state->ssh2) {
                char *fp;
-               fp = state->ssh2key.alg->fingerprint(state->ssh2key.data);
+               fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data);
                SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
                sfree(fp);
            } else {
@@ -1414,7 +1372,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
       case WM_HELP:
         {
             int id = ((LPHELPINFO)lParam)->iCtrlId;
-            char *topic = NULL;
+            const char *topic = NULL;
             switch (id) {
               case IDC_GENERATING:
               case IDC_PROGRESS:
@@ -1448,12 +1406,14 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
               case IDC_KEYSSH2RSA:
               case IDC_KEYSSH2DSA:
               case IDC_KEYSSH2ECDSA:
+              case IDC_KEYSSH2ED25519:
                 topic = WINHELP_CTX_puttygen_keytype; break;
               case IDC_BITSSTATIC:
               case IDC_BITS:
                 topic = WINHELP_CTX_puttygen_bits; break;
               case IDC_IMPORT:
-              case IDC_EXPORT_OPENSSH:
+              case IDC_EXPORT_OPENSSH_AUTO:
+              case IDC_EXPORT_OPENSSH_NEW:
               case IDC_EXPORT_SSHCOM:
                 topic = WINHELP_CTX_puttygen_conversions; break;
             }