Mailing List Archive

[PATCH] VisualHostKey: unknown
After using VisualHostKey ssh client option for some time, I've found
out that for me it's quite useful for manual host key verification
(where DNS-signed host keys are not available, for example), but it's
too noisy for casual usage when it outputs ASCII art on every login. So,
I've implemented a new value for VisualHostKey option, "unknown", that
only displays ASCII art when prompting for unknown host key, but is
silent for already known ones.

I have tested the patch on the portable repository. I'll happily fix any
issues if you find any problems while finding the contribution a welcome
one, sorry in advance if I've done something wrong. I've tried
submitting the patch to the OpenBSD tech mailing list, but I've a
feeling that it could have gone to spam because of spf/dkim violation
after forwarding. If the patch should be submitted to OpenBSD first and
someone can help me with it, I'd be thankful. I've also submitted it via
GitHub merge request before finding mailing lists.

In case the patch is good as it is now,

Signed-off-by: Dmitry Lapshin <ldvsoft@ldvsoft.net>
---
readconf.c | 11 ++++++++++-
readconf.h | 4 ++++
ssh.1 | 4 +++-
ssh_config.5 | 4 ++++
sshconnect.c | 2 +-
5 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/readconf.c b/readconf.c
index 554efd7..dd2c720 100644
--- a/readconf.c
+++ b/readconf.c
@@ -876,6 +876,14 @@ static const struct multistate
multistate_compression[] = {
{ "no", COMP_NONE },
{ NULL, -1 }
};
+static const struct multistate multistate_visualhostkey[] = {
+ { "true", SSH_VISUAL_HOSTKEY_YES },
+ { "false", SSH_VISUAL_HOSTKEY_NO },
+ { "yes", SSH_VISUAL_HOSTKEY_YES },
+ { "no", SSH_VISUAL_HOSTKEY_NO },
+ { "unknown", SSH_VISUAL_HOSTKEY_UNKNOWN },
+ { NULL, -1 }
+};

static int
parse_multistate_value(const char *arg, const char *filename, int linenum,
@@ -1607,7 +1615,8 @@ parse_keytypes:

case oVisualHostKey:
intptr = &options->visual_host_key;
- goto parse_flag;
+ multistate_ptr = multistate_visualhostkey;
+ goto parse_multistate;

case oInclude:
if (cmdline)
diff --git a/readconf.h b/readconf.h
index d6a1555..06ebd4d 100644
--- a/readconf.h
+++ b/readconf.h
@@ -200,6 +200,10 @@ typedef struct {
#define SSH_STRICT_HOSTKEY_YES 2
#define SSH_STRICT_HOSTKEY_ASK 3

+#define SSH_VISUAL_HOSTKEY_NO 0
+#define SSH_VISUAL_HOSTKEY_YES 1
+#define SSH_VISUAL_HOSTKEY_UNKNOWN 2
+
const char *kex_default_pk_alg(void);
char *ssh_connection_hash(const char *thishost, const char *host,
const char *portstr, const char *user);
diff --git a/ssh.1 b/ssh.1
index 5553178..44ab019 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1240,7 +1240,9 @@ By setting the
option to
.Dq yes ,
a small ASCII graphic gets displayed on every login to a server, no matter
-if the session itself is interactive or not.
+if the session itself is interactive or not. Option value
+.Dq unknown
+will display random art only for unknown keys.
By learning the pattern a known server produces, a user can easily
find out that the host key has changed when a completely different pattern
is displayed.
diff --git a/ssh_config.5 b/ssh_config.5
index 6be1f1a..97f97fa 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1785,6 +1785,10 @@ an ASCII art representation of the remote host
key fingerprint is
printed in addition to the fingerprint string at login and
for unknown host keys.
If this flag is set to
+.Cm unknown ,
+no fingerprint strings are printed at login, but an ASCII art and
+a fingerprint string are printed for unknown host keys.
+If this flag is set to
.Cm no
(the default),
no fingerprint strings are printed at login and
diff --git a/sshconnect.c b/sshconnect.c
index 9ec0618..fe59ac5 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -830,7 +830,7 @@ check_host_key(char *hostname, struct sockaddr
*hostaddr, u_short port,
logit("Warning: Permanently added the %s host "
"key for IP address '%.128s' to the list "
"of known hosts.", type, ip);
- } else if (options.visual_host_key) {
+ } else if (options.visual_host_key == SSH_VISUAL_HOSTKEY_YES) {
fp = sshkey_fingerprint(host_key,
options.fingerprint_hash, SSH_FP_DEFAULT);
ra = sshkey_fingerprint(host_key,