mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-25 01:02:24 +00:00
Special host key warning when a better key exists.
If you're connecting to a new server and it _only_ provides host key types you've configured to be below the warning threshold, it's OK to give the standard askalg() message. But if you've newly demoted a host key type and now reconnect to some server for which that type was the best key you had cached, the askalg() wording isn't really appropriate (it's not that the key we've settled on is the first type _supported by the server_, it's that it's the first type _cached by us_), and also it's potentially helpful to list the better algorithms so that the user can pick one to cross-certify.
This commit is contained in:
parent
909a7af07c
commit
940a82fd37
9
putty.h
9
putty.h
@ -1232,10 +1232,17 @@ int verify_ssh_host_key(void *frontend, char *host, int port,
|
||||
*/
|
||||
int have_ssh_host_key(const char *host, int port, const char *keytype);
|
||||
/*
|
||||
* askalg has the same set of return values as verify_ssh_host_key.
|
||||
* askalg and askhk have the same set of return values as
|
||||
* verify_ssh_host_key.
|
||||
*
|
||||
* (askhk is used in the case where we're using a host key below the
|
||||
* warning threshold because that's all we have cached, but at least
|
||||
* one acceptable algorithm is available that we don't have cached.)
|
||||
*/
|
||||
int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
void (*callback)(void *ctx, int result), void *ctx);
|
||||
int askhk(void *frontend, const char *algname, const char *betteralgs,
|
||||
void (*callback)(void *ctx, int result), void *ctx);
|
||||
/*
|
||||
* askappend can return four values:
|
||||
*
|
||||
|
49
ssh.c
49
ssh.c
@ -6813,10 +6813,53 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
|
||||
}
|
||||
|
||||
if (s->warn_hk) {
|
||||
int j, k;
|
||||
char *betteralgs;
|
||||
|
||||
ssh_set_frozen(ssh, 1);
|
||||
s->dlgret = askalg(ssh->frontend, "host key type",
|
||||
ssh->hostkey->name,
|
||||
ssh_dialog_callback, ssh);
|
||||
|
||||
/*
|
||||
* Change warning box wording depending on why we chose a
|
||||
* warning-level host key algorithm. If it's because
|
||||
* that's all we have *cached*, use the askhk mechanism,
|
||||
* and list the host keys we could usefully cross-certify.
|
||||
* Otherwise, use askalg for the standard wording.
|
||||
*/
|
||||
betteralgs = NULL;
|
||||
for (j = 0; j < ssh->n_uncert_hostkeys; j++) {
|
||||
const struct ssh_signkey_with_user_pref_id *hktype =
|
||||
&hostkey_algs[ssh->uncert_hostkeys[j]];
|
||||
int better = FALSE;
|
||||
for (k = 0; k < HK_MAX; k++) {
|
||||
int id = conf_get_int_int(ssh->conf, CONF_ssh_hklist, k);
|
||||
if (id == HK_WARN) {
|
||||
break;
|
||||
} else if (id == hktype->id) {
|
||||
better = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (better) {
|
||||
if (betteralgs) {
|
||||
char *old_ba = betteralgs;
|
||||
betteralgs = dupcat(betteralgs, ",",
|
||||
hktype->alg->name,
|
||||
(const char *)NULL);
|
||||
sfree(old_ba);
|
||||
} else {
|
||||
betteralgs = dupstr(hktype->alg->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (betteralgs) {
|
||||
s->dlgret = askhk(ssh->frontend, ssh->hostkey->name,
|
||||
betteralgs, ssh_dialog_callback, ssh);
|
||||
sfree(betteralgs);
|
||||
} else {
|
||||
s->dlgret = askalg(ssh->frontend, "host key type",
|
||||
ssh->hostkey->name,
|
||||
ssh_dialog_callback, ssh);
|
||||
}
|
||||
if (s->dlgret < 0) {
|
||||
do {
|
||||
crReturnV;
|
||||
|
@ -3562,6 +3562,37 @@ int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
}
|
||||
}
|
||||
|
||||
int askhk(void *frontend, const char *algname, const char *betteralgs,
|
||||
void (*callback)(void *ctx, int result), void *ctx)
|
||||
{
|
||||
static const char msg[] =
|
||||
"The first host key type we have stored for this server\n"
|
||||
"is %s, which is below the configured warning threshold.\n"
|
||||
"The server also provides the following types of host key\n"
|
||||
"above the threshold, which we do not have stored:\n"
|
||||
"%s\n"
|
||||
"Continue with connection?";
|
||||
char *text;
|
||||
int ret;
|
||||
|
||||
text = dupprintf(msg, algname, betteralgs);
|
||||
ret = messagebox(GTK_WIDGET(get_window(frontend)),
|
||||
"PuTTY Security Alert", text,
|
||||
string_width("is ecdsa-nistp521, which is"
|
||||
" below the configured warning threshold."),
|
||||
FALSE,
|
||||
"Yes", 'y', 0, 1,
|
||||
"No", 'n', 0, 0,
|
||||
NULL);
|
||||
sfree(text);
|
||||
|
||||
if (ret) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void old_keyfile_warning(void)
|
||||
{
|
||||
/*
|
||||
|
@ -264,6 +264,59 @@ int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
}
|
||||
}
|
||||
|
||||
int askhk(void *frontend, const char *algname, const char *betteralgs,
|
||||
void (*callback)(void *ctx, int result), void *ctx)
|
||||
{
|
||||
static const char msg[] =
|
||||
"The first host key type we have stored for this server\n"
|
||||
"is %s, which is below the configured warning threshold.\n"
|
||||
"The server also provides the following types of host key\n"
|
||||
"above the threshold, which we do not have stored:\n"
|
||||
"%s\n"
|
||||
"Continue with connection? (y/n) ";
|
||||
static const char msg_batch[] =
|
||||
"The first host key type we have stored for this server\n"
|
||||
"is %s, which is below the configured warning threshold.\n"
|
||||
"The server also provides the following types of host key\n"
|
||||
"above the threshold, which we do not have stored:\n"
|
||||
"%s\n"
|
||||
"Connection abandoned.\n";
|
||||
static const char abandoned[] = "Connection abandoned.\n";
|
||||
|
||||
char line[32];
|
||||
struct termios cf;
|
||||
|
||||
premsg(&cf);
|
||||
if (console_batch_mode) {
|
||||
fprintf(stderr, msg_batch, algname, betteralgs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, msg, algname, betteralgs);
|
||||
fflush(stderr);
|
||||
|
||||
{
|
||||
struct termios oldmode, newmode;
|
||||
tcgetattr(0, &oldmode);
|
||||
newmode = oldmode;
|
||||
newmode.c_lflag |= ECHO | ISIG | ICANON;
|
||||
tcsetattr(0, TCSANOW, &newmode);
|
||||
line[0] = '\0';
|
||||
if (block_and_read(0, line, sizeof(line) - 1) <= 0)
|
||||
/* handled below */;
|
||||
tcsetattr(0, TCSANOW, &oldmode);
|
||||
}
|
||||
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
postmsg(&cf);
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr, abandoned);
|
||||
postmsg(&cf);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask whether to wipe a session log file before writing to it.
|
||||
* Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
|
||||
|
@ -197,6 +197,53 @@ int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
}
|
||||
}
|
||||
|
||||
int askhk(void *frontend, const char *algname, const char *betteralgs,
|
||||
void (*callback)(void *ctx, int result), void *ctx)
|
||||
{
|
||||
HANDLE hin;
|
||||
DWORD savemode, i;
|
||||
|
||||
static const char msg[] =
|
||||
"The first host key type we have stored for this server\n"
|
||||
"is %s, which is below the configured warning threshold.\n"
|
||||
"The server also provides the following types of host key\n"
|
||||
"above the threshold, which we do not have stored:\n"
|
||||
"%s\n"
|
||||
"Continue with connection? (y/n) ";
|
||||
static const char msg_batch[] =
|
||||
"The first host key type we have stored for this server\n"
|
||||
"is %s, which is below the configured warning threshold.\n"
|
||||
"The server also provides the following types of host key\n"
|
||||
"above the threshold, which we do not have stored:\n"
|
||||
"%s\n"
|
||||
"Connection abandoned.\n";
|
||||
static const char abandoned[] = "Connection abandoned.\n";
|
||||
|
||||
char line[32];
|
||||
|
||||
if (console_batch_mode) {
|
||||
fprintf(stderr, msg_batch, algname, betteralgs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, msg, algname, betteralgs);
|
||||
fflush(stderr);
|
||||
|
||||
hin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
GetConsoleMode(hin, &savemode);
|
||||
SetConsoleMode(hin, (savemode | ENABLE_ECHO_INPUT |
|
||||
ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT));
|
||||
ReadFile(hin, line, sizeof(line) - 1, &i, NULL);
|
||||
SetConsoleMode(hin, savemode);
|
||||
|
||||
if (line[0] == 'y' || line[0] == 'Y') {
|
||||
return 1;
|
||||
} else {
|
||||
fprintf(stderr, abandoned);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask whether to wipe a session log file before writing to it.
|
||||
* Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
|
||||
|
@ -895,6 +895,33 @@ int askalg(void *frontend, const char *algtype, const char *algname,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int askhk(void *frontend, const char *algname, const char *betteralgs,
|
||||
void (*callback)(void *ctx, int result), void *ctx)
|
||||
{
|
||||
static const char mbtitle[] = "%s Security Alert";
|
||||
static const char msg[] =
|
||||
"The first host key type we have stored for this server\n"
|
||||
"is %s, which is below the configured warning threshold.\n"
|
||||
"The server also provides the following types of host key\n"
|
||||
"above the threshold, which we do not have stored:\n"
|
||||
"%s\n"
|
||||
"Do you want to continue with this connection?\n";
|
||||
char *message, *title;
|
||||
int mbret;
|
||||
|
||||
message = dupprintf(msg, algname, betteralgs);
|
||||
title = dupprintf(mbtitle, appname);
|
||||
mbret = MessageBox(NULL, message, title,
|
||||
MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
|
||||
socket_reselect_all();
|
||||
sfree(message);
|
||||
sfree(title);
|
||||
if (mbret == IDYES)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ask whether to wipe a session log file before writing to it.
|
||||
* Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
|
||||
|
Loading…
Reference in New Issue
Block a user