1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Windows Pageant: initial work on deferred decryption.

This fills in the missing piece of Windows Pageant's story on deferred
decryption: we now actually know how to put up a dialog box asking for
the passphrase, when a not-yet-decrypted key is used.

This is quite a rough implementation so far, but it's a start. Known
issues:

 - these new non-modal dialog boxes are serialised with respect to
   each other by the Pageant core, but they can run in parallel with a
   passphrase prompt popping up from the ordinary GUI 'Add Key'
   operation. That may be too confusing; perhaps I should fix it.

 - I'm not confident that the passphrase dialog box gets the keyboard
   focus in all situations where I'd like it to (or what I can do
   about it if not).

 - the text in the non-modal box has two copies of the instruction
   'enter passphrase for key'.
This commit is contained in:
Simon Tatham 2020-03-21 15:59:51 +00:00
parent 9fc8320fc3
commit 26930236ae

View File

@ -97,8 +97,10 @@ void modalfatalbox(const char *fmt, ...)
static bool has_security; static bool has_security;
struct PassphraseProcStruct { struct PassphraseProcStruct {
char **passphrase; bool modal;
char *comment; PageantClientDialogId *dlgid;
char *passphrase;
const char *comment;
}; };
/* /*
@ -173,7 +175,30 @@ static INT_PTR CALLBACK AboutProc(HWND hwnd, UINT msg,
return 0; return 0;
} }
static HWND passphrase_box; static HWND modal_passphrase_hwnd = NULL;
static HWND nonmodal_passphrase_hwnd = NULL;
static void end_passphrase_dialog(HWND hwnd, INT_PTR result)
{
struct PassphraseProcStruct *p = (struct PassphraseProcStruct *)
GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (p->modal) {
EndDialog(hwnd, result);
} else {
if (result)
pageant_passphrase_request_success(
p->dlgid, ptrlen_from_asciz(p->passphrase));
else
pageant_passphrase_request_refused(p->dlgid);
burnstr(p->passphrase);
sfree(p);
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) NULL);
DestroyWindow(hwnd);
nonmodal_passphrase_hwnd = NULL;
}
}
/* /*
* Dialog-box function for the passphrase box. * Dialog-box function for the passphrase box.
@ -181,12 +206,21 @@ static HWND passphrase_box;
static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg, static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam) WPARAM wParam, LPARAM lParam)
{ {
static char **passphrase = NULL;
struct PassphraseProcStruct *p; struct PassphraseProcStruct *p;
if (msg == WM_INITDIALOG) {
p = (struct PassphraseProcStruct *) lParam;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) p);
} else {
p = (struct PassphraseProcStruct *)
GetWindowLongPtr(hwnd, GWLP_USERDATA);
}
switch (msg) { switch (msg) {
case WM_INITDIALOG: { case WM_INITDIALOG: {
passphrase_box = hwnd; if (p->modal)
modal_passphrase_hwnd = hwnd;
/* /*
* Centre the window. * Centre the window.
*/ */
@ -203,36 +237,36 @@ static INT_PTR CALLBACK PassphraseProc(HWND hwnd, UINT msg,
SetForegroundWindow(hwnd); SetForegroundWindow(hwnd);
SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
p = (struct PassphraseProcStruct *) lParam; if (!p->modal)
passphrase = p->passphrase; SetActiveWindow(hwnd); /* this won't have happened automatically */
if (p->comment) if (p->comment)
SetDlgItemText(hwnd, 101, p->comment); SetDlgItemText(hwnd, 101, p->comment);
burnstr(*passphrase); burnstr(p->passphrase);
*passphrase = dupstr(""); p->passphrase = dupstr("");
SetDlgItemText(hwnd, 102, *passphrase); SetDlgItemText(hwnd, 102, p->passphrase);
return 0; return 0;
} }
case WM_COMMAND: case WM_COMMAND:
switch (LOWORD(wParam)) { switch (LOWORD(wParam)) {
case IDOK: case IDOK:
if (*passphrase) if (p->passphrase)
EndDialog(hwnd, 1); end_passphrase_dialog(hwnd, 1);
else else
MessageBeep(0); MessageBeep(0);
return 0; return 0;
case IDCANCEL: case IDCANCEL:
EndDialog(hwnd, 0); end_passphrase_dialog(hwnd, 0);
return 0; return 0;
case 102: /* edit box */ case 102: /* edit box */
if ((HIWORD(wParam) == EN_CHANGE) && passphrase) { if ((HIWORD(wParam) == EN_CHANGE) && p->passphrase) {
burnstr(*passphrase); burnstr(p->passphrase);
*passphrase = GetDlgItemText_alloc(hwnd, 102); p->passphrase = GetDlgItemText_alloc(hwnd, 102);
} }
return 0; return 0;
} }
return 0; return 0;
case WM_CLOSE: case WM_CLOSE:
EndDialog(hwnd, 0); end_passphrase_dialog(hwnd, 0);
return 0; return 0;
} }
return 0; return 0;
@ -364,7 +398,6 @@ static void win_add_keyfile(Filename *filename)
{ {
char *err; char *err;
int ret; int ret;
char *passphrase = NULL;
/* /*
* Try loading the key without a passphrase. (Or rather, without a * Try loading the key without a passphrase. (Or rather, without a
@ -385,40 +418,37 @@ static void win_add_keyfile(Filename *filename)
while (1) { while (1) {
INT_PTR dlgret; INT_PTR dlgret;
struct PassphraseProcStruct pps; struct PassphraseProcStruct pps;
pps.modal = true;
pps.passphrase = &passphrase; pps.dlgid = NULL;
pps.passphrase = NULL;
pps.comment = err; pps.comment = err;
dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210), dlgret = DialogBoxParam(hinst, MAKEINTRESOURCE(210),
NULL, PassphraseProc, (LPARAM) &pps); NULL, PassphraseProc, (LPARAM) &pps);
passphrase_box = NULL; modal_passphrase_hwnd = NULL;
if (!dlgret) if (!dlgret) {
burnstr(pps.passphrase);
goto done; /* operation cancelled */ goto done; /* operation cancelled */
}
sfree(err); sfree(err);
assert(passphrase != NULL); assert(pps.passphrase != NULL);
ret = pageant_add_keyfile(filename, pps.passphrase, &err, false);
burnstr(pps.passphrase);
ret = pageant_add_keyfile(filename, passphrase, &err, false);
if (ret == PAGEANT_ACTION_OK) { if (ret == PAGEANT_ACTION_OK) {
goto done; goto done;
} else if (ret == PAGEANT_ACTION_FAILURE) { } else if (ret == PAGEANT_ACTION_FAILURE) {
goto error; goto error;
} }
smemclr(passphrase, strlen(passphrase));
sfree(passphrase);
passphrase = NULL;
} }
error: error:
message_box(traywindow, err, APPNAME, MB_OK | MB_ICONERROR, message_box(traywindow, err, APPNAME, MB_OK | MB_ICONERROR,
HELPCTXID(errors_cantloadkey)); HELPCTXID(errors_cantloadkey));
done: done:
if (passphrase) {
smemclr(passphrase, strlen(passphrase));
sfree(passphrase);
}
sfree(err); sfree(err);
return; return;
} }
@ -527,9 +557,9 @@ static INT_PTR CALLBACK KeyListProc(HWND hwnd, UINT msg,
case 101: /* add key */ case 101: /* add key */
if (HIWORD(wParam) == BN_CLICKED || if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED) { HIWORD(wParam) == BN_DOUBLECLICKED) {
if (passphrase_box) { if (modal_passphrase_hwnd) {
MessageBeep(MB_ICONERROR); MessageBeep(MB_ICONERROR);
SetForegroundWindow(passphrase_box); SetForegroundWindow(modal_passphrase_hwnd);
break; break;
} }
prompt_add_keyfile(); prompt_add_keyfile();
@ -788,11 +818,29 @@ static void wm_copydata_got_response(
SetEvent(wmct.ev_reply_ready); SetEvent(wmct.ev_reply_ready);
} }
static bool ask_passphrase_common(PageantClientDialogId *dlgid,
const char *msg)
{
/* Pageant core should be serialising requests, so we never expect
* a passphrase prompt to exist already at this point */
assert(!nonmodal_passphrase_hwnd);
struct PassphraseProcStruct *pps = snew(struct PassphraseProcStruct);
pps->modal = false;
pps->dlgid = dlgid;
pps->passphrase = NULL;
pps->comment = msg;
nonmodal_passphrase_hwnd = CreateDialogParam(
hinst, MAKEINTRESOURCE(210), NULL, PassphraseProc, (LPARAM)pps);
return true;
}
static bool wm_copydata_ask_passphrase( static bool wm_copydata_ask_passphrase(
PageantClient *pc, PageantClientDialogId *dlgid, const char *msg) PageantClient *pc, PageantClientDialogId *dlgid, const char *msg)
{ {
/* FIXME: we don't yet support dialog boxes */ return ask_passphrase_common(dlgid, msg);
return false;
} }
static const PageantClientVtable wmcpc_vtable = { static const PageantClientVtable wmcpc_vtable = {
@ -1017,8 +1065,8 @@ static LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT message,
break; break;
} }
case IDM_CLOSE: case IDM_CLOSE:
if (passphrase_box) if (modal_passphrase_hwnd)
SendMessage(passphrase_box, WM_CLOSE, 0, 0); SendMessage(modal_passphrase_hwnd, WM_CLOSE, 0, 0);
SendMessage(hwnd, WM_CLOSE, 0, 0); SendMessage(hwnd, WM_CLOSE, 0, 0);
break; break;
case IDM_VIEWKEYS: case IDM_VIEWKEYS:
@ -1039,9 +1087,9 @@ static LRESULT CALLBACK TrayWndProc(HWND hwnd, UINT message,
SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
break; break;
case IDM_ADDKEY: case IDM_ADDKEY:
if (passphrase_box) { if (modal_passphrase_hwnd) {
MessageBeep(MB_ICONERROR); MessageBeep(MB_ICONERROR);
SetForegroundWindow(passphrase_box); SetForegroundWindow(modal_passphrase_hwnd);
break; break;
} }
prompt_add_keyfile(); prompt_add_keyfile();
@ -1180,8 +1228,7 @@ void cleanup_exit(int code)
static bool winpgnt_listener_ask_passphrase( static bool winpgnt_listener_ask_passphrase(
PageantListenerClient *plc, PageantClientDialogId *dlgid, const char *msg) PageantListenerClient *plc, PageantClientDialogId *dlgid, const char *msg)
{ {
/* FIXME: we don't yet support dialog boxes */ return ask_passphrase_common(dlgid, msg);
return false;
} }
struct winpgnt_client { struct winpgnt_client {
@ -1464,6 +1511,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
continue; continue;
if (IsWindow(aboutbox) && IsDialogMessage(aboutbox, &msg)) if (IsWindow(aboutbox) && IsDialogMessage(aboutbox, &msg))
continue; continue;
if (IsWindow(nonmodal_passphrase_hwnd) &&
IsDialogMessage(nonmodal_passphrase_hwnd, &msg))
continue;
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);