diff --git a/cli-kex.c b/cli-kex.c
index d8824230ab440896a44ee216e2329b6d7b94d456..436fdad7d205d9cd5779417cac0bf04cd220f0bb 100644
--- a/cli-kex.c
+++ b/cli-kex.c
@@ -37,6 +37,8 @@
 #include "signkey.h"
 
 
+static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen);
+#define MAX_KNOWNHOSTS_LINE 4500
 
 void send_msg_kexdh_init() {
 
@@ -58,14 +60,22 @@ void recv_msg_kexdh_reply() {
 
 	mp_int dh_f;
 	sign_key *hostkey = NULL;
-	int type, keylen;
+	unsigned int type, keybloblen;
+	unsigned char* keyblob = NULL;
+
 
 	TRACE(("enter recv_msg_kexdh_reply"));
 	type = ses.newkeys->algo_hostkey;
 	TRACE(("type is %d", type));
 
 	hostkey = new_sign_key();
-	keylen = buf_getint(ses.payload);
+	keybloblen = buf_getint(ses.payload);
+
+	keyblob = buf_getptr(ses.payload, keybloblen);
+	if (!ses.kexstate.donefirstkex) {
+		/* Only makes sense the first time */
+		checkhostkey(keyblob, keybloblen);
+	}
 
 	if (buf_get_pub_key(ses.payload, hostkey, &type) != DROPBEAR_SUCCESS) {
 		TRACE(("failed getting pubkey"));
@@ -86,9 +96,6 @@ void recv_msg_kexdh_reply() {
 		dropbear_exit("Bad hostkey signature");
 	}
 
-	/* XXX TODO */
-	dropbear_log(LOG_WARNING,"Not checking hostkey fingerprint for the moment");
-
 	sign_key_free(hostkey);
 	hostkey = NULL;
 
@@ -96,3 +103,123 @@ void recv_msg_kexdh_reply() {
 	ses.requirenext = SSH_MSG_NEWKEYS;
 	TRACE(("leave recv_msg_kexdh_init"));
 }
+
+static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) {
+
+	char* fp = NULL;
+
+	fp = sign_key_fingerprint(keyblob, keybloblen);
+	fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n", 
+			cli_opts.remotehost, 
+			fp);
+
+	if (getc(stdin) == 'y') {
+		m_free(fp);
+		return;
+	}
+
+	dropbear_exit("Didn't validate host key");
+}
+
+static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) {
+
+	char * filename = NULL;
+	FILE *hostsfile = NULL;
+	struct passwd *pw = NULL;
+	unsigned int len, hostlen;
+	const char *algoname = NULL;
+	buffer * line = NULL;
+	int ret;
+	
+	pw = getpwuid(getuid());
+
+	if (pw == NULL) {
+		dropbear_exit("Failed to get homedir");
+	}
+
+	len = strlen(pw->pw_dir);
+	filename = m_malloc(len + 18); /* "/.ssh/known_hosts" and null-terminator*/
+
+	snprintf(filename, len+18, "%s/.ssh", pw->pw_dir);
+	/* Check that ~/.ssh exists - easiest way is just to mkdir */
+	if (mkdir(filename, S_IRWXU) != 0) {
+		if (errno != EEXIST) {
+			ask_to_confirm(keyblob, keybloblen);
+			goto out; /* only get here on success */
+		}
+	}
+
+	snprintf(filename, len+18, "%s/.ssh/known_hosts", pw->pw_dir);
+	hostsfile = fopen(filename, "r+");
+	if (hostsfile == NULL) {
+		ask_to_confirm(keyblob, keybloblen);
+		goto out; /* We only get here on success */
+	}
+
+	line = buf_new(MAX_KNOWNHOSTS_LINE);
+	hostlen = strlen(cli_opts.remotehost);
+
+	do {
+		if (buf_getline(line, hostsfile) == DROPBEAR_FAILURE) {
+			TRACE(("failed reading line: prob EOF"));
+			break;
+		}
+
+		/* The line is too short to be sensible */
+		/* "30" is 'enough to hold ssh-dss plus the spaces, ie so we don't
+		 * buf_getfoo() past the end and die horribly - the base64 parsing
+		 * code is what tiptoes up to the end nicely */
+		if (line->len < (hostlen+30) ) {
+			TRACE(("line is too short to be sensible"));
+			continue;
+		}
+
+		/* Compare hostnames */
+		if (strncmp(cli_opts.remotehost, buf_getptr(line, hostlen),
+					hostlen) != 0) {
+			TRACE(("hosts don't match"));
+			continue;
+		}
+
+		buf_incrpos(line, hostlen);
+		if (buf_getbyte(line) != ' ') {
+			/* there wasn't a space after the hostname, something dodgy */
+			TRACE(("missing space afte matching hostname"));
+			continue;
+		}
+
+		algoname = signkey_name_from_type(ses.newkeys->algo_hostkey, &len);
+		if ( strncmp(buf_getptr(line, len), algoname, len) != 0) {
+			TRACE(("algo doesn't match"));
+			continue;
+		}
+
+		buf_incrpos(line, len);
+		if (buf_getbyte(line) != ' ') {
+			TRACE(("missing space after algo"));
+			continue;
+		}
+
+		/* Now we're at the interesting hostkey */
+		ret = cmp_base64_key(keyblob, keybloblen, algoname, len, line);
+
+		if (ret == DROPBEAR_SUCCESS) {
+			/* Good matching key */
+			TRACE(("good matching key"));
+			goto out;
+		}
+
+		/* The keys didn't match. eep. */
+	} while (1); /* keep going 'til something happens */
+
+	/* Key doesn't exist yet */
+	ask_to_confirm(keyblob, keybloblen);
+	/* If we get here, they said yes */
+
+out:
+	if (hostsfile != NULL) {
+		fclose(hostsfile);
+	}
+	m_free(filename);
+	buf_free(line);
+}
diff --git a/dbutil.c b/dbutil.c
index 1c0648c815edaebe0dde4ed0f9b0d3c957aa3e86..dd6841683b3483faf8cac8b5dcbe95d654f4ca6f 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -320,6 +320,52 @@ int buf_readfile(buffer* buf, const char* filename) {
 	return DROPBEAR_SUCCESS;
 }
 
