1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-07 06:22:47 -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

@ -1682,9 +1682,6 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win)
term->paste_buffer = NULL;
term->paste_len = 0;
bufchain_init(&term->inbuf);
bufchain_sink_init(&term->inbuf_bs, &term->inbuf);
term->inbuf_scc = stripctrl_new_term(
BinarySink_UPCAST(&term->inbuf_bs), false, 0, term);
bufchain_init(&term->printer_buf);
term->printing = term->only_printing = false;
term->print_job = NULL;
@ -1779,7 +1776,6 @@ void term_free(Terminal *term)
term->beephead = beep->next;
sfree(beep);
}
stripctrl_free(term->inbuf_scc);
bufchain_clear(&term->inbuf);
if(term->print_job)
printer_finish_job(term->print_job);
@ -6837,12 +6833,6 @@ size_t term_data(Terminal *term, bool is_stderr, const void *data, size_t len)
return 0;
}
static void term_data_untrusted(Terminal *term, const void *data, size_t len)
{
put_data(term->inbuf_scc, data, len);
term_added_data(term);
}
void term_provide_logctx(Terminal *term, LogContext *logctx)
{
term->logctx = logctx;
@ -6877,6 +6867,12 @@ struct term_userpass_state {
size_t pos; /* cursor position */
};
/* Tiny wrapper to make it easier to write lots of little strings */
static inline void term_write(Terminal *term, ptrlen data)
{
term_data(term, false, data.ptr, data.len);
}
/*
* Process some terminal data in the course of username/password
* input.
@ -6893,17 +6889,17 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
s->done_prompt = false;
/* We only print the `name' caption if we have to... */
if (p->name_reqd && p->name) {
size_t l = strlen(p->name);
term_data_untrusted(term, p->name, l);
if (p->name[l-1] != '\n')
term_data_untrusted(term, "\n", 1);
ptrlen plname = ptrlen_from_asciz(p->name);
term_write(term, plname);
if (!ptrlen_endswith(plname, PTRLEN_LITERAL("\n"), NULL))
term_write(term, PTRLEN_LITERAL("\r\n"));
}
/* ...but we always print any `instruction'. */
if (p->instruction) {
size_t l = strlen(p->instruction);
term_data_untrusted(term, p->instruction, l);
if (p->instruction[l-1] != '\n')
term_data_untrusted(term, "\n", 1);
ptrlen plinst = ptrlen_from_asciz(p->instruction);
term_write(term, plinst);
if (!ptrlen_endswith(plinst, PTRLEN_LITERAL("\n"), NULL))
term_write(term, PTRLEN_LITERAL("\r\n"));
}
/*
* Zero all the results, in case we abort half-way through.
@ -6921,7 +6917,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
bool finished_prompt = false;
if (!s->done_prompt) {
term_data_untrusted(term, pr->prompt, strlen(pr->prompt));
term_write(term, ptrlen_from_asciz(pr->prompt));
s->done_prompt = true;
s->pos = 0;
}
@ -6937,7 +6933,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
switch (c) {
case 10:
case 13:
term_data(term, false, "\r\n", 2);
term_write(term, PTRLEN_LITERAL("\r\n"));
prompt_ensure_result_size(pr, s->pos + 1);
pr->result[s->pos] = '\0';
/* go to next prompt, if any */
@ -6949,7 +6945,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
case 127:
if (s->pos > 0) {
if (pr->echo)
term_data(term, false, "\b \b", 3);
term_write(term, PTRLEN_LITERAL("\b \b"));
s->pos--;
}
break;
@ -6957,14 +6953,14 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
case 27:
while (s->pos > 0) {
if (pr->echo)
term_data(term, false, "\b \b", 3);
term_write(term, PTRLEN_LITERAL("\b \b"));
s->pos--;
}
break;
case 3:
case 4:
/* Immediate abort. */
term_data(term, false, "\r\n", 2);
term_write(term, PTRLEN_LITERAL("\r\n"));
sfree(s);
p->data = NULL;
return 0; /* user abort */
@ -6979,7 +6975,7 @@ int term_get_userpass_input(Terminal *term, prompts_t *p, bufchain *input)
prompt_ensure_result_size(pr, s->pos + 1);
pr->result[s->pos++] = c;
if (pr->echo)
term_data(term, false, &c, 1);
term_write(term, make_ptrlen(&c, 1));
}
break;
}