1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-01 03:22:48 -05:00

Move sanitisation of k-i prompts into the SSH code.

Now, instead of each seat's prompt-handling function doing the
control-char sanitisation of prompt text, the SSH code does it. This
means we can do it differently depending on the prompt.

In particular, prompts _we_ generate (e.g. a genuine request for your
private key's passphrase) are not sanitised; but prompts coming from
the server (in keyboard-interactive mode, or its more restricted SSH-1
analogues, TIS and CryptoCard) are not only sanitised but also
line-length limited and surrounded by uncounterfeitable headers, like
I've just done to the authentication banners.

This should mean that if a malicious server tries to fake the local
passphrase prompt (perhaps because it's somehow already got a copy of
your _encrypted_ private key), you can tell the difference.
This commit is contained in:
Simon Tatham
2019-03-09 15:51:38 +00:00
parent 767a9c6e45
commit e21afff605
6 changed files with 182 additions and 142 deletions

View File

@ -494,22 +494,9 @@ static void console_close(FILE *outfp, int infd)
fclose(outfp); /* will automatically close infd too */
}
static void console_prompt_text(FILE *outfp, const char *data, size_t len)
static void console_write(FILE *outfp, ptrlen data)
{
bufchain sanitised;
bufchain_sink bs;
bufchain_init(&sanitised);
bufchain_sink_init(&bs, &sanitised);
StripCtrlChars *scc = stripctrl_new(BinarySink_UPCAST(&bs), false, 0);
put_data(scc, data, len);
stripctrl_free(scc);
while (bufchain_size(&sanitised) > 0) {
ptrlen sdata = bufchain_prefix(&sanitised);
fwrite(sdata.ptr, 1, sdata.len, outfp);
bufchain_consume(&sanitised, sdata.len);
}
fwrite(data.ptr, 1, data.len, outfp);
fflush(outfp);
}
@ -538,17 +525,17 @@ int console_get_userpass_input(prompts_t *p)
*/
/* We only print the `name' caption if we have to... */
if (p->name_reqd && p->name) {
size_t l = strlen(p->name);
console_prompt_text(outfp, p->name, l);
if (p->name[l-1] != '\n')
console_prompt_text(outfp, "\n", 1);
ptrlen plname = ptrlen_from_asciz(p->name);
console_write(outfp, plname);
if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
console_write(outfp, PTRLEN_LITERAL("\n"));
}
/* ...but we always print any `instruction'. */
if (p->instruction) {
size_t l = strlen(p->instruction);
console_prompt_text(outfp, p->instruction, l);
if (p->instruction[l-1] != '\n')
console_prompt_text(outfp, "\n", 1);
ptrlen plinst = ptrlen_from_asciz(p->instruction);
console_write(outfp, plinst);
if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
console_write(outfp, PTRLEN_LITERAL("\n"));
}
for (curr_prompt = 0; curr_prompt < p->n_prompts; curr_prompt++) {
@ -566,7 +553,7 @@ int console_get_userpass_input(prompts_t *p)
newmode.c_lflag |= ECHO;
tcsetattr(infd, TCSANOW, &newmode);
console_prompt_text(outfp, pr->prompt, strlen(pr->prompt));
console_write(outfp, ptrlen_from_asciz(pr->prompt));
len = 0;
while (1) {
@ -588,7 +575,7 @@ int console_get_userpass_input(prompts_t *p)
tcsetattr(infd, TCSANOW, &oldmode);
if (!pr->echo)
console_prompt_text(outfp, "\n", 1);
console_write(outfp, PTRLEN_LITERAL("\n"));
if (len < 0) {
console_close(outfp, infd);