+/* get a line from the file into buffer in the style expected for an
+ * authkeys file.
+ * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
+/* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */
+#if defined(DROPBEAR_CLIENT) || defined(DROPBEAR_PUBKEY_AUTH)
+int buf_getline(buffer * line, FILE * authfile) {
+
+	int c = EOF;
+
+	TRACE(("enter buf_getline"));
+
+	buf_setpos(line, 0);
+	buf_setlen(line, 0);
+
+	while (line->pos < line->size) {
+
+		c = fgetc(authfile); /*getc() is weird with some uClibc systems*/
+		if (c == EOF || c == '\n' || c == '\r') {
+			goto out;
+		}
+
+		buf_putbyte(line, (unsigned char)c);
+	}
+
+	TRACE(("leave getauthline: line too long"));
+	/* We return success, but the line length will be zeroed - ie we just
+	 * ignore that line */
+	buf_setlen(line, 0);
+
+out:
+
+	buf_setpos(line, 0);
+
+	/* if we didn't read anything before EOF or error, exit */
+	if (c == EOF && line->pos == 0) {
+		TRACE(("leave getauthline: failure"));
+		return DROPBEAR_FAILURE;
+	} else {
+		TRACE(("leave getauthline: success"));
+		return DROPBEAR_SUCCESS;
+	}
+
+	TRACE(("leave buf_getline"));
+}	
+#endif
+
 /* loop until the socket is closed (in case of EINTR) or
  * we get and error.
  * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
diff --git a/options.h b/options.h
index 55755b2111333cae7bb3bae0efcf6330bfd25e47..d4abf098f57736a77c967aec63b0fb9eb08e3451 100644
--- a/options.h
+++ b/options.h
@@ -301,6 +301,10 @@
 #define USING_LISTENERS
 #endif
 
+#if defined(DROPBEAR_CLIENT) || defined(DROPBEAR_PUBKEY_AUTH)
+#define DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
+#endif
+
 /* We use dropbear_client and dropbear_server as shortcuts to avoid redundant
  * code, if we're just compiling as client or server */
 #if defined(DROPBEAR_SERVER) && defined(DROPBEAR_CLIENT)
