diff options
-rw-r--r-- | debian/.git-dpm | 4 | ||||
-rw-r--r-- | debian/changelog | 3 | ||||
-rw-r--r-- | debian/patches/series | 2 | ||||
-rw-r--r-- | debian/patches/sshfp_with_server_cert | 112 | ||||
-rw-r--r-- | debian/patches/sshfp_with_server_cert_upstr | 83 | ||||
-rw-r--r-- | sshconnect.c | 77 |
6 files changed, 118 insertions, 163 deletions
diff --git a/debian/.git-dpm b/debian/.git-dpm index e8c4eb71a..6b27e0a3f 100644 --- a/debian/.git-dpm +++ b/debian/.git-dpm | |||
@@ -1,6 +1,6 @@ | |||
1 | # see git-dpm(1) from git-dpm package | 1 | # see git-dpm(1) from git-dpm package |
2 | db4cdf7b763414af951c7f4031b10679c54d7988 | 2 | 63d5fa28e16d96db6bac2dbe3fcecb65328f8966 |
3 | db4cdf7b763414af951c7f4031b10679c54d7988 | 3 | 63d5fa28e16d96db6bac2dbe3fcecb65328f8966 |
4 | 796ba4fd011b5d0d9d78d592ba2f30fc9d5ed2e7 | 4 | 796ba4fd011b5d0d9d78d592ba2f30fc9d5ed2e7 |
5 | 796ba4fd011b5d0d9d78d592ba2f30fc9d5ed2e7 | 5 | 796ba4fd011b5d0d9d78d592ba2f30fc9d5ed2e7 |
6 | openssh_6.6p1.orig.tar.gz | 6 | openssh_6.6p1.orig.tar.gz |
diff --git a/debian/changelog b/debian/changelog index d92aac4a7..017f5bb0e 100644 --- a/debian/changelog +++ b/debian/changelog | |||
@@ -11,7 +11,8 @@ openssh (1:6.6p1-1) UNRELEASED; urgency=medium | |||
11 | 11 | ||
12 | [ Matthew Vernon ] | 12 | [ Matthew Vernon ] |
13 | * Fix failure to check SSHFP records if server presents a certificate | 13 | * Fix failure to check SSHFP records if server presents a certificate |
14 | (bug reported by me, patch largely by Mark Wooding) (Closes: #742513) | 14 | (bug reported by me, patch by upstream's Damien Miller; thanks also to |
15 | Mark Wooding for his help in fixing this) (Closes: #742513) | ||
15 | 16 | ||
16 | -- Colin Watson <cjwatson@debian.org> Thu, 20 Mar 2014 00:32:46 +0000 | 17 | -- Colin Watson <cjwatson@debian.org> Thu, 20 Mar 2014 00:32:46 +0000 |
17 | 18 | ||
diff --git a/debian/patches/series b/debian/patches/series index 7bd72e6ed..de7c9902d 100644 --- a/debian/patches/series +++ b/debian/patches/series | |||
@@ -26,4 +26,4 @@ no-openssl-version-check.patch | |||
26 | gnome-ssh-askpass2-icon.patch | 26 | gnome-ssh-askpass2-icon.patch |
27 | sigstop.patch | 27 | sigstop.patch |
28 | debian-config.patch | 28 | debian-config.patch |
29 | sshfp_with_server_cert | 29 | sshfp_with_server_cert_upstr |
diff --git a/debian/patches/sshfp_with_server_cert b/debian/patches/sshfp_with_server_cert deleted file mode 100644 index 7e6a489e6..000000000 --- a/debian/patches/sshfp_with_server_cert +++ /dev/null | |||
@@ -1,112 +0,0 @@ | |||
1 | From db4cdf7b763414af951c7f4031b10679c54d7988 Mon Sep 17 00:00:00 2001 | ||
2 | From: Matthew Vernon <mcv21@cam.ac.uk> | ||
3 | Date: Tue, 25 Mar 2014 11:02:33 +0000 | ||
4 | Subject: Attempt SSHFP lookup even if server presents a certificate | ||
5 | |||
6 | If an ssh server presents a certificate to the client, then the client | ||
7 | does not check the DNS for SSHFP records. This means that a malicious | ||
8 | server can essentially disable DNS-host-key-checking, which means the | ||
9 | client will fall back to asking the user (who will just say "yes" to | ||
10 | the fingerprint, sadly). | ||
11 | |||
12 | This patch means that the ssh client will, if necessary, extract the | ||
13 | server key from the proffered certificate, and attempt to verify it | ||
14 | against the DNS. The patch was written by Mark Wooding | ||
15 | <mdw@distorted.org.uk>. I modified it to add one debug2 call, reviewed | ||
16 | it, and tested it. | ||
17 | |||
18 | Signed-off-by: Matthew Vernon <matthew@debian.org> | ||
19 | Bug-Debian: http://bugs.debian.org/742513 | ||
20 | Patch-Name: sshfp_with_server_cert | ||
21 | --- | ||
22 | sshconnect.c | 67 ++++++++++++++++++++++++++++++++++++++++------------------ | ||
23 | 1 file changed, 47 insertions(+), 20 deletions(-) | ||
24 | |||
25 | diff --git a/sshconnect.c b/sshconnect.c | ||
26 | index 87c3770..b8510d2 100644 | ||
27 | --- a/sshconnect.c | ||
28 | +++ b/sshconnect.c | ||
29 | @@ -1218,36 +1218,63 @@ fail: | ||
30 | return -1; | ||
31 | } | ||
32 | |||
33 | +static int | ||
34 | +check_host_key_sshfp(char *host, struct sockaddr *hostaddr, Key *host_key) | ||
35 | +{ | ||
36 | + int rc = -1; | ||
37 | + int flags = 0; | ||
38 | + Key *raw_key = NULL; | ||
39 | + | ||
40 | + if (!options.verify_host_key_dns) | ||
41 | + goto done; | ||
42 | + | ||
43 | + /* XXX certs are not yet supported for DNS; try looking the raw key | ||
44 | + * up in the DNS anyway. | ||
45 | + */ | ||
46 | + if (key_is_cert(host_key)) { | ||
47 | + debug2("Extracting key from cert for SSHFP lookup"); | ||
48 | + raw_key = key_from_private(host_key); | ||
49 | + if (key_drop_cert(raw_key)) | ||
50 | + fatal("Couldn't drop certificate"); | ||
51 | + host_key = raw_key; | ||
52 | + } | ||
53 | + | ||
54 | + if (verify_host_key_dns(host, hostaddr, host_key, &flags)) | ||
55 | + goto done; | ||
56 | + | ||
57 | + if (flags & DNS_VERIFY_FOUND) { | ||
58 | + | ||
59 | + if (options.verify_host_key_dns == 1 && | ||
60 | + flags & DNS_VERIFY_MATCH && | ||
61 | + flags & DNS_VERIFY_SECURE) { | ||
62 | + rc = 0; | ||
63 | + } else if (flags & DNS_VERIFY_MATCH) { | ||
64 | + matching_host_key_dns = 1; | ||
65 | + } else { | ||
66 | + warn_changed_key(host_key); | ||
67 | + error("Update the SSHFP RR in DNS with the new " | ||
68 | + "host key to get rid of this message."); | ||
69 | + } | ||
70 | + } | ||
71 | + | ||
72 | +done: | ||
73 | + if (raw_key) | ||
74 | + key_free(raw_key); | ||
75 | + return rc; | ||
76 | +} | ||
77 | + | ||
78 | /* returns 0 if key verifies or -1 if key does NOT verify */ | ||
79 | int | ||
80 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | ||
81 | { | ||
82 | - int flags = 0; | ||
83 | char *fp; | ||
84 | |||
85 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | ||
86 | debug("Server host key: %s %s", key_type(host_key), fp); | ||
87 | free(fp); | ||
88 | |||
89 | - /* XXX certs are not yet supported for DNS */ | ||
90 | - if (!key_is_cert(host_key) && options.verify_host_key_dns && | ||
91 | - verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { | ||
92 | - if (flags & DNS_VERIFY_FOUND) { | ||
93 | - | ||
94 | - if (options.verify_host_key_dns == 1 && | ||
95 | - flags & DNS_VERIFY_MATCH && | ||
96 | - flags & DNS_VERIFY_SECURE) | ||
97 | - return 0; | ||
98 | - | ||
99 | - if (flags & DNS_VERIFY_MATCH) { | ||
100 | - matching_host_key_dns = 1; | ||
101 | - } else { | ||
102 | - warn_changed_key(host_key); | ||
103 | - error("Update the SSHFP RR in DNS with the new " | ||
104 | - "host key to get rid of this message."); | ||
105 | - } | ||
106 | - } | ||
107 | - } | ||
108 | + if (check_host_key_sshfp(host, hostaddr, host_key) == 0) | ||
109 | + return 0; | ||
110 | |||
111 | return check_host_key(host, hostaddr, options.port, host_key, RDRW, | ||
112 | options.user_hostfiles, options.num_user_hostfiles, | ||
diff --git a/debian/patches/sshfp_with_server_cert_upstr b/debian/patches/sshfp_with_server_cert_upstr new file mode 100644 index 000000000..dd642d2a3 --- /dev/null +++ b/debian/patches/sshfp_with_server_cert_upstr | |||
@@ -0,0 +1,83 @@ | |||
1 | From 63d5fa28e16d96db6bac2dbe3fcecb65328f8966 Mon Sep 17 00:00:00 2001 | ||
2 | From: Matthew Vernon <mcv21@cam.ac.uk> | ||
3 | Date: Wed, 26 Mar 2014 15:32:23 +0000 | ||
4 | Subject: Attempt SSHFP lookup even if server presents a certificate | ||
5 | |||
6 | If an ssh server presents a certificate to the client, then the client | ||
7 | does not check the DNS for SSHFP records. This means that a malicious | ||
8 | server can essentially disable DNS-host-key-checking, which means the | ||
9 | client will fall back to asking the user (who will just say "yes" to | ||
10 | the fingerprint, sadly). | ||
11 | |||
12 | This patch is by Damien Miller (of openssh upstream). It's simpler | ||
13 | than the patch by Mark Wooding which I applied yesterday; a copy is | ||
14 | taken of the proffered key/cert, the key extracted from the cert (if | ||
15 | necessary), and then the DNS consulted. | ||
16 | |||
17 | Signed-off-by: Matthew Vernon <matthew@debian.org> | ||
18 | Bug-Debian: http://bugs.debian.org/742513 | ||
19 | Patch-Name: sshfp_with_server_cert_upstr | ||
20 | --- | ||
21 | sshconnect.c | 42 ++++++++++++++++++++++++++---------------- | ||
22 | 1 file changed, 26 insertions(+), 16 deletions(-) | ||
23 | |||
24 | diff --git a/sshconnect.c b/sshconnect.c | ||
25 | index 87c3770..324f5e0 100644 | ||
26 | --- a/sshconnect.c | ||
27 | +++ b/sshconnect.c | ||
28 | @@ -1224,29 +1224,39 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | ||
29 | { | ||
30 | int flags = 0; | ||
31 | char *fp; | ||
32 | + Key *plain = NULL; | ||
33 | |||
34 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | ||
35 | debug("Server host key: %s %s", key_type(host_key), fp); | ||
36 | free(fp); | ||
37 | |||
38 | - /* XXX certs are not yet supported for DNS */ | ||
39 | - if (!key_is_cert(host_key) && options.verify_host_key_dns && | ||
40 | - verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { | ||
41 | - if (flags & DNS_VERIFY_FOUND) { | ||
42 | - | ||
43 | - if (options.verify_host_key_dns == 1 && | ||
44 | - flags & DNS_VERIFY_MATCH && | ||
45 | - flags & DNS_VERIFY_SECURE) | ||
46 | - return 0; | ||
47 | - | ||
48 | - if (flags & DNS_VERIFY_MATCH) { | ||
49 | - matching_host_key_dns = 1; | ||
50 | - } else { | ||
51 | - warn_changed_key(host_key); | ||
52 | - error("Update the SSHFP RR in DNS with the new " | ||
53 | - "host key to get rid of this message."); | ||
54 | + if (options.verify_host_key_dns) { | ||
55 | + /* | ||
56 | + * XXX certs are not yet supported for DNS, so downgrade | ||
57 | + * them and try the plain key. | ||
58 | + */ | ||
59 | + plain = key_from_private(host_key); | ||
60 | + if (key_is_cert(plain)) | ||
61 | + key_drop_cert(plain); | ||
62 | + if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { | ||
63 | + if (flags & DNS_VERIFY_FOUND) { | ||
64 | + if (options.verify_host_key_dns == 1 && | ||
65 | + flags & DNS_VERIFY_MATCH && | ||
66 | + flags & DNS_VERIFY_SECURE) { | ||
67 | + key_free(plain); | ||
68 | + return 0; | ||
69 | + } | ||
70 | + if (flags & DNS_VERIFY_MATCH) { | ||
71 | + matching_host_key_dns = 1; | ||
72 | + } else { | ||
73 | + warn_changed_key(plain); | ||
74 | + error("Update the SSHFP RR in DNS " | ||
75 | + "with the new host key to get rid " | ||
76 | + "of this message."); | ||
77 | + } | ||
78 | } | ||
79 | } | ||
80 | + key_free(plain); | ||
81 | } | ||
82 | |||
83 | return check_host_key(host, hostaddr, options.port, host_key, RDRW, | ||
diff --git a/sshconnect.c b/sshconnect.c index b8510d201..324f5e0a3 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1218,63 +1218,46 @@ 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 | |||
1266 | /* returns 0 if key verifies or -1 if key does NOT verify */ | 1221 | /* returns 0 if key verifies or -1 if key does NOT verify */ |
1267 | int | 1222 | int |
1268 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 1223 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) |
1269 | { | 1224 | { |
1225 | int flags = 0; | ||
1270 | char *fp; | 1226 | char *fp; |
1227 | Key *plain = NULL; | ||
1271 | 1228 | ||
1272 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 1229 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
1273 | debug("Server host key: %s %s", key_type(host_key), fp); | 1230 | debug("Server host key: %s %s", key_type(host_key), fp); |
1274 | free(fp); | 1231 | free(fp); |
1275 | 1232 | ||
1276 | if (check_host_key_sshfp(host, hostaddr, host_key) == 0) | 1233 | if (options.verify_host_key_dns) { |
1277 | return 0; | 1234 | /* |
1235 | * XXX certs are not yet supported for DNS, so downgrade | ||
1236 | * them and try the plain key. | ||
1237 | */ | ||
1238 | plain = key_from_private(host_key); | ||
1239 | if (key_is_cert(plain)) | ||
1240 | key_drop_cert(plain); | ||
1241 | if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { | ||
1242 | if (flags & DNS_VERIFY_FOUND) { | ||
1243 | if (options.verify_host_key_dns == 1 && | ||
1244 | flags & DNS_VERIFY_MATCH && | ||
1245 | flags & DNS_VERIFY_SECURE) { | ||
1246 | key_free(plain); | ||
1247 | return 0; | ||
1248 | } | ||
1249 | if (flags & DNS_VERIFY_MATCH) { | ||
1250 | matching_host_key_dns = 1; | ||
1251 | } else { | ||
1252 | warn_changed_key(plain); | ||
1253 | error("Update the SSHFP RR in DNS " | ||
1254 | "with the new host key to get rid " | ||
1255 | "of this message."); | ||
1256 | } | ||
1257 | } | ||
1258 | } | ||
1259 | key_free(plain); | ||
1260 | } | ||
1278 | 1261 | ||
1279 | return check_host_key(host, hostaddr, options.port, host_key, RDRW, | 1262 | return check_host_key(host, hostaddr, options.port, host_key, RDRW, |
1280 | options.user_hostfiles, options.num_user_hostfiles, | 1263 | options.user_hostfiles, options.num_user_hostfiles, |