diff --git a/pscp.c b/pscp.c index 4e5d7cbf..0b091085 100644 --- a/pscp.c +++ b/pscp.c @@ -75,7 +75,7 @@ static const SeatVtable pscp_seat_vt = { .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = console_verify_ssh_host_key, + .confirm_ssh_host_key = console_confirm_ssh_host_key, .confirm_weak_crypto_primitive = console_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = console_confirm_weak_cached_hostkey, .is_utf8 = nullseat_is_never_utf8, diff --git a/psftp.c b/psftp.c index 4dc60dc1..e00ebed1 100644 --- a/psftp.c +++ b/psftp.c @@ -56,7 +56,7 @@ static const SeatVtable psftp_seat_vt = { .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = console_verify_ssh_host_key, + .confirm_ssh_host_key = console_confirm_ssh_host_key, .confirm_weak_crypto_primitive = console_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = console_confirm_weak_cached_hostkey, .is_utf8 = nullseat_is_never_utf8, diff --git a/psocks.c b/psocks.c index 50bdf714..f3c8efa0 100644 --- a/psocks.c +++ b/psocks.c @@ -523,8 +523,8 @@ void psocks_start(psocks_state *ps) * Some stubs that are needed to link against PuTTY modules. */ -int verify_host_key(const char *hostname, int port, - const char *keytype, const char *key) +int check_stored_host_key(const char *hostname, int port, + const char *keytype, const char *key) { unreachable("host keys not handled in this tool"); } diff --git a/putty.h b/putty.h index 82ee83a8..1d55f91e 100644 --- a/putty.h +++ b/putty.h @@ -1081,31 +1081,43 @@ struct SeatVtable { /* * Ask the seat whether a given SSH host key should be accepted. - * This may return immediately after checking saved configuration - * or command-line options, or it may have to present a prompt to - * the user and return asynchronously later. + * This is called after we've already checked it by any means we + * can do ourselves, such as checking against host key + * fingerprints in the Conf or the host key cache on disk: once we + * call this function, we've already decided there's nothing for + * it but to prompt the user. + * + * 'mismatch' reports the result of checking the host key cache: + * it is true if the server has presented a host key different + * from the one we expected, and false if we had no expectation in + * the first place. + * + * This call may prompt the user synchronously and not return + * until the answer is available, or it may present the prompt and + * return immediately, giving the answer later via the provided + * callback. * * Return values: * - * - +1 means `key was OK' (either already known or the user just - * approved it) `so continue with the connection' + * - +1 means `user approved the key, so continue with the + * connection' * - * - 0 means `key was not OK, abandon the connection' + * - 0 means `user rejected the key, abandon the connection' * * - -1 means `I've initiated enquiries, please wait to be called * back via the provided function with a result that's either 0 * or +1'. */ - int (*verify_ssh_host_key)( + int (*confirm_ssh_host_key)( Seat *seat, const char *host, int port, const char *keytype, char *keystr, const char *keydisp, char **key_fingerprints, - void (*callback)(void *ctx, int result), void *ctx); + bool mismatch, void (*callback)(void *ctx, int result), void *ctx); /* * Check with the seat whether it's OK to use a cryptographic * primitive from below the 'warn below this line' threshold in * the input Conf. Return values are the same as - * verify_ssh_host_key above. + * confirm_ssh_host_key above. */ int (*confirm_weak_crypto_primitive)( Seat *seat, const char *algtype, const char *algname, @@ -1229,11 +1241,12 @@ static inline char *seat_get_ttymode(Seat *seat, const char *mode) { return seat->vt->get_ttymode(seat, mode); } static inline void seat_set_busy_status(Seat *seat, BusyStatus status) { seat->vt->set_busy_status(seat, status); } -static inline int seat_verify_ssh_host_key( +static inline int seat_confirm_ssh_host_key( Seat *seat, const char *h, int p, const char *ktyp, char *kstr, - const char *kdsp, char **fps, void (*cb)(void *ctx, int result), void *ctx) -{ return seat->vt->verify_ssh_host_key(seat, h, p, ktyp, kstr, kdsp, fps, - cb, ctx); } + const char *kdsp, char **fps, bool mis, + void (*cb)(void *ctx, int result), void *ctx) +{ return seat->vt->confirm_ssh_host_key(seat, h, p, ktyp, kstr, kdsp, fps, + mis, cb, ctx); } static inline int seat_confirm_weak_crypto_primitive( Seat *seat, const char *atyp, const char *aname, void (*cb)(void *ctx, int result), void *ctx) @@ -1308,9 +1321,9 @@ void nullseat_connection_fatal(Seat *seat, const char *message); void nullseat_update_specials_menu(Seat *seat); char *nullseat_get_ttymode(Seat *seat, const char *mode); void nullseat_set_busy_status(Seat *seat, BusyStatus status); -int nullseat_verify_ssh_host_key( +int nullseat_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **key_fingerprints, + char *keystr, const char *keydisp, char **key_fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx); int nullseat_confirm_weak_crypto_primitive( Seat *seat, const char *algtype, const char *algname, @@ -1341,9 +1354,9 @@ bool nullseat_get_cursor_position(Seat *seat, int *x, int *y); */ void console_connection_fatal(Seat *seat, const char *message); -int console_verify_ssh_host_key( +int console_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **key_fingerprints, + char *keystr, const char *keydisp, char **key_fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx); int console_confirm_weak_crypto_primitive( Seat *seat, const char *algtype, const char *algname, diff --git a/ssh.h b/ssh.h index d4729d5f..e633da20 100644 --- a/ssh.h +++ b/ssh.h @@ -1707,7 +1707,10 @@ unsigned alloc_channel_id_general(tree234 *channels, size_t localid_offset); void add_to_commasep(strbuf *buf, const char *data); bool get_commasep_word(ptrlen *list, ptrlen *word); -int verify_ssh_manual_host_key(Conf *conf, char **fingerprints, ssh_key *key); +int verify_ssh_host_key( + Seat *seat, Conf *conf, const char *host, int port, ssh_key *key, + const char *keytype, char *keystr, const char *keydisp, + char **fingerprints, void (*callback)(void *ctx, int result), void *ctx); typedef struct ssh_transient_hostkey_cache ssh_transient_hostkey_cache; ssh_transient_hostkey_cache *ssh_transient_hostkey_cache_new(void); diff --git a/ssh/common.c b/ssh/common.c index c67a2dfb..ee09910a 100644 --- a/ssh/common.c +++ b/ssh/common.c @@ -9,6 +9,7 @@ #include "putty.h" #include "mpint.h" #include "ssh.h" +#include "storage.h" #include "bpp.h" #include "ppl.h" #include "channel.h" @@ -837,58 +838,93 @@ bool ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) #undef SSH1_BITMAP_WORD /* ---------------------------------------------------------------------- - * Function to check a host key against any manually configured in Conf. + * Centralised component of SSH host key verification. + * + * verify_ssh_host_key is called from both the SSH-1 and SSH-2 + * transport layers, and does the initial work of checking whether the + * host key is already known. If so, it returns success on its own + * account; otherwise, it calls out to the Seat to give an interactive + * prompt (the nature of which varies depending on the Seat itself). + * + * Return values are 0 for 'abort connection', 1 for 'ok, carry on', + * and negative for 'answer not received yet, wait for a callback'. */ -int verify_ssh_manual_host_key(Conf *conf, char **fingerprints, ssh_key *key) +int verify_ssh_host_key( + Seat *seat, Conf *conf, const char *host, int port, ssh_key *key, + const char *keytype, char *keystr, const char *keydisp, + char **fingerprints, void (*callback)(void *ctx, int result), void *ctx) { - if (!conf_get_str_nthstrkey(conf, CONF_ssh_manual_hostkeys, 0)) - return -1; /* no manual keys configured */ + /* + * First, check if the Conf includes a manual specification of the + * expected host key. If so, that completely supersedes everything + * else, including the normal host key cache _and_ including + * manual overrides: we return success or failure immediately, + * entirely based on whether the key matches the Conf. + */ + if (conf_get_str_nthstrkey(conf, CONF_ssh_manual_hostkeys, 0)) { + if (fingerprints) { + for (size_t i = 0; i < SSH_N_FPTYPES; i++) { + /* + * Each fingerprint string we've been given will have + * things like 'ssh-rsa 2048' at the front of it. Strip + * those off and narrow down to just the hash at the end + * of the string. + */ + const char *fingerprint = fingerprints[i]; + if (!fingerprint) + continue; + const char *p = strrchr(fingerprint, ' '); + fingerprint = p ? p+1 : fingerprint; + if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys, + fingerprint)) + return 1; /* success */ + } + } - if (fingerprints) { - for (size_t i = 0; i < SSH_N_FPTYPES; i++) { + if (key) { /* - * Each fingerprint string we've been given will have - * things like 'ssh-rsa 2048' at the front of it. Strip - * those off and narrow down to just the hash at the end - * of the string. + * Construct the base64-encoded public key blob and see if + * that's listed. */ - const char *fingerprint = fingerprints[i]; - if (!fingerprint) - continue; - const char *p = strrchr(fingerprint, ' '); - fingerprint = p ? p+1 : fingerprint; + strbuf *binblob; + char *base64blob; + int atoms, i; + binblob = strbuf_new(); + ssh_key_public_blob(key, BinarySink_UPCAST(binblob)); + atoms = (binblob->len + 2) / 3; + base64blob = snewn(atoms * 4 + 1, char); + for (i = 0; i < atoms; i++) + base64_encode_atom(binblob->u + 3*i, + binblob->len - 3*i, base64blob + 4*i); + base64blob[atoms * 4] = '\0'; + strbuf_free(binblob); if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys, - fingerprint)) + base64blob)) { + sfree(base64blob); return 1; /* success */ - } - } - - if (key) { - /* - * Construct the base64-encoded public key blob and see if - * that's listed. - */ - strbuf *binblob; - char *base64blob; - int atoms, i; - binblob = strbuf_new(); - ssh_key_public_blob(key, BinarySink_UPCAST(binblob)); - atoms = (binblob->len + 2) / 3; - base64blob = snewn(atoms * 4 + 1, char); - for (i = 0; i < atoms; i++) - base64_encode_atom(binblob->u + 3*i, - binblob->len - 3*i, base64blob + 4*i); - base64blob[atoms * 4] = '\0'; - strbuf_free(binblob); - if (conf_get_str_str_opt(conf, CONF_ssh_manual_hostkeys, base64blob)) { + } sfree(base64blob); - return 1; /* success */ } - sfree(base64blob); + + return 0; } - return 0; + /* + * Next, check the host key cache. + */ + int storage_status = check_stored_host_key(host, port, keytype, keystr); + if (storage_status == 0) /* matching key was found in the cache */ + return 1; /* success */ + + /* + * The key is either missing from the cache, or does not match. + * Either way, fall back to an interactive prompt from the Seat. + */ + bool mismatch = (storage_status != 1); + return seat_confirm_ssh_host_key( + seat, host, port, keytype, keystr, keydisp, fingerprints, mismatch, + callback, ctx); } /* ---------------------------------------------------------------------- diff --git a/ssh/kex2-client.c b/ssh/kex2-client.c index 4bbd8765..2435534c 100644 --- a/ssh/kex2-client.c +++ b/ssh/kex2-client.c @@ -843,39 +843,33 @@ void ssh2kex_coroutine(struct ssh2_transport_state *s, bool *aborted) * Authenticate remote host: verify host key. (We've already * checked the signature of the exchange hash.) */ - char **fingerprints = ssh2_all_fingerprints(s->hkey); - FingerprintType fptype_default = - ssh2_pick_default_fingerprint(fingerprints); - ppl_logevent("Host key fingerprint is:"); - ppl_logevent("%s", fingerprints[fptype_default]); - /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key( - s->conf, fingerprints, s->hkey); - if (s->dlgret == 0) { /* did not match */ - ssh2_free_all_fingerprints(fingerprints); - ssh_sw_abort(s->ppl.ssh, "Host key did not appear in manually " - "configured list"); - *aborted = true; - return; - } else if (s->dlgret < 0) { /* none configured; use standard handling */ + { ssh2_userkey uk = { .key = s->hkey, .comment = NULL }; char *keydisp = ssh2_pubkey_openssh_str(&uk); - s->dlgret = seat_verify_ssh_host_key( - s->ppl.seat, s->savedhost, s->savedport, + char **fingerprints = ssh2_all_fingerprints(s->hkey); + + FingerprintType fptype_default = + ssh2_pick_default_fingerprint(fingerprints); + ppl_logevent("Host key fingerprint is:"); + ppl_logevent("%s", fingerprints[fptype_default]); + + s->dlgret = verify_ssh_host_key( + s->ppl.seat, s->conf, s->savedhost, s->savedport, s->hkey, ssh_key_cache_id(s->hkey), s->keystr, keydisp, fingerprints, ssh2_transport_dialog_callback, s); - sfree(keydisp); + ssh2_free_all_fingerprints(fingerprints); + sfree(keydisp); + } #ifdef FUZZING - s->dlgret = 1; + s->dlgret = 1; #endif - crMaybeWaitUntilV(s->dlgret >= 0); - if (s->dlgret == 0) { - ssh_user_close(s->ppl.ssh, - "User aborted at host key verification"); - *aborted = true; - return; - } + crMaybeWaitUntilV(s->dlgret >= 0); + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, + "User aborted at host key verification"); + *aborted = true; + return; } /* diff --git a/ssh/login1.c b/ssh/login1.c index 1e2d7d3e..001b3d8e 100644 --- a/ssh/login1.c +++ b/ssh/login1.c @@ -238,42 +238,29 @@ static void ssh1_login_process_queue(PacketProtocolLayer *ppl) * Verify the host key. */ { - /* - * First format the key into a string. - */ char *keystr = rsastr_fmt(&s->hostkey); + char *keydisp = ssh1_pubkey_str(&s->hostkey); char **fingerprints = rsa_ssh1_fake_all_fingerprints(&s->hostkey); - /* First check against manually configured host keys. */ - s->dlgret = verify_ssh_manual_host_key(s->conf, fingerprints, NULL); - if (s->dlgret == 0) { /* did not match */ - ssh2_free_all_fingerprints(fingerprints); - sfree(keystr); - ssh_proto_error(s->ppl.ssh, "Host key did not appear in manually " - "configured list"); - return; - } else if (s->dlgret < 0) { /* none configured; use standard handling */ - char *keydisp = ssh1_pubkey_str(&s->hostkey); - s->dlgret = seat_verify_ssh_host_key( - s->ppl.seat, s->savedhost, s->savedport, "rsa", keystr, - keydisp, fingerprints, ssh1_login_dialog_callback, s); - sfree(keydisp); - ssh2_free_all_fingerprints(fingerprints); - sfree(keystr); -#ifdef FUZZING - s->dlgret = 1; -#endif - crMaybeWaitUntilV(s->dlgret >= 0); + s->dlgret = verify_ssh_host_key( + s->ppl.seat, s->conf, s->savedhost, s->savedport, NULL, + "rsa", keystr, keydisp, fingerprints, + ssh1_login_dialog_callback, s); - if (s->dlgret == 0) { - ssh_user_close(s->ppl.ssh, - "User aborted at host key verification"); - return; - } - } else { - ssh2_free_all_fingerprints(fingerprints); - sfree(keystr); - } + ssh2_free_all_fingerprints(fingerprints); + sfree(keydisp); + sfree(keystr); + } + +#ifdef FUZZING + s->dlgret = 1; +#endif + crMaybeWaitUntilV(s->dlgret >= 0); + + if (s->dlgret == 0) { + ssh_user_close(s->ppl.ssh, + "User aborted at host key verification"); + return; } for (i = 0; i < 32; i++) { diff --git a/ssh/server.c b/ssh/server.c index 404ba77d..63a68f62 100644 --- a/ssh/server.c +++ b/ssh/server.c @@ -116,7 +116,7 @@ static const SeatVtable server_seat_vt = { .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = nullseat_verify_ssh_host_key, + .confirm_ssh_host_key = nullseat_confirm_ssh_host_key, .confirm_weak_crypto_primitive = server_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = server_confirm_weak_cached_hostkey, .is_utf8 = nullseat_is_never_utf8, diff --git a/ssh/sesschan.c b/ssh/sesschan.c index ff4a008f..6951edc4 100644 --- a/ssh/sesschan.c +++ b/ssh/sesschan.c @@ -195,7 +195,7 @@ static const SeatVtable sesschan_seat_vt = { .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = nullseat_verify_ssh_host_key, + .confirm_ssh_host_key = nullseat_confirm_ssh_host_key, .confirm_weak_crypto_primitive = nullseat_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = nullseat_confirm_weak_cached_hostkey, .is_utf8 = nullseat_is_never_utf8, diff --git a/sshproxy.c b/sshproxy.c index 31657645..ad274d57 100644 --- a/sshproxy.c +++ b/sshproxy.c @@ -338,10 +338,10 @@ static void sshproxy_connection_fatal(Seat *seat, const char *message) } } -static int sshproxy_verify_ssh_host_key( - Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **key_fingerprints, - void (*callback)(void *ctx, int result), void *ctx) +static int sshproxy_confirm_ssh_host_key( + Seat *seat, const char *host, int port, const char *keytype, + char *keystr, const char *keydisp, char **key_fingerprints, bool mismatch, + void (*callback)(void *ctx, int result), void *ctx) { SshProxy *sp = container_of(seat, SshProxy, seat); @@ -350,39 +350,17 @@ static int sshproxy_verify_ssh_host_key( * If we have access to the outer Seat, pass this prompt * request on to it. FIXME: appropriately adjusted */ - return seat_verify_ssh_host_key( + return seat_confirm_ssh_host_key( sp->clientseat, host, port, keytype, keystr, keydisp, - key_fingerprints, callback, ctx); + key_fingerprints, mismatch, callback, ctx); } /* - * Otherwise, behave as if we're in batch mode: directly verify - * the host key against the cache, and if that fails, take the - * safe option in the absence of interactive confirmation, and - * abort the connection. + * Otherwise, behave as if we're in batch mode, i.e. take the safe + * option in the absence of interactive confirmation, i.e. abort + * the connection. */ - int hkstatus = verify_host_key(host, port, keytype, keystr); - FingerprintType fptype = ssh2_pick_default_fingerprint(key_fingerprints); - - switch (hkstatus) { - case 0: /* host key matched */ - return 1; - - case 1: /* host key not in cache at all */ - sshproxy_error(sp, "Host key not in cache for %s:%d (fingerprint %s). " - "Abandoning proxy SSH connection.", host, port, - key_fingerprints[fptype]); - return 0; - - case 2: - sshproxy_error(sp, "HOST KEY DOES NOT MATCH CACHE for %s:%d " - "(fingerprint %s). Abandoning proxy SSH connection.", - host, port, key_fingerprints[fptype]); - return 0; - - default: - unreachable("bad return value from verify_host_key"); - } + return 0; } static int sshproxy_confirm_weak_crypto_primitive( @@ -482,7 +460,7 @@ static const SeatVtable SshProxy_seat_vt = { .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = sshproxy_verify_ssh_host_key, + .confirm_ssh_host_key = sshproxy_confirm_ssh_host_key, .confirm_weak_crypto_primitive = sshproxy_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = sshproxy_confirm_weak_cached_hostkey, .is_utf8 = nullseat_is_never_utf8, diff --git a/storage.h b/storage.h index 6464b69d..3e03181a 100644 --- a/storage.h +++ b/storage.h @@ -81,8 +81,8 @@ void enum_settings_finish(settings_e *handle); * be 0 (entry matches database), 1 (entry is absent in database), * or 2 (entry exists in database and is different). */ -int verify_host_key(const char *hostname, int port, - const char *keytype, const char *key); +int check_stored_host_key(const char *hostname, int port, + const char *keytype, const char *key); /* * Write a host key into the database, overwriting any previous diff --git a/unix/console.c b/unix/console.c index 8a7cd8f9..da795614 100644 --- a/unix/console.c +++ b/unix/console.c @@ -102,30 +102,20 @@ static int block_and_read(int fd, void *buf, size_t len) return ret; } -int console_verify_ssh_host_key( +int console_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **fingerprints, + char *keystr, const char *keydisp, char **fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx) { - int ret; - char line[32]; struct termios cf; char *common; const char *intro, *prompt; - /* - * Verify the key. - */ - ret = verify_host_key(host, port, keytype, keystr); - - if (ret == 0) /* success - key matched OK */ - return 1; - FingerprintType fptype_default = ssh2_pick_default_fingerprint(fingerprints); - if (ret == 2) { /* key was different */ + if (mismatch) { /* key was different */ common = hk_wrongmsg_common(host, port, keytype, fingerprints[fptype_default]); intro = hk_wrongmsg_interactive_intro; diff --git a/unix/dialog.c b/unix/dialog.c index 42cff97f..743be31d 100644 --- a/unix/dialog.c +++ b/unix/dialog.c @@ -3448,7 +3448,7 @@ GtkWidget *create_message_box( NULL /* action_postproc */, NULL /* postproc_ctx */); } -struct verify_ssh_host_key_dialog_ctx { +struct confirm_ssh_host_key_dialog_ctx { char *host; int port; char *keytype; @@ -3462,10 +3462,10 @@ struct verify_ssh_host_key_dialog_ctx { GtkWidget *more_info_dialog; }; -static void verify_ssh_host_key_result_callback(void *vctx, int result) +static void confirm_ssh_host_key_result_callback(void *vctx, int result) { - struct verify_ssh_host_key_dialog_ctx *ctx = - (struct verify_ssh_host_key_dialog_ctx *)vctx; + struct confirm_ssh_host_key_dialog_ctx *ctx = + (struct confirm_ssh_host_key_dialog_ctx *)vctx; if (result >= 0) { int logical_result; @@ -3518,16 +3518,16 @@ static GtkWidget *add_more_info_button(GtkWidget *w, void *vctx) static void more_info_closed(void *vctx, int result) { - struct verify_ssh_host_key_dialog_ctx *ctx = - (struct verify_ssh_host_key_dialog_ctx *)vctx; + struct confirm_ssh_host_key_dialog_ctx *ctx = + (struct confirm_ssh_host_key_dialog_ctx *)vctx; ctx->more_info_dialog = NULL; } static void more_info_button_clicked(GtkButton *button, gpointer vctx) { - struct verify_ssh_host_key_dialog_ctx *ctx = - (struct verify_ssh_host_key_dialog_ctx *)vctx; + struct confirm_ssh_host_key_dialog_ctx *ctx = + (struct confirm_ssh_host_key_dialog_ctx *)vctx; if (ctx->more_info_dialog) return; @@ -3539,9 +3539,9 @@ static void more_info_button_clicked(GtkButton *button, gpointer vctx) &buttons_ok, more_info_closed, ctx); } -int gtk_seat_verify_ssh_host_key( +int gtk_seat_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **fingerprints, + char *keystr, const char *keydisp, char **fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx) { static const char absenttxt[] = @@ -3584,25 +3584,16 @@ int gtk_seat_verify_ssh_host_key( }; char *text; - int ret; - struct verify_ssh_host_key_dialog_ctx *result_ctx; + struct confirm_ssh_host_key_dialog_ctx *result_ctx; GtkWidget *mainwin, *msgbox; - /* - * Verify the key. - */ - ret = verify_host_key(host, port, keytype, keystr); - - if (ret == 0) /* success - key matched OK */ - return 1; - FingerprintType fptype_default = ssh2_pick_default_fingerprint(fingerprints); - text = dupprintf((ret == 2 ? wrongtxt : absenttxt), host, port, + text = dupprintf((mismatch ? wrongtxt : absenttxt), host, port, keytype, fingerprints[fptype_default]); - result_ctx = snew(struct verify_ssh_host_key_dialog_ctx); + result_ctx = snew(struct confirm_ssh_host_key_dialog_ctx); result_ctx->callback = callback; result_ctx->callback_ctx = ctx; result_ctx->host = dupstr(host); @@ -3616,7 +3607,7 @@ int gtk_seat_verify_ssh_host_key( msgbox = create_message_box_general( mainwin, "PuTTY Security Alert", text, string_width(fingerprints[fptype_default]), true, - &buttons_hostkey, verify_ssh_host_key_result_callback, result_ctx, + &buttons_hostkey, confirm_ssh_host_key_result_callback, result_ctx, add_more_info_button, &more_info_button); result_ctx->main_dialog = msgbox; diff --git a/unix/platform.h b/unix/platform.h index 97762f3f..b4f5a008 100644 --- a/unix/platform.h +++ b/unix/platform.h @@ -217,9 +217,9 @@ void showeventlog(eventlog_stuff *estuff, void *parentwin); void logevent_dlg(eventlog_stuff *estuff, const char *string); int gtkdlg_askappend(Seat *seat, Filename *filename, void (*callback)(void *ctx, int result), void *ctx); -int gtk_seat_verify_ssh_host_key( +int gtk_seat_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **fingerprints, + char *keystr, const char *keydisp, char **fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx); int gtk_seat_confirm_weak_crypto_primitive( Seat *seat, const char *algtype, const char *algname, diff --git a/unix/plink.c b/unix/plink.c index 643fc563..524e4545 100644 --- a/unix/plink.c +++ b/unix/plink.c @@ -399,7 +399,7 @@ static const SeatVtable plink_seat_vt = { .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = plink_get_ttymode, .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = console_verify_ssh_host_key, + .confirm_ssh_host_key = console_confirm_ssh_host_key, .confirm_weak_crypto_primitive = console_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = console_confirm_weak_cached_hostkey, .is_utf8 = nullseat_is_never_utf8, diff --git a/unix/storage.c b/unix/storage.c index 9db713d1..16bb63e0 100644 --- a/unix/storage.c +++ b/unix/storage.c @@ -595,8 +595,8 @@ void enum_settings_finish(settings_e *handle) * * rsa@22:foovax.example.org 0x23,0x293487364395345345....2343 */ -int verify_host_key(const char *hostname, int port, - const char *keytype, const char *key) +int check_stored_host_key(const char *hostname, int port, + const char *keytype, const char *key) { FILE *fp; char *filename; @@ -668,10 +668,10 @@ bool have_ssh_host_key(const char *hostname, int port, const char *keytype) { /* - * If we have a host key, verify_host_key will return 0 or 2. + * If we have a host key, check_stored_host_key will return 0 or 2. * If we don't have one, it'll return 1. */ - return verify_host_key(hostname, port, keytype, "") != 1; + return check_stored_host_key(hostname, port, keytype, "") != 1; } void store_host_key(const char *hostname, int port, diff --git a/unix/window.c b/unix/window.c index 8740bc50..c3ddb515 100644 --- a/unix/window.c +++ b/unix/window.c @@ -398,7 +398,7 @@ static const SeatVtable gtk_seat_vt = { .update_specials_menu = gtk_seat_update_specials_menu, .get_ttymode = gtk_seat_get_ttymode, .set_busy_status = gtk_seat_set_busy_status, - .verify_ssh_host_key = gtk_seat_verify_ssh_host_key, + .confirm_ssh_host_key = gtk_seat_confirm_ssh_host_key, .confirm_weak_crypto_primitive = gtk_seat_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = gtk_seat_confirm_weak_cached_hostkey, .is_utf8 = gtk_seat_is_utf8, diff --git a/utils/nullseat.c b/utils/nullseat.c index 43c478e0..19fad59d 100644 --- a/utils/nullseat.c +++ b/utils/nullseat.c @@ -16,9 +16,9 @@ void nullseat_connection_fatal(Seat *seat, const char *message) {} void nullseat_update_specials_menu(Seat *seat) {} char *nullseat_get_ttymode(Seat *seat, const char *mode) { return NULL; } void nullseat_set_busy_status(Seat *seat, BusyStatus status) {} -int nullseat_verify_ssh_host_key( +int nullseat_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **key_fingerprints, + char *keystr, const char *keydisp, char **key_fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx) { return 0; } int nullseat_confirm_weak_crypto_primitive( Seat *seat, const char *algtype, const char *algname, diff --git a/utils/tempseat.c b/utils/tempseat.c index 0046fe0d..f877dd1d 100644 --- a/utils/tempseat.c +++ b/utils/tempseat.c @@ -224,12 +224,12 @@ static int tempseat_get_userpass_input(Seat *seat, prompts_t *p) unreachable("get_userpass_input should never be called on TempSeat"); } -static int tempseat_verify_ssh_host_key( +static int tempseat_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **key_fingerprints, + char *keystr, const char *keydisp, char **key_fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx) { - unreachable("verify_ssh_host_key should never be called on TempSeat"); + unreachable("confirm_ssh_host_key should never be called on TempSeat"); } static int tempseat_confirm_weak_crypto_primitive( @@ -307,7 +307,7 @@ static const struct SeatVtable tempseat_vt = { .update_specials_menu = tempseat_update_specials_menu, .get_ttymode = tempseat_get_ttymode, .set_busy_status = tempseat_set_busy_status, - .verify_ssh_host_key = tempseat_verify_ssh_host_key, + .confirm_ssh_host_key = tempseat_confirm_ssh_host_key, .confirm_weak_crypto_primitive = tempseat_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = tempseat_confirm_weak_cached_hostkey, .is_utf8 = tempseat_is_utf8, diff --git a/windows/console.c b/windows/console.c index 75d55916..abd31270 100644 --- a/windows/console.c +++ b/windows/console.c @@ -32,12 +32,11 @@ void console_print_error_msg(const char *prefix, const char *msg) fflush(stderr); } -int console_verify_ssh_host_key( +int console_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **fingerprints, + char *keystr, const char *keydisp, char **fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx) { - int ret; HANDLE hin; DWORD savemode, i; char *common; @@ -45,18 +44,10 @@ int console_verify_ssh_host_key( char line[32]; - /* - * Verify the key against the registry. - */ - ret = verify_host_key(host, port, keytype, keystr); - - if (ret == 0) /* success - key matched OK */ - return 1; - FingerprintType fptype_default = ssh2_pick_default_fingerprint(fingerprints); - if (ret == 2) { /* key was different */ + if (mismatch) { /* key was different */ common = hk_wrongmsg_common(host, port, keytype, fingerprints[fptype_default]); intro = hk_wrongmsg_interactive_intro; diff --git a/windows/dialog.c b/windows/dialog.c index 4778528b..a5af31ed 100644 --- a/windows/dialog.c +++ b/windows/dialog.c @@ -976,52 +976,43 @@ static INT_PTR CALLBACK HostKeyDialogProc(HWND hwnd, UINT msg, return 0; } -int win_seat_verify_ssh_host_key( +int win_seat_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **fingerprints, - void (*callback)(void *ctx, int result), void *ctx) + char *keystr, const char *keydisp, char **fingerprints, bool mismatch, + void (*callback)(void *ctx, int result), void *vctx) { - int ret; - WinGuiSeat *wgs = container_of(seat, WinGuiSeat, seat); - /* - * Verify the key against the registry. - */ - ret = verify_host_key(host, port, keytype, keystr); + static const char *const keywords[] = + { "{KEYTYPE}", "{APPNAME}", NULL }; - if (ret == 0) /* success - key matched OK */ + const char *values[2]; + values[0] = keytype; + values[1] = appname; + + struct hostkey_dialog_ctx ctx[1]; + ctx->keywords = keywords; + ctx->values = values; + ctx->fingerprints = fingerprints; + ctx->fptype_default = ssh2_pick_default_fingerprint(fingerprints); + ctx->keydisp = keydisp; + ctx->iconid = (mismatch ? IDI_WARNING : IDI_QUESTION); + ctx->helpctx = (mismatch ? WINHELP_CTX_errors_hostkey_changed : + WINHELP_CTX_errors_hostkey_absent); + ctx->host = host; + ctx->port = port; + int dlgid = (mismatch ? IDD_HK_WRONG : IDD_HK_ABSENT); + int mbret = DialogBoxParam( + hinst, MAKEINTRESOURCE(dlgid), wgs->term_hwnd, + HostKeyDialogProc, (LPARAM)ctx); + assert(mbret==IDC_HK_ACCEPT || mbret==IDC_HK_ONCE || mbret==IDCANCEL); + if (mbret == IDC_HK_ACCEPT) { + store_host_key(host, port, keytype, keystr); + return 1; + } else if (mbret == IDC_HK_ONCE) { return 1; - else { - static const char *const keywords[] = - { "{KEYTYPE}", "{APPNAME}", NULL }; - - const char *values[2]; - values[0] = keytype; - values[1] = appname; - - struct hostkey_dialog_ctx ctx[1]; - ctx->keywords = keywords; - ctx->values = values; - ctx->fingerprints = fingerprints; - ctx->fptype_default = ssh2_pick_default_fingerprint(fingerprints); - ctx->keydisp = keydisp; - ctx->iconid = (ret == 2 ? IDI_WARNING : IDI_QUESTION); - ctx->helpctx = (ret == 2 ? WINHELP_CTX_errors_hostkey_changed : - WINHELP_CTX_errors_hostkey_absent); - ctx->host = host; - ctx->port = port; - int dlgid = (ret == 2 ? IDD_HK_WRONG : IDD_HK_ABSENT); - int mbret = DialogBoxParam( - hinst, MAKEINTRESOURCE(dlgid), wgs->term_hwnd, - HostKeyDialogProc, (LPARAM)ctx); - assert(mbret==IDC_HK_ACCEPT || mbret==IDC_HK_ONCE || mbret==IDCANCEL); - if (mbret == IDC_HK_ACCEPT) { - store_host_key(host, port, keytype, keystr); - return 1; - } else if (mbret == IDC_HK_ONCE) - return 1; } + return 0; /* abandon the connection */ } diff --git a/windows/platform.h b/windows/platform.h index 65dacdc1..cf76566b 100644 --- a/windows/platform.h +++ b/windows/platform.h @@ -220,9 +220,9 @@ int has_embedded_chm(void); /* 1 = yes, 0 = no, -1 = N/A */ * GUI seat methods in windlg.c, so that the vtable definition in * window.c can refer to them. */ -int win_seat_verify_ssh_host_key( +int win_seat_confirm_ssh_host_key( Seat *seat, const char *host, int port, const char *keytype, - char *keystr, const char *keydisp, char **key_fingerprints, + char *keystr, const char *keydisp, char **key_fingerprints, bool mismatch, void (*callback)(void *ctx, int result), void *ctx); int win_seat_confirm_weak_crypto_primitive( Seat *seat, const char *algtype, const char *algname, diff --git a/windows/plink.c b/windows/plink.c index b49266d3..7506a13f 100644 --- a/windows/plink.c +++ b/windows/plink.c @@ -93,7 +93,7 @@ static const SeatVtable plink_seat_vt = { .update_specials_menu = nullseat_update_specials_menu, .get_ttymode = nullseat_get_ttymode, .set_busy_status = nullseat_set_busy_status, - .verify_ssh_host_key = console_verify_ssh_host_key, + .confirm_ssh_host_key = console_confirm_ssh_host_key, .confirm_weak_crypto_primitive = console_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = console_confirm_weak_cached_hostkey, .is_utf8 = nullseat_is_never_utf8, diff --git a/windows/storage.c b/windows/storage.c index 09e5c028..2bb08953 100644 --- a/windows/storage.c +++ b/windows/storage.c @@ -322,8 +322,8 @@ static void hostkey_regname(strbuf *sb, const char *hostname, escape_registry_key(hostname, sb); } -int verify_host_key(const char *hostname, int port, - const char *keytype, const char *key) +int check_stored_host_key(const char *hostname, int port, + const char *keytype, const char *key) { char *otherstr; strbuf *regname; @@ -437,10 +437,10 @@ bool have_ssh_host_key(const char *hostname, int port, const char *keytype) { /* - * If we have a host key, verify_host_key will return 0 or 2. + * If we have a host key, check_stored_host_key will return 0 or 2. * If we don't have one, it'll return 1. */ - return verify_host_key(hostname, port, keytype, "") != 1; + return check_stored_host_key(hostname, port, keytype, "") != 1; } void store_host_key(const char *hostname, int port, diff --git a/windows/window.c b/windows/window.c index 2f7cb274..4c67009b 100644 --- a/windows/window.c +++ b/windows/window.c @@ -340,7 +340,7 @@ static const SeatVtable win_seat_vt = { .update_specials_menu = win_seat_update_specials_menu, .get_ttymode = win_seat_get_ttymode, .set_busy_status = win_seat_set_busy_status, - .verify_ssh_host_key = win_seat_verify_ssh_host_key, + .confirm_ssh_host_key = win_seat_confirm_ssh_host_key, .confirm_weak_crypto_primitive = win_seat_confirm_weak_crypto_primitive, .confirm_weak_cached_hostkey = win_seat_confirm_weak_cached_hostkey, .is_utf8 = win_seat_is_utf8,