X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=windows%2Fwinpgen.c;h=db47e60f8be7e2661302582d95dfeac29af6e27c;hb=2bf868835591b39f17a157b1511b1e2f4b6e77da;hp=1e3910515ddd71af6a663eaa55099179644f2b1d;hpb=62cbc7dc0b33808dc8794c59f60971fbba97894b;p=PuTTY.git diff --git a/windows/winpgen.c b/windows/winpgen.c index 1e391051..db47e60f 100644 --- a/windows/winpgen.c +++ b/windows/winpgen.c @@ -5,6 +5,7 @@ #include #include #include +#include #define PUTTY_DO_GLOBALS @@ -19,7 +20,7 @@ #define WM_DONEKEY (WM_APP + 1) -#define DEFAULT_KEYSIZE 1024 +#define DEFAULT_KEYSIZE 2048 static char *cmdline_keyfile = NULL; @@ -40,6 +41,22 @@ void modalfatalbox(char *fmt, ...) exit(1); } +/* + * Print a non-fatal message box and do not exit. + */ +void nonfatal(char *fmt, ...) +{ + va_list ap; + char *stuff; + + va_start(ap, fmt); + stuff = dupvprintf(fmt, ap); + va_end(ap); + MessageBox(NULL, stuff, "PuTTYgen Error", + MB_SYSTEMMODAL | MB_ICONERROR | MB_OK); + sfree(stuff); +} + /* ---------------------------------------------------------------------- * Progress report code. This is really horrible :-) */ @@ -116,10 +133,8 @@ static void progress_update(void *param, int action, int phase, int iprogress) extern char ver[]; -#define PASSPHRASE_MAXLEN 512 - struct PassphraseProcStruct { - char *passphrase; + char **passphrase; char *comment; }; @@ -129,7 +144,7 @@ struct PassphraseProcStruct { static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - static char *passphrase = NULL; + static char **passphrase = NULL; struct PassphraseProcStruct *p; switch (msg) { @@ -157,8 +172,9 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, passphrase = p->passphrase; if (p->comment) SetDlgItemText(hwnd, 101, p->comment); - *passphrase = 0; - SetDlgItemText(hwnd, 102, passphrase); + burnstr(*passphrase); + *passphrase = dupstr(""); + SetDlgItemText(hwnd, 102, *passphrase); return 0; case WM_COMMAND: switch (LOWORD(wParam)) { @@ -173,9 +189,8 @@ static int CALLBACK PassphraseProc(HWND hwnd, UINT msg, return 0; case 102: /* edit box */ if ((HIWORD(wParam) == EN_CHANGE) && passphrase) { - GetDlgItemText(hwnd, 102, passphrase, - PASSPHRASE_MAXLEN - 1); - passphrase[PASSPHRASE_MAXLEN - 1] = '\0'; + burnstr(*passphrase); + *passphrase = GetDlgItemText_alloc(hwnd, 102); } return 0; } @@ -300,6 +315,8 @@ static int CALLBACK AboutProc(HWND hwnd, UINT msg, return 0; } +typedef enum {RSA, DSA, ECDSA} keytype; + /* * Thread to generate a key. */ @@ -307,9 +324,12 @@ struct rsa_key_thread_params { HWND progressbar; /* notify this with progress */ HWND dialog; /* notify this on completion */ int keysize; /* bits in key */ - int is_dsa; - struct RSAKey *key; - struct dss_key *dsskey; + keytype keytype; + union { + struct RSAKey *key; + struct dss_key *dsskey; + struct ec_key *eckey; + }; }; static DWORD WINAPI generate_rsa_key_thread(void *param) { @@ -320,8 +340,10 @@ static DWORD WINAPI generate_rsa_key_thread(void *param) progress_update(&prog, PROGFN_INITIALISE, 0, 0); - if (params->is_dsa) + if (params->keytype == DSA) dsa_generate(params->dsskey, params->keysize, progress_update, &prog); + else if (params->keytype == ECDSA) + ec_generate(params->eckey, params->keysize, progress_update, &prog); else rsa_generate(params->key, params->keysize, progress_update, &prog); @@ -337,12 +359,16 @@ struct MainDlgState { int key_exists; int entropy_got, entropy_required, entropy_size; int keysize; - int ssh2, is_dsa; + int ssh2; + keytype keytype; char **commentptr; /* points to key.comment or ssh2key.comment */ struct ssh2_userkey ssh2key; unsigned *entropy; - struct RSAKey key; - struct dss_key dsskey; + union { + struct RSAKey key; + struct dss_key dsskey; + struct ec_key eckey; + }; HMENU filemenu, keymenu, cvtmenu; }; @@ -405,11 +431,11 @@ 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; + 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); @@ -504,6 +530,7 @@ enum { IDC_SAVESTATIC, IDC_SAVE, IDC_SAVEPUB, IDC_BOX_PARAMS, IDC_TYPESTATIC, IDC_KEYSSH1, IDC_KEYSSH2RSA, IDC_KEYSSH2DSA, + IDC_KEYSSH2ECDSA, IDC_BITSSTATIC, IDC_BITS, IDC_ABOUT, IDC_GIVEHELP, @@ -540,6 +567,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1); EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1); EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 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); @@ -548,6 +576,8 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA, + MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH, MF_GRAYED|MF_BYCOMMAND); @@ -565,6 +595,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 0); EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 0); EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 0); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 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); @@ -573,6 +604,8 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA, MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA, MF_GRAYED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA, + MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_EXPORT_OPENSSH, MF_GRAYED|MF_BYCOMMAND); @@ -590,6 +623,7 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH1), 1); EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2RSA), 1); EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2DSA), 1); + EnableWindow(GetDlgItem(hwnd, IDC_KEYSSH2ECDSA), 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); @@ -598,6 +632,8 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) EnableMenuItem(state->keymenu, IDC_KEYSSH1, MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->keymenu, IDC_KEYSSH2RSA,MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->keymenu, IDC_KEYSSH2DSA,MF_ENABLED|MF_BYCOMMAND); + EnableMenuItem(state->keymenu, IDC_KEYSSH2ECDSA, + MF_ENABLED|MF_BYCOMMAND); EnableMenuItem(state->cvtmenu, IDC_IMPORT, MF_ENABLED|MF_BYCOMMAND); /* * Enable export menu items if and only if the key type @@ -617,13 +653,12 @@ void ui_set_state(HWND hwnd, struct MainDlgState *state, int status) void load_key_file(HWND hwnd, struct MainDlgState *state, Filename *filename, int was_import_cmd) { - char passphrase[PASSPHRASE_MAXLEN]; + char *passphrase; int needs_pass; int type, realtype; int ret; const char *errmsg = NULL; char *comment; - struct PassphraseProcStruct pps; struct RSAKey newkey1; struct ssh2_userkey *newkey2 = NULL; @@ -646,17 +681,22 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, } comment = NULL; + passphrase = NULL; if (realtype == SSH_KEYTYPE_SSH1) needs_pass = rsakey_encrypted(filename, &comment); 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 { + burnstr(passphrase); + passphrase = NULL; + if (needs_pass) { int dlgret; + struct PassphraseProcStruct pps; + pps.passphrase = &passphrase; + pps.comment = comment; dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210), NULL, PassphraseProc, @@ -665,8 +705,9 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, ret = -2; break; } + assert(passphrase != NULL); } else - *passphrase = '\0'; + passphrase = dupstr(""); if (type == SSH_KEYTYPE_SSH1) { if (realtype == type) ret = loadrsakey(filename, &newkey1, passphrase, &errmsg); @@ -779,6 +820,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state, MB_OK | MB_ICONINFORMATION); } } + burnstr(passphrase); } /* @@ -834,6 +876,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, AppendMenu(menu1, MF_ENABLED, IDC_KEYSSH1, "SSH-&1 key (RSA)"); 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(menu, MF_POPUP | MF_ENABLED, (UINT) menu1, "&Key"); state->keymenu = menu1; @@ -912,13 +955,14 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, radioline(&cp, "Type of key to generate:", IDC_TYPESTATIC, 3, "SSH-&1 (RSA)", IDC_KEYSSH1, "SSH-2 &RSA", IDC_KEYSSH2RSA, - "SSH-2 &DSA", IDC_KEYSSH2DSA, NULL); + "SSH-2 &DSA", IDC_KEYSSH2DSA, + "SSH-2 &ECDSA", IDC_KEYSSH2ECDSA, NULL); staticedit(&cp, "Number of &bits in a generated key:", IDC_BITSSTATIC, IDC_BITS, 20); endbox(&cp); } - CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2DSA, IDC_KEYSSH2RSA); - CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA, + CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA, IDC_KEYSSH2RSA); + CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2ECDSA, IDC_KEYSSH2RSA, MF_BYCOMMAND); SetDlgItemInt(hwnd, IDC_BITS, DEFAULT_KEYSIZE, FALSE); @@ -933,8 +977,11 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, /* * Load a key file if one was provided on the command line. */ - if (cmdline_keyfile) - load_key_file(hwnd, state, filename_from_str(cmdline_keyfile), 0); + if (cmdline_keyfile) { + Filename *fn = filename_from_str(cmdline_keyfile); + load_key_file(hwnd, state, fn, 0); + filename_free(fn); + } return 1; case WM_MOUSEMOVE: @@ -953,7 +1000,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, * Seed the entropy pool */ random_add_heavynoise(state->entropy, state->entropy_size); - memset(state->entropy, 0, state->entropy_size); + smemclr(state->entropy, state->entropy_size); sfree(state->entropy); state->collecting_entropy = FALSE; @@ -966,7 +1013,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, params->progressbar = GetDlgItem(hwnd, IDC_PROGRESS); params->dialog = hwnd; params->keysize = state->keysize; - params->is_dsa = state->is_dsa; + params->keytype = state->keytype; params->key = &state->key; params->dsskey = &state->dsskey; @@ -987,6 +1034,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, case IDC_KEYSSH1: case IDC_KEYSSH2RSA: case IDC_KEYSSH2DSA: + case IDC_KEYSSH2ECDSA: { state = (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); @@ -995,6 +1043,11 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, LOWORD(wParam)); CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, IDC_KEYSSH2DSA, LOWORD(wParam), MF_BYCOMMAND); + CheckRadioButton(hwnd, IDC_KEYSSH1, IDC_KEYSSH2ECDSA, + LOWORD(wParam)); + CheckMenuRadioItem(state->keymenu, IDC_KEYSSH1, + IDC_KEYSSH2ECDSA, + LOWORD(wParam), MF_BYCOMMAND); } break; case IDC_QUIT: @@ -1046,7 +1099,12 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, state->keysize = DEFAULT_KEYSIZE; /* If we ever introduce a new key type, check it here! */ state->ssh2 = !IsDlgButtonChecked(hwnd, IDC_KEYSSH1); - state->is_dsa = IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA); + state->keytype = RSA; + if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2DSA)) { + state->keytype = DSA; + } else if (IsDlgButtonChecked(hwnd, IDC_KEYSSH2ECDSA)) { + state->keytype = ECDSA; + } if (state->keysize < 256) { int ret = MessageBox(hwnd, "PuTTYgen will not generate a key" @@ -1059,6 +1117,20 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, state->keysize = 256; SetDlgItemInt(hwnd, IDC_BITS, 256, FALSE); } + if (state->keytype == ECDSA && !(state->keysize == 256 || + state->keysize == 384 || + state->keysize == 521)) { + int ret = MessageBox(hwnd, + "Only 256, 384 and 521 bit 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; @@ -1097,8 +1169,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, (struct MainDlgState *) GetWindowLongPtr(hwnd, GWLP_USERDATA); if (state->key_exists) { char filename[FILENAME_MAX]; - char passphrase[PASSPHRASE_MAXLEN]; - char passphrase2[PASSPHRASE_MAXLEN]; + char *passphrase, *passphrase2; int type, realtype; if (state->ssh2) @@ -1124,16 +1195,17 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, break; } - GetDlgItemText(hwnd, IDC_PASSPHRASE1EDIT, - passphrase, sizeof(passphrase)); - GetDlgItemText(hwnd, IDC_PASSPHRASE2EDIT, - passphrase2, sizeof(passphrase2)); + passphrase = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE1EDIT); + passphrase2 = GetDlgItemText_alloc(hwnd, IDC_PASSPHRASE2EDIT); if (strcmp(passphrase, passphrase2)) { MessageBox(hwnd, "The two passphrases given do not match.", "PuTTYgen Error", MB_OK | MB_ICONERROR); + burnstr(passphrase); + burnstr(passphrase2); break; } + burnstr(passphrase2); if (!*passphrase) { int ret; ret = MessageBox(hwnd, @@ -1141,8 +1213,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, "without a passphrase to protect it?", "PuTTYgen Warning", MB_YESNO | MB_ICONWARNING); - if (ret != IDYES) - break; + if (ret != IDYES) { + burnstr(passphrase); + break; + } } if (prompt_keyfile(hwnd, "Save private key as:", filename, 1, (type == realtype))) { @@ -1156,8 +1230,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, ret = MessageBox(hwnd, buffer, "PuTTYgen Warning", MB_YESNO | MB_ICONWARNING); sfree(buffer); - if (ret != IDYES) + if (ret != IDYES) { + burnstr(passphrase); break; + } } if (state->ssh2) { @@ -1185,6 +1261,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, "PuTTYgen Error", MB_OK | MB_ICONERROR); } } + burnstr(passphrase); } break; case IDC_SAVEPUB: @@ -1230,9 +1307,11 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, if (!state->generation_thread_exists) { char filename[FILENAME_MAX]; if (prompt_keyfile(hwnd, "Load private key:", - filename, 0, LOWORD(wParam)==IDC_LOAD)) - load_key_file(hwnd, state, filename_from_str(filename), - LOWORD(wParam) != IDC_LOAD); + filename, 0, LOWORD(wParam)==IDC_LOAD)) { + Filename *fn = filename_from_str(filename); + load_key_file(hwnd, state, fn, LOWORD(wParam) != IDC_LOAD); + filename_free(fn); + } } break; } @@ -1245,9 +1324,17 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, MAKELPARAM(0, PROGRESSRANGE)); SendDlgItemMessage(hwnd, IDC_PROGRESS, PBM_SETPOS, PROGRESSRANGE, 0); if (state->ssh2) { - if (state->is_dsa) { + if (state->keytype == DSA) { state->ssh2key.data = &state->dsskey; 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; } else { state->ssh2key.data = &state->key; state->ssh2key.alg = &ssh_rsa; @@ -1266,8 +1353,10 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, { struct tm tm; tm = ltime(); - if (state->is_dsa) + if (state->keytype == DSA) 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 strftime(*state->commentptr, 30, "rsa-key-%Y%m%d", &tm); } @@ -1358,6 +1447,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg, case IDC_KEYSSH1: case IDC_KEYSSH2RSA: case IDC_KEYSSH2DSA: + case IDC_KEYSSH2ECDSA: topic = WINHELP_CTX_puttygen_keytype; break; case IDC_BITSSTATIC: case IDC_BITS: