summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Vernon <mcv21@cam.ac.uk>2014-03-25 11:02:33 +0000
committerMatthew Vernon <mcv21@cam.ac.uk>2014-03-25 11:44:10 +0000
commitdb4cdf7b763414af951c7f4031b10679c54d7988 (patch)
tree5c51d1b53beb8924b9db30802823267ca8e4b5f2
parent9cbb60f5e4932634db04c330c88abc49cc5567bd (diff)
Attempt SSHFP lookup even if server presents a certificate
If an ssh server presents a certificate to the client, then the client does not check the DNS for SSHFP records. This means that a malicious server can essentially disable DNS-host-key-checking, which means the client will fall back to asking the user (who will just say "yes" to the fingerprint, sadly). This patch means that the ssh client will, if necessary, extract the server key from the proffered certificate, and attempt to verify it against the DNS. The patch was written by Mark Wooding <mdw@distorted.org.uk>. I modified it to add one debug2 call, reviewed it, and tested it. Signed-off-by: Matthew Vernon <matthew@debian.org> Bug-Debian: http://bugs.debian.org/742513 Patch-Name: sshfp_with_server_cert
-rw-r--r--sshconnect.c67
1 files changed, 47 insertions, 20 deletions
diff --git a/sshconnect.c b/sshconnect.c
index 87c3770c0..b8510d201 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1218,36 +1218,63 @@ fail:
1218 return -1; 1218 return -1;
1219} 1219}
1220 1220
1221static int
1222check_host_key_sshfp(char *host, struct sockaddr *hostaddr, Key *host_key)
1223{
1224 int rc = -1;
1225 int flags = 0;
1226 Key *raw_key = NULL;
1227
1228 if (!options.verify_host_key_dns)
1229 goto done;
1230
1231 /* XXX certs are not yet supported for DNS; try looking the raw key
1232 * up in the DNS anyway.
1233 */
1234 if (key_is_cert(host_key)) {
1235 debug2("Extracting key from cert for SSHFP lookup");
1236 raw_key = key_from_private(host_key);
1237 if (key_drop_cert(raw_key))
1238 fatal("Couldn't drop certificate");
1239 host_key = raw_key;
1240 }
1241
1242 if (verify_host_key_dns(host, hostaddr, host_key, &flags))
1243 goto done;
1244
1245 if (flags & DNS_VERIFY_FOUND) {
1246
1247 if (options.verify_host_key_dns == 1 &&
1248 flags & DNS_VERIFY_MATCH &&
1249 flags & DNS_VERIFY_SECURE) {
1250 rc = 0;
1251 } else if (flags & DNS_VERIFY_MATCH) {
1252 matching_host_key_dns = 1;
1253 } else {
1254 warn_changed_key(host_key);
1255 error("Update the SSHFP RR in DNS with the new "
1256 "host key to get rid of this message.");
1257 }
1258 }
1259
1260done:
1261 if (raw_key)
1262 key_free(raw_key);
1263 return rc;
1264}
1265
1221/* returns 0 if key verifies or -1 if key does NOT verify */ 1266/* returns 0 if key verifies or -1 if key does NOT verify */
1222int 1267int
1223verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 1268verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
1224{ 1269{
1225 int flags = 0;
1226 char *fp; 1270 char *fp;
1227 1271
1228 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); 1272 fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
1229 debug("Server host key: %s %s", key_type(host_key), fp); 1273 debug("Server host key: %s %s", key_type(host_key), fp);
1230 free(fp); 1274 free(fp);
1231 1275
1232 /* XXX certs are not yet supported for DNS */ 1276 if (check_host_key_sshfp(host, hostaddr, host_key) == 0)
1233 if (!key_is_cert(host_key) && options.verify_host_key_dns && 1277 return 0;
1234 verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
1235 if (flags & DNS_VERIFY_FOUND) {
1236
1237 if (options.verify_host_key_dns == 1 &&
1238 flags & DNS_VERIFY_MATCH &&
1239 flags & DNS_VERIFY_SECURE)
1240 return 0;
1241
1242 if (flags & DNS_VERIFY_MATCH) {
1243 matching_host_key_dns = 1;
1244 } else {
1245 warn_changed_key(host_key);
1246 error("Update the SSHFP RR in DNS with the new "
1247 "host key to get rid of this message.");
1248 }
1249 }
1250 }
1251 1278
1252 return check_host_key(host, hostaddr, options.port, host_key, RDRW, 1279 return check_host_key(host, hostaddr, options.port, host_key, RDRW,
1253 options.user_hostfiles, options.num_user_hostfiles, 1280 options.user_hostfiles, options.num_user_hostfiles,