diff options
author | Matthew Vernon <mcv21@cam.ac.uk> | 2014-03-25 11:02:33 +0000 |
---|---|---|
committer | Matthew Vernon <mcv21@cam.ac.uk> | 2014-03-25 11:44:10 +0000 |
commit | db4cdf7b763414af951c7f4031b10679c54d7988 (patch) | |
tree | 5c51d1b53beb8924b9db30802823267ca8e4b5f2 | |
parent | 9cbb60f5e4932634db04c330c88abc49cc5567bd (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.c | 67 |
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 | ||
1221 | static int | ||
1222 | check_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 | |||
1260 | done: | ||
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 */ |
1222 | int | 1267 | int |
1223 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 1268 | verify_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, |