*/
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:
*
}
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;
}
}
+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)
{
/*
}
}
+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).
}
}
+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).
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).