# HG changeset patch # User Matt Johnston # Date 1172158172 0 # Node ID 7282370416a03dbade0e6f03bcf6de6069c28046 # Parent 337c45621e819321cc7a88f303b96df4e931c02c Improve known_hosts checking. diff -r 337c45621e81 -r 7282370416a0 cli-kex.c --- a/cli-kex.c Thu Feb 22 14:53:49 2007 +0000 +++ b/cli-kex.c Thu Feb 22 15:29:32 2007 +0000 @@ -146,31 +146,24 @@ dropbear_exit("Didn't validate host key"); } -static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { - +static FILE* open_known_hosts_file(int * readonly) +{ + FILE * hostsfile = NULL; char * filename = NULL; - FILE *hostsfile = NULL; - int readonly = 0; - struct passwd *pw = NULL; char * homedir = NULL; - unsigned int hostlen, algolen; - unsigned long len; - const char *algoname = NULL; - buffer * line = NULL; - int ret; homedir = getenv("HOME"); if (!homedir) { + struct passwd * pw = NULL; pw = getpwuid(getuid()); if (pw) { homedir = pw->pw_dir; } - pw = NULL; } if (homedir) { - + unsigned int len; len = strlen(homedir); filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/ @@ -181,8 +174,7 @@ dropbear_log(LOG_INFO, "Warning: failed creating %s/.ssh: %s", homedir, strerror(errno)); TRACE(("mkdir didn't work: %s", strerror(errno))) - ask_to_confirm(keyblob, keybloblen); - goto out; /* only get here on success */ + goto out; } } @@ -190,12 +182,13 @@ hostsfile = fopen(filename, "a+"); if (hostsfile != NULL) { + *readonly = 0; fseek(hostsfile, 0, SEEK_SET); } else { /* We mightn't have been able to open it if it was read-only */ if (errno == EACCES || errno == EROFS) { TRACE(("trying readonly: %s", strerror(errno))) - readonly = 1; + *readonly = 1; hostsfile = fopen(filename, "r"); } } @@ -205,10 +198,32 @@ TRACE(("hostsfile didn't open: %s", strerror(errno))) dropbear_log(LOG_WARNING, "Failed to open %s/.ssh/known_hosts", homedir); + goto out; + } + +out: + m_free(filename); + return hostsfile; +} + +static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { + + FILE *hostsfile = NULL; + int readonly = 0; + unsigned int hostlen, algolen; + unsigned long len; + const char *algoname = NULL; + char * fingerprint = NULL; + buffer * line = NULL; + int ret; + + hostsfile = open_known_hosts_file(&readonly); + if (!hostsfile) { ask_to_confirm(keyblob, keybloblen); - goto out; /* We only get here on success */ + /* ask_to_confirm will exit upon failure */ + return; } - + line = buf_new(MAX_KNOWNHOSTS_LINE); hostlen = strlen(cli_opts.remotehost); algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &algolen); @@ -242,7 +257,7 @@ continue; } - if ( strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) { + if (strncmp(buf_getptr(line, algolen), algoname, algolen) != 0) { TRACE(("algo doesn't match")) continue; } @@ -254,7 +269,8 @@ } /* Now we're at the interesting hostkey */ - ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, line); + ret = cmp_base64_key(keyblob, keybloblen, algoname, algolen, + line, &fingerprint); if (ret == DROPBEAR_SUCCESS) { /* Good matching key */ @@ -262,7 +278,15 @@ goto out; } - /* The keys didn't match. eep. */ + /* The keys didn't match. eep. Note that we're "leaking" + the fingerprint strings here, but we're exiting anyway */ + dropbear_exit("\n\nHost key mismatch for %s !\n" + "Fingerprint is %s\n" + "Expected %s\n" + "If you know that the host key is correct you can\nremove the bad entry from ~/.ssh/known_hosts", + cli_opts.remotehost, + sign_key_fingerprint(keyblob, keybloblen), + fingerprint ? fingerprint : "UNKNOWN"); } while (1); /* keep going 'til something happens */ /* Key doesn't exist yet */ @@ -300,7 +324,6 @@ if (hostsfile != NULL) { fclose(hostsfile); } - m_free(filename); if (line != NULL) { buf_free(line); } diff -r 337c45621e81 -r 7282370416a0 signkey.c --- a/signkey.c Thu Feb 22 14:53:49 2007 +0000 +++ b/signkey.c Thu Feb 22 15:29:32 2007 +0000 @@ -432,9 +432,11 @@ /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing * a key, a key, and a type. The buffer is positioned at the start of the * base64 data, and contains no trailing data */ +/* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint + of the key if it is successfully decoded */ int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, const unsigned char* algoname, unsigned int algolen, - buffer * line) { + buffer * line, char ** fingerprint) { buffer * decodekey = NULL; int ret = DROPBEAR_FAILURE; @@ -456,6 +458,11 @@ TRACE(("checkpubkey: base64_decode success")) buf_incrlen(decodekey, decodekeylen); + if (fingerprint) { + *fingerprint = sign_key_fingerprint(buf_getptr(decodekey, decodekeylen), + decodekeylen); + } + /* compare the keys */ if ( ( decodekeylen != keybloblen ) || memcmp( buf_getptr(decodekey, decodekey->len), diff -r 337c45621e81 -r 7282370416a0 signkey.h --- a/signkey.h Thu Feb 22 14:53:49 2007 +0000 +++ b/signkey.h Thu Feb 22 15:29:32 2007 +0000 @@ -58,6 +58,6 @@ #endif int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, const unsigned char* algoname, unsigned int algolen, - buffer * line); + buffer * line, char ** fingerprint); #endif /* _SIGNKEY_H_ */ diff -r 337c45621e81 -r 7282370416a0 svr-authpubkey.c --- a/svr-authpubkey.c Thu Feb 22 14:53:49 2007 +0000 +++ b/svr-authpubkey.c Thu Feb 22 15:29:32 2007 +0000 @@ -231,7 +231,7 @@ TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len)) - ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line); + ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line, NULL); if (ret == DROPBEAR_SUCCESS) { break; }