diff --git a/signkey.c b/signkey.c
index ec6ea7474ce4bcbd98fff09b4738920a664d9f9c..3efcc2b25f4699057fbc60bb89daa6a437c21033 100644
--- a/signkey.c
+++ b/signkey.c
@@ -272,25 +272,20 @@ static char hexdig(unsigned char x) {
 /* Since we're not sure if we'll have md5 or sha1, we present both.
  * MD5 is used in preference, but sha1 could still be useful */
 #ifdef DROPBEAR_MD5_HMAC
-static char * sign_key_md5_fingerprint(sign_key *key, int type) {
+static char * sign_key_md5_fingerprint(unsigned char* keyblob,
+		unsigned int keybloblen) {
 
 	char * ret;
 	hash_state hs;
-	buffer *pubkeys;
 	unsigned char hash[MD5_HASH_SIZE];
 	unsigned int h, i;
 	unsigned int buflen;
 
 	md5_init(&hs);
 
-	pubkeys = buf_new(1000);
-	buf_put_pub_key(pubkeys, key, type);
 	/* skip the size int of the string - this is a bit messy */
-	buf_setpos(pubkeys, 4);
-	md5_process(&hs, buf_getptr(pubkeys, pubkeys->len-pubkeys->pos),
-			pubkeys->len-pubkeys->pos);
+	md5_process(&hs, keyblob, keybloblen);
 
-	buf_free(pubkeys);
 	md5_done(&hs, hash);
 
 	/* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
@@ -311,25 +306,20 @@ static char * sign_key_md5_fingerprint(sign_key *key, int type) {
 }
 
 #else /* use SHA1 rather than MD5 for fingerprint */
-static char * sign_key_sha1_fingerprint(sign_key *key, int type) {
+static char * sign_key_sha1_fingerprint(unsigned char* keyblob, 
+		unsigned int keybloblen) {
 
 	char * ret;
 	hash_state hs;
-	buffer *pubkeys;
 	unsigned char hash[SHA1_HASH_SIZE];
 	unsigned int h, i;
 	unsigned int buflen;
 
 	sha1_init(&hs);
 
-	pubkeys = buf_new(1000);
-	buf_put_pub_key(pubkeys, key, type);
-	buf_setpos(pubkeys, 4);
 	/* skip the size int of the string - this is a bit messy */
-	sha1_process(&hs, buf_getptr(pubkeys, pubkeys->len-pubkeys->pos),
-			pubkeys->len-pubkeys->pos);
+	sha1_process(&hs, keyblob, keybloblen);
 
-	buf_free(pubkeys);
 	sha1_done(&hs, hash);
 
 	/* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
@@ -352,12 +342,12 @@ static char * sign_key_sha1_fingerprint(sign_key *key, int type) {
 
 /* This will return a freshly malloced string, containing a fingerprint
  * in either sha1 or md5 */
-char * sign_key_fingerprint(sign_key *key, int type) {
+char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen) {
 
 #ifdef DROPBEAR_MD5_HMAC
-	return sign_key_md5_fingerprint(key, type);
+	return sign_key_md5_fingerprint(keyblob, keybloblen);
 #else
-	return sign_key_sha1_fingerprint(key, type);
+	return sign_key_sha1_fingerprint(keyblob, keybloblen);
 #endif
 }
 
@@ -427,3 +417,59 @@ int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
 	return DROPBEAR_FAILURE;
 }
 #endif /* DROPBEAR_SIGNKEY_VERIFY */
+
+#ifdef DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
+
+/* 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 */
+int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, 
+					const unsigned char* algoname, unsigned int algolen, 
+					buffer * line) {
+
+	buffer * decodekey = NULL;
+	int ret = DROPBEAR_FAILURE;
+	unsigned int len, filealgolen;
+	unsigned long decodekeylen;
+	unsigned char* filealgo = NULL;
+
+	/* now we have the actual data */
+	len = line->len - line->pos;
+	decodekeylen = len * 2; /* big to be safe */
+	decodekey = buf_new(decodekeylen);
+
+	if (base64_decode(buf_getptr(line, len), len,
+				buf_getwriteptr(decodekey, decodekey->size),
+				&decodekeylen) != CRYPT_OK) {
+		TRACE(("checkpubkey: base64 decode failed"));
+		goto out;
+	}
+	TRACE(("checkpubkey: base64_decode success"));
+	buf_incrlen(decodekey, decodekeylen);
+	
+	/* compare the keys */
+	if ( ( decodekeylen != keybloblen )
+			|| memcmp( buf_getptr(decodekey, decodekey->len),
+						keyblob, decodekey->len) != 0) {
+		TRACE(("checkpubkey: compare failed"));
+		goto out;
+	}
+
+	/* ... and also check that the algo specified and the algo in the key
+	 * itself match */
+	filealgolen = buf_getint(decodekey);
+	filealgo = buf_getptr(decodekey, filealgolen);
+	if (filealgolen != algolen || memcmp(filealgo, algoname, algolen) != 0) {
+		TRACE(("checkpubkey: algo match failed")); 
+		goto out;
+	}
+
+	/* All checks passed */
+	ret = DROPBEAR_SUCCESS;
+
+out:
+	buf_free(decodekey);
+	decodekey = NULL;
+	return ret;
+}
+#endif
diff --git a/signkey.h b/signkey.h
index 3bd5c58d803a3bd61833a40303f45b5f8a286f2a..8bc7e8f10fb7ab67d8cacc6891690c88f72627f6 100644
--- a/signkey.h
+++ b/signkey.h
@@ -54,7 +54,10 @@ void buf_put_sign(buffer* buf, sign_key *key, int type,
 #ifdef DROPBEAR_SIGNKEY_VERIFY
 int buf_verify(buffer * buf, sign_key *key, const unsigned char *data,
 		unsigned int len);
-char * sign_key_fingerprint(sign_key *key, int type);
+char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen);
 #endif
+int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, 
+					const unsigned char* algoname, unsigned int algolen, 
+					buffer * line);
 
 #endif /* _SIGNKEY_H_ */
diff --git a/svr-authpubkey.c b/svr-authpubkey.c
index e6cc60670e9eeb7df3bf8e7c6a740287edf6842a..53d5c064ac1c58011c38305ba70ded27f23ea616 100644
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -38,7 +38,7 @@
 #ifdef DROPBEAR_PUBKEY_AUTH
 
 #define MIN_AUTHKEYS_LINE 10 /* "ssh-rsa AB" - short but doesn't matter */
-#define MAX_AUTHKEYS_LINE 1000 /* max length of a line in authkeys */
+#define MAX_AUTHKEYS_LINE 4200 /* max length of a line in authkeys */
 
 static int checkpubkey(unsigned char* algo, unsigned int algolen,
 		unsigned char* keyblob, unsigned int keybloblen);
@@ -46,7 +46,6 @@ static int checkpubkeyperms();
 static void send_msg_userauth_pk_ok(unsigned char* algo, unsigned int algolen,
 		unsigned char* keyblob, unsigned int keybloblen);
 static int checkfileperm(char * filename);
-static int getauthline(buffer * line, FILE * authfile);
 
 /* process a pubkey auth request, sending success or failure message as
  * appropriate */
@@ -102,7 +101,7 @@ void svr_auth_pubkey() {
 	buf_setpos(signbuf, 0);
 
 	/* ... and finally verify the signature */
-	fp = sign_key_fingerprint(key, type);
+	fp = sign_key_fingerprint(keyblob, keybloblen);
 	if (buf_verify(ses.payload, key, buf_getptr(signbuf, signbuf->len),
 				signbuf->len) == DROPBEAR_SUCCESS) {
 		dropbear_log(LOG_NOTICE,
@@ -160,10 +159,6 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
 	char * filename = NULL;
 	int ret = DROPBEAR_FAILURE;
 	buffer * line = NULL;
-	buffer * decodekey = NULL;
-	unsigned long decodekeylen;
-	unsigned char* filealgo = NULL;
-	unsigned int filealgolen;
 	unsigned int len, pos;
 	
 	TRACE(("enter checkpubkey"));
@@ -202,14 +197,8 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
 
 	/* iterate through the lines */
 	do {
-		/* free reused vars */
-		if (decodekey) {
-			buf_free(decodekey);
-			decodekey = NULL;
-		}
-		m_free(filealgo);
 
-		if (getauthline(line, authfile) == DROPBEAR_FAILURE) {
+		if (buf_getline(line, authfile) == DROPBEAR_FAILURE) {
 			/* EOF reached */
 			TRACE(("checkpubkey: authorized_keys EOF reached"));
 			break;
@@ -243,38 +232,12 @@ static int checkpubkey(unsigned char* algo, unsigned int algolen,
 
 		TRACE(("checkpubkey: line pos = %d len = %d", line->pos, line->len));
 
-		/* now we have the actual data */
-		decodekeylen = (line->len - line->pos) * 2;
-		decodekey = buf_new(decodekeylen);
-		if (base64_decode(buf_getptr(line, line->len - line->pos),
-					line->len - line->pos,
-					buf_getwriteptr(decodekey, decodekey->size),
-					&decodekeylen) != CRYPT_OK) {
-			TRACE(("checkpubkey: base64 decode failed"));
-			continue;
-		}
-		TRACE(("checkpubkey: base64_decode success"));
-		buf_incrlen(decodekey, decodekeylen);
-		
-		/* compare the keys */
-		if (decodekeylen != keybloblen || memcmp(
-					buf_getptr(decodekey, decodekey->len),
-					keyblob, decodekey->len) != 0) {
-			TRACE(("checkpubkey: compare failed"));
-			continue;
-		}
-
-		/* and also check that the algo specified and the algo in the key
-		 * itself match */
-		filealgo = buf_getstring(decodekey, &filealgolen);
-		if (filealgolen != algolen || memcmp(filealgo, algo, algolen) != 0) {
-			TRACE(("checkpubkey: algo match failed")); 
-			continue;
+		ret = cmp_base64_key(keyblob, keybloblen, algo, algolen, line);
+		if (ret == DROPBEAR_SUCCESS) {
+			break;
 		}
 
-		/* now we know this key is good */
-		ret = DROPBEAR_SUCCESS;
-		break;
+		/* We continue to the next line otherwise */
 		
 	} while (1);
 
@@ -285,53 +248,11 @@ out:
 	if (line) {
 		buf_free(line);
 	}
-	if (decodekey) {
-		buf_free(decodekey);
-	}
 	m_free(filename);
-	m_free(filealgo);
 	TRACE(("leave checkpubkey: ret=%d", ret));
 	return ret;
 }
 
-/* get a line from the file into buffer in the style expected for an
- * authkeys file.
- * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
-static int getauthline(buffer * line, FILE * authfile) {
-
-	int c = EOF;
-
-	TRACE(("enter getauthline"));
-
-	buf_setpos(line, 0);
-	buf_setlen(line, 0);
-
-	while (line->pos < line->size) {
-		c = fgetc(authfile); /*getc() is weird with some uClibc systems*/
-		if (c == EOF || c == '\n' || c == '\r') {
-			goto out;
-		}
-		buf_putbyte(line, (unsigned char)c);
-	}
-
-	TRACE(("leave getauthline: line too long"));
-	return DROPBEAR_FAILURE;
-
-out:
-
-	buf_setpos(line, 0);
-
-	/* if we didn't read anything before EOF or error, exit */
-	if (c == EOF && line->pos == 0) {
-		TRACE(("leave getauthline: failure"));
-		return DROPBEAR_FAILURE;
-	} else {
-		TRACE(("leave getauthline: success"));
-		return DROPBEAR_SUCCESS;
-	}
-
-	TRACE(("leave getauthline"));
-}	
 
 /* Returns DROPBEAR_SUCCESS if file permissions for pubkeys are ok,
  * DROPBEAR_FAILURE otherwise.