diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | dns.c | 68 | ||||
-rw-r--r-- | dns.h | 13 | ||||
-rw-r--r-- | readconf.c | 5 | ||||
-rw-r--r-- | ssh_config.5 | 19 | ||||
-rw-r--r-- | sshconnect.c | 40 |
6 files changed, 81 insertions, 69 deletions
@@ -31,6 +31,9 @@ | |||
31 | - dtucker@cvs.openbsd.org 2003/11/12 10:12:15 | 31 | - dtucker@cvs.openbsd.org 2003/11/12 10:12:15 |
32 | [scp.c] | 32 | [scp.c] |
33 | When called with -q, pass -q to ssh; suppresses SSH2 banner. ok markus@ | 33 | When called with -q, pass -q to ssh; suppresses SSH2 banner. ok markus@ |
34 | - jakob@cvs.openbsd.org 2003/11/12 16:39:58 | ||
35 | [dns.c dns.h readconf.c ssh_config.5 sshconnect.c] | ||
36 | update SSHFP validation. ok markus@ | ||
34 | 37 | ||
35 | 20031115 | 38 | 20031115 |
36 | - (dtucker) [regress/agent-ptrace.sh] Test for GDB output from Solaris and | 39 | - (dtucker) [regress/agent-ptrace.sh] Test for GDB output from Solaris and |
@@ -1451,4 +1454,4 @@ | |||
1451 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. | 1454 | - Fix sshd BindAddress and -b options for systems using fake-getaddrinfo. |
1452 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au | 1455 | Report from murple@murple.net, diagnosis from dtucker@zip.com.au |
1453 | 1456 | ||
1454 | $Id: ChangeLog,v 1.3105 2003/11/17 10:19:05 djm Exp $ | 1457 | $Id: ChangeLog,v 1.3106 2003/11/17 10:19:29 djm Exp $ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dns.c,v 1.7 2003/10/14 19:42:10 jakob Exp $ */ | 1 | /* $OpenBSD: dns.c,v 1.8 2003/11/12 16:39:58 jakob Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. | 4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. |
@@ -43,7 +43,7 @@ | |||
43 | #include "uuencode.h" | 43 | #include "uuencode.h" |
44 | 44 | ||
45 | extern char *__progname; | 45 | extern char *__progname; |
46 | RCSID("$OpenBSD: dns.c,v 1.7 2003/10/14 19:42:10 jakob Exp $"); | 46 | RCSID("$OpenBSD: dns.c,v 1.8 2003/11/12 16:39:58 jakob Exp $"); |
47 | 47 | ||
48 | #ifndef LWRES | 48 | #ifndef LWRES |
49 | static const char *errset_text[] = { | 49 | static const char *errset_text[] = { |
@@ -83,7 +83,7 @@ dns_result_totext(unsigned int error) | |||
83 | */ | 83 | */ |
84 | static int | 84 | static int |
85 | dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, | 85 | dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, |
86 | u_char **digest, u_int *digest_len, Key *key) | 86 | u_char **digest, u_int *digest_len, const Key *key) |
87 | { | 87 | { |
88 | int success = 0; | 88 | int success = 0; |
89 | 89 | ||
@@ -145,16 +145,15 @@ dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type, | |||
145 | 145 | ||
146 | /* | 146 | /* |
147 | * Verify the given hostname, address and host key using DNS. | 147 | * Verify the given hostname, address and host key using DNS. |
148 | * Returns 0 if key verifies or -1 if key does NOT verify | 148 | * Returns 0 if lookup succeeds, -1 otherwise |
149 | */ | 149 | */ |
150 | int | 150 | int |
151 | verify_host_key_dns(const char *hostname, struct sockaddr *address, | 151 | verify_host_key_dns(const char *hostname, struct sockaddr *address, |
152 | Key *hostkey) | 152 | const Key *hostkey, int *flags) |
153 | { | 153 | { |
154 | int counter; | 154 | int counter; |
155 | int result; | 155 | int result; |
156 | struct rrsetinfo *fingerprints = NULL; | 156 | struct rrsetinfo *fingerprints = NULL; |
157 | int failures = 0; | ||
158 | 157 | ||
159 | u_int8_t hostkey_algorithm; | 158 | u_int8_t hostkey_algorithm; |
160 | u_int8_t hostkey_digest_type; | 159 | u_int8_t hostkey_digest_type; |
@@ -166,6 +165,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | |||
166 | u_char *dnskey_digest; | 165 | u_char *dnskey_digest; |
167 | u_int dnskey_digest_len; | 166 | u_int dnskey_digest_len; |
168 | 167 | ||
168 | *flags = 0; | ||
169 | 169 | ||
170 | debug3("verify_hostkey_dns"); | 170 | debug3("verify_hostkey_dns"); |
171 | if (hostkey == NULL) | 171 | if (hostkey == NULL) |
@@ -175,28 +175,29 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | |||
175 | DNS_RDATATYPE_SSHFP, 0, &fingerprints); | 175 | DNS_RDATATYPE_SSHFP, 0, &fingerprints); |
176 | if (result) { | 176 | if (result) { |
177 | verbose("DNS lookup error: %s", dns_result_totext(result)); | 177 | verbose("DNS lookup error: %s", dns_result_totext(result)); |
178 | return DNS_VERIFY_ERROR; | 178 | return -1; |
179 | } | 179 | } |
180 | 180 | ||
181 | #ifdef DNSSEC | 181 | if (fingerprints->rri_flags & RRSET_VALIDATED) { |
182 | /* Only accept validated answers */ | 182 | *flags |= DNS_VERIFY_SECURE; |
183 | if (!fingerprints->rri_flags & RRSET_VALIDATED) { | 183 | debug("found %d secure fingerprints in DNS", |
184 | error("Ignored unvalidated fingerprint from DNS."); | 184 | fingerprints->rri_nrdatas); |
185 | freerrset(fingerprints); | 185 | } else { |
186 | return DNS_VERIFY_ERROR; | 186 | debug("found %d insecure fingerprints in DNS", |
187 | fingerprints->rri_nrdatas); | ||
187 | } | 188 | } |
188 | #endif | ||
189 | |||
190 | debug("found %d fingerprints in DNS", fingerprints->rri_nrdatas); | ||
191 | 189 | ||
192 | /* Initialize host key parameters */ | 190 | /* Initialize host key parameters */ |
193 | if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, | 191 | if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, |
194 | &hostkey_digest, &hostkey_digest_len, hostkey)) { | 192 | &hostkey_digest, &hostkey_digest_len, hostkey)) { |
195 | error("Error calculating host key fingerprint."); | 193 | error("Error calculating host key fingerprint."); |
196 | freerrset(fingerprints); | 194 | freerrset(fingerprints); |
197 | return DNS_VERIFY_ERROR; | 195 | return -1; |
198 | } | 196 | } |
199 | 197 | ||
198 | if (fingerprints->rri_nrdatas) | ||
199 | *flags |= DNS_VERIFY_FOUND; | ||
200 | |||
200 | for (counter = 0 ; counter < fingerprints->rri_nrdatas ; counter++) { | 201 | for (counter = 0 ; counter < fingerprints->rri_nrdatas ; counter++) { |
201 | /* | 202 | /* |
202 | * Extract the key from the answer. Ignore any badly | 203 | * Extract the key from the answer. Ignore any badly |
@@ -218,35 +219,22 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | |||
218 | memcmp(hostkey_digest, dnskey_digest, | 219 | memcmp(hostkey_digest, dnskey_digest, |
219 | hostkey_digest_len) == 0) { | 220 | hostkey_digest_len) == 0) { |
220 | 221 | ||
221 | /* Matching algoritm and digest. */ | 222 | *flags |= DNS_VERIFY_MATCH; |
222 | freerrset(fingerprints); | ||
223 | debug("matching host key fingerprint found in DNS"); | ||
224 | return DNS_VERIFY_OK; | ||
225 | } else { | ||
226 | /* Correct algorithm but bad digest */ | ||
227 | debug("verify_hostkey_dns: failed"); | ||
228 | failures++; | ||
229 | } | 223 | } |
230 | } | 224 | } |
231 | } | 225 | } |
232 | 226 | ||
233 | freerrset(fingerprints); | 227 | freerrset(fingerprints); |
234 | 228 | ||
235 | if (failures) { | 229 | if (*flags & DNS_VERIFY_FOUND) |
236 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); | 230 | if (*flags & DNS_VERIFY_MATCH) |
237 | error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); | 231 | debug("matching host key fingerprint found in DNS"); |
238 | error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); | 232 | else |
239 | error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); | 233 | debug("mismatching host key fingerprint found in DNS"); |
240 | error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); | 234 | else |
241 | error("It is also possible that the %s host key has just been changed.", | 235 | debug("no host key fingerprint found in DNS"); |
242 | key_type(hostkey)); | ||
243 | error("Please contact your system administrator."); | ||
244 | return DNS_VERIFY_FAILED; | ||
245 | } | ||
246 | |||
247 | debug("fingerprints found in DNS, but none of them matched"); | ||
248 | 236 | ||
249 | return DNS_VERIFY_ERROR; | 237 | return 0; |
250 | } | 238 | } |
251 | 239 | ||
252 | 240 | ||
@@ -254,7 +242,7 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address, | |||
254 | * Export the fingerprint of a key as a DNS resource record | 242 | * Export the fingerprint of a key as a DNS resource record |
255 | */ | 243 | */ |
256 | int | 244 | int |
257 | export_dns_rr(const char *hostname, Key *key, FILE *f, int generic) | 245 | export_dns_rr(const char *hostname, const Key *key, FILE *f, int generic) |
258 | { | 246 | { |
259 | u_int8_t rdata_pubkey_algorithm = 0; | 247 | u_int8_t rdata_pubkey_algorithm = 0; |
260 | u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; | 248 | u_int8_t rdata_digest_type = SSHFP_HASH_SHA1; |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dns.h,v 1.4 2003/10/14 19:42:10 jakob Exp $ */ | 1 | /* $OpenBSD: dns.h,v 1.5 2003/11/12 16:39:58 jakob Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. | 4 | * Copyright (c) 2003 Wesley Griffin. All rights reserved. |
@@ -45,11 +45,12 @@ enum sshfp_hashes { | |||
45 | #define DNS_RDATACLASS_IN 1 | 45 | #define DNS_RDATACLASS_IN 1 |
46 | #define DNS_RDATATYPE_SSHFP 44 | 46 | #define DNS_RDATATYPE_SSHFP 44 |
47 | 47 | ||
48 | #define DNS_VERIFY_FAILED -1 | 48 | #define DNS_VERIFY_FOUND 0x00000001 |
49 | #define DNS_VERIFY_OK 0 | 49 | #define DNS_VERIFY_MATCH 0x00000002 |
50 | #define DNS_VERIFY_ERROR 1 | 50 | #define DNS_VERIFY_SECURE 0x00000004 |
51 | 51 | ||
52 | int verify_host_key_dns(const char *, struct sockaddr *, Key *); | 52 | |
53 | int export_dns_rr(const char *, Key *, FILE *, int); | 53 | int verify_host_key_dns(const char *, struct sockaddr *, const Key *, int *); |
54 | int export_dns_rr(const char *, const Key *, FILE *, int); | ||
54 | 55 | ||
55 | #endif /* DNS_H */ | 56 | #endif /* DNS_H */ |
diff --git a/readconf.c b/readconf.c index 86d28bc8d..da49a3944 100644 --- a/readconf.c +++ b/readconf.c | |||
@@ -12,7 +12,7 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include "includes.h" | 14 | #include "includes.h" |
15 | RCSID("$OpenBSD: readconf.c,v 1.124 2003/10/14 19:42:10 jakob Exp $"); | 15 | RCSID("$OpenBSD: readconf.c,v 1.125 2003/11/12 16:39:58 jakob Exp $"); |
16 | 16 | ||
17 | #include "ssh.h" | 17 | #include "ssh.h" |
18 | #include "xmalloc.h" | 18 | #include "xmalloc.h" |
@@ -401,10 +401,11 @@ parse_flag: | |||
401 | 401 | ||
402 | case oVerifyHostKeyDNS: | 402 | case oVerifyHostKeyDNS: |
403 | intptr = &options->verify_host_key_dns; | 403 | intptr = &options->verify_host_key_dns; |
404 | goto parse_flag; | 404 | goto parse_yesnoask; |
405 | 405 | ||
406 | case oStrictHostKeyChecking: | 406 | case oStrictHostKeyChecking: |
407 | intptr = &options->strict_host_key_checking; | 407 | intptr = &options->strict_host_key_checking; |
408 | parse_yesnoask: | ||
408 | arg = strdelim(&s); | 409 | arg = strdelim(&s); |
409 | if (!arg || *arg == '\0') | 410 | if (!arg || *arg == '\0') |
410 | fatal("%.200s line %d: Missing yes/no/ask argument.", | 411 | fatal("%.200s line %d: Missing yes/no/ask argument.", |
diff --git a/ssh_config.5 b/ssh_config.5 index 9073ce51f..55ca907eb 100644 --- a/ssh_config.5 +++ b/ssh_config.5 | |||
@@ -34,7 +34,7 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: ssh_config.5,v 1.23 2003/10/12 13:12:13 jmc Exp $ | 37 | .\" $OpenBSD: ssh_config.5,v 1.24 2003/11/12 16:39:58 jakob Exp $ |
38 | .Dd September 25, 1999 | 38 | .Dd September 25, 1999 |
39 | .Dt SSH_CONFIG 5 | 39 | .Dt SSH_CONFIG 5 |
40 | .Os | 40 | .Os |
@@ -642,6 +642,23 @@ host key database instead of | |||
642 | .It Cm VerifyHostKeyDNS | 642 | .It Cm VerifyHostKeyDNS |
643 | Specifies whether to verify the remote key using DNS and SSHFP resource | 643 | Specifies whether to verify the remote key using DNS and SSHFP resource |
644 | records. | 644 | records. |
645 | If this option is set to | ||
646 | .Dq yes , | ||
647 | the client will implicitly trust keys that matches a secure fingerprint | ||
648 | from DNS. | ||
649 | Insecure fingerprints will be handled as if this option was set to | ||
650 | .Dq ask . | ||
651 | If this option is set to | ||
652 | .Dq ask , | ||
653 | information on fingerprint match will be displayed, but the user will still | ||
654 | need to confirm new host keys according to the | ||
655 | .Cm StrictHostKeyChecking | ||
656 | option. | ||
657 | The argument must be | ||
658 | .Dq yes , | ||
659 | .Dq no | ||
660 | or | ||
661 | .Dq ask . | ||
645 | The default is | 662 | The default is |
646 | .Dq no . | 663 | .Dq no . |
647 | Note that this option applies to protocol version 2 only. | 664 | Note that this option applies to protocol version 2 only. |
diff --git a/sshconnect.c b/sshconnect.c index bf8c23d73..5972e2ba9 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -13,7 +13,7 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include "includes.h" | 15 | #include "includes.h" |
16 | RCSID("$OpenBSD: sshconnect.c,v 1.152 2003/11/10 16:23:41 jakob Exp $"); | 16 | RCSID("$OpenBSD: sshconnect.c,v 1.153 2003/11/12 16:39:58 jakob Exp $"); |
17 | 17 | ||
18 | #include <openssl/bn.h> | 18 | #include <openssl/bn.h> |
19 | 19 | ||
@@ -38,7 +38,7 @@ RCSID("$OpenBSD: sshconnect.c,v 1.152 2003/11/10 16:23:41 jakob Exp $"); | |||
38 | char *client_version_string = NULL; | 38 | char *client_version_string = NULL; |
39 | char *server_version_string = NULL; | 39 | char *server_version_string = NULL; |
40 | 40 | ||
41 | int verified_host_key_dns = 0; | 41 | int matching_host_key_dns = 0; |
42 | 42 | ||
43 | /* import */ | 43 | /* import */ |
44 | extern Options options; | 44 | extern Options options; |
@@ -728,7 +728,7 @@ check_host_key(char *host, struct sockaddr *hostaddr, Key *host_key, | |||
728 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); | 728 | fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); |
729 | msg2[0] = '\0'; | 729 | msg2[0] = '\0'; |
730 | if (options.verify_host_key_dns) { | 730 | if (options.verify_host_key_dns) { |
731 | if (verified_host_key_dns) | 731 | if (matching_host_key_dns) |
732 | snprintf(msg2, sizeof(msg2), | 732 | snprintf(msg2, sizeof(msg2), |
733 | "Matching host key fingerprint" | 733 | "Matching host key fingerprint" |
734 | " found in DNS.\n"); | 734 | " found in DNS.\n"); |
@@ -892,23 +892,25 @@ int | |||
892 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 892 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) |
893 | { | 893 | { |
894 | struct stat st; | 894 | struct stat st; |
895 | int flags = 0; | ||
895 | 896 | ||
896 | if (options.verify_host_key_dns) { | 897 | if (options.verify_host_key_dns && |
897 | switch(verify_host_key_dns(host, hostaddr, host_key)) { | 898 | verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { |
898 | case DNS_VERIFY_OK: | 899 | |
899 | #ifdef DNSSEC | 900 | if (flags & DNS_VERIFY_FOUND) { |
900 | return 0; | 901 | |
901 | #else | 902 | if (options.verify_host_key_dns == 1 && |
902 | verified_host_key_dns = 1; | 903 | flags & DNS_VERIFY_MATCH && |
903 | break; | 904 | flags & DNS_VERIFY_SECURE) |
904 | #endif | 905 | return 0; |
905 | case DNS_VERIFY_FAILED: | 906 | |
906 | return -1; | 907 | if (flags & DNS_VERIFY_MATCH) { |
907 | case DNS_VERIFY_ERROR: | 908 | matching_host_key_dns = 1; |
908 | break; | 909 | } else { |
909 | default: | 910 | warn_changed_key(host_key); |
910 | debug3("bad return value from verify_host_key_dns"); | 911 | error("Update the SSHFP RR in DNS with the new " |
911 | break; | 912 | "host key to get rid of this message."); |
913 | } | ||
912 | } | 914 | } |
913 | } | 915 | } |
914 | 916 | ||