summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--dns.c68
-rw-r--r--dns.h13
-rw-r--r--readconf.c5
-rw-r--r--ssh_config.519
-rw-r--r--sshconnect.c40
6 files changed, 81 insertions, 69 deletions
diff --git a/ChangeLog b/ChangeLog
index 40a393109..b5667e79a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
3520031115 3820031115
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 $
diff --git a/dns.c b/dns.c
index 2fff1b802..2342b6609 100644
--- a/dns.c
+++ b/dns.c
@@ -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
45extern char *__progname; 45extern char *__progname;
46RCSID("$OpenBSD: dns.c,v 1.7 2003/10/14 19:42:10 jakob Exp $"); 46RCSID("$OpenBSD: dns.c,v 1.8 2003/11/12 16:39:58 jakob Exp $");
47 47
48#ifndef LWRES 48#ifndef LWRES
49static const char *errset_text[] = { 49static const char *errset_text[] = {
@@ -83,7 +83,7 @@ dns_result_totext(unsigned int error)
83 */ 83 */
84static int 84static int
85dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, 85dns_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 */
150int 150int
151verify_host_key_dns(const char *hostname, struct sockaddr *address, 151verify_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 */
256int 244int
257export_dns_rr(const char *hostname, Key *key, FILE *f, int generic) 245export_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;
diff --git a/dns.h b/dns.h
index 1eb07d96e..c5da22ef6 100644
--- a/dns.h
+++ b/dns.h
@@ -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
52int verify_host_key_dns(const char *, struct sockaddr *, Key *); 52
53int export_dns_rr(const char *, Key *, FILE *, int); 53int verify_host_key_dns(const char *, struct sockaddr *, const Key *, int *);
54int 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"
15RCSID("$OpenBSD: readconf.c,v 1.124 2003/10/14 19:42:10 jakob Exp $"); 15RCSID("$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;
408parse_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
643Specifies whether to verify the remote key using DNS and SSHFP resource 643Specifies whether to verify the remote key using DNS and SSHFP resource
644records. 644records.
645If this option is set to
646.Dq yes ,
647the client will implicitly trust keys that matches a secure fingerprint
648from DNS.
649Insecure fingerprints will be handled as if this option was set to
650.Dq ask .
651If this option is set to
652.Dq ask ,
653information on fingerprint match will be displayed, but the user will still
654need to confirm new host keys according to the
655.Cm StrictHostKeyChecking
656option.
657The argument must be
658.Dq yes ,
659.Dq no
660or
661.Dq ask .
645The default is 662The default is
646.Dq no . 663.Dq no .
647Note that this option applies to protocol version 2 only. 664Note 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"
16RCSID("$OpenBSD: sshconnect.c,v 1.152 2003/11/10 16:23:41 jakob Exp $"); 16RCSID("$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 $");
38char *client_version_string = NULL; 38char *client_version_string = NULL;
39char *server_version_string = NULL; 39char *server_version_string = NULL;
40 40
41int verified_host_key_dns = 0; 41int matching_host_key_dns = 0;
42 42
43/* import */ 43/* import */
44extern Options options; 44extern 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
892verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 892verify_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