summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Makefile.in8
-rw-r--r--README.dns55
-rw-r--r--dns.c293
-rw-r--r--dns.h57
-rw-r--r--key.c4
-rw-r--r--key.h3
-rw-r--r--readconf.c12
-rw-r--r--readconf.h3
-rw-r--r--ssh-keygen.111
-rw-r--r--ssh-keygen.c55
-rw-r--r--ssh_config.57
-rw-r--r--sshconnect.c23
13 files changed, 523 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 8ad7108a6..8feae8b23 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,12 @@
4 [ssh-agent.1] 4 [ssh-agent.1]
5 setup -> set up; 5 setup -> set up;
6 from wiz@netbsd 6 from wiz@netbsd
7 - jakob@cvs.openbsd.org 2003/05/14 18:16:20
8 [key.c key.h readconf.c readconf.h ssh_config.5 sshconnect.c]
9 [dns.c dns.h README.dns ssh-keygen.1 ssh-keygen.c]
10 add experimental support for verifying hos keys using DNS as described
11 in draft-ietf-secsh-dns-xx.txt. more information in README.dns.
12 ok markus@ and henning@
7 13
820030514 1420030514
9 - (djm) Bug #117: Don't lie to PAM about username 15 - (djm) Bug #117: Don't lie to PAM about username
@@ -1479,4 +1485,4 @@
1479 save auth method before monitor_reset_key_state(); bugzilla bug #284; 1485 save auth method before monitor_reset_key_state(); bugzilla bug #284;
1480 ok provos@ 1486 ok provos@
1481 1487
1482$Id: ChangeLog,v 1.2701 2003/05/15 00:16:21 djm Exp $ 1488$Id: ChangeLog,v 1.2702 2003/05/15 00:19:46 djm Exp $
diff --git a/Makefile.in b/Makefile.in
index ba898db40..f25fe0ae5 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,4 +1,4 @@
1# $Id: Makefile.in,v 1.232 2003/05/14 04:31:11 djm Exp $ 1# $Id: Makefile.in,v 1.233 2003/05/15 00:19:46 djm Exp $
2 2
3# uncomment if you run a non bourne compatable shell. Ie. csh 3# uncomment if you run a non bourne compatable shell. Ie. csh
4#SHELL = @SH@ 4#SHELL = @SH@
@@ -62,11 +62,11 @@ TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keys
62 62
63LIBSSH_OBJS=authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o \ 63LIBSSH_OBJS=authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o \
64 cipher.o compat.o compress.o crc32.o deattack.o fatal.o \ 64 cipher.o compat.o compress.o crc32.o deattack.o fatal.o \
65 hostfile.o log.o match.o mpaux.o nchan.o packet.o radix.o readpass.o \ 65 hostfile.o log.o match.o mpaux.o nchan.o packet.o radix.o \
66 rsa.o tildexpand.o ttymodes.o xmalloc.o atomicio.o \ 66 readpass.o rsa.o tildexpand.o ttymodes.o xmalloc.o atomicio.o \
67 key.o dispatch.o kex.o mac.o uuencode.o misc.o \ 67 key.o dispatch.o kex.o mac.o uuencode.o misc.o \
68 rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o kexgex.o \ 68 rijndael.o ssh-dss.o ssh-rsa.o dh.o kexdh.o kexgex.o \
69 kexdhc.o kexgexc.o scard.o msg.o progressmeter.o \ 69 kexdhc.o kexgexc.o scard.o msg.o progressmeter.o dns.o \
70 entropy.o 70 entropy.o
71 71
72SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ 72SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
diff --git a/README.dns b/README.dns
new file mode 100644
index 000000000..d6889b9a5
--- /dev/null
+++ b/README.dns
@@ -0,0 +1,55 @@
1How to verify host keys using OpenSSH and DNS
2---------------------------------------------
3
4OpenSSH contains experimental support for verifying host keys using DNS
5as described in draft-ietf-secsh-dns-xx.txt. The document contains
6very brief instructions on how to test this feature. Configuring DNS
7and DNSSEC is out of the scope of this document.
8
9
10(1) Enable DNS fingerprint support in OpenSSH
11
12Edit /usr/src/usr.bin/ssh/Makefile.inc and uncomment the line containing
13
14 CFLAGS+= -DDNS
15
16
17(2) Generate and publish the DNS RR
18
19To create a DNS resource record (RR) containing a fingerprint of the
20public host key, use the following command:
21
22 ssh-keygen -r hostname -f keyfile -g
23
24where "hostname" is your fully qualified hostname and "keyfile" is the
25file containing the public host key file. If you have multiple keys,
26you should generate one RR for each key.
27
28In the example above, ssh-keygen will print the fingerprint in a
29generic DNS RR format parsable by most modern name server
30implementations. If your nameserver has support for the SSHFP RR, as
31defined by the draft, you can omit the -g flag and ssh-keygen will
32print a standard RR.
33
34To publish the fingerprint using the DNS you must add the generated RR
35to your DNS zone file and sign your zone.
36
37
38(3) Enable the ssh client to verify host keys using DNS
39
40To enable the ssh client to verify host keys using DNS, you have to
41add the following option to the ssh configuration file
42($HOME/.ssh/config or /etc/ssh/ssh_config):
43
44 VerifyHostKeyDNS yes
45
46Upon connection the client will try to look up the fingerprint RR
47using DNS. If the fingerprint received from the DNS server matches
48the remote host key, the user will be notified.
49
50
51 Jakob Schlyter
52 Wesley Griffin
53
54
55$OpenBSD: README.dns,v 1.1 2003/05/14 18:16:20 jakob Exp $
diff --git a/dns.c b/dns.c
new file mode 100644
index 000000000..9b7a0e7a0
--- /dev/null
+++ b/dns.c
@@ -0,0 +1,293 @@
1/* $OpenBSD: dns.c,v 1.4 2003/05/14 23:29:22 jakob Exp $ */
2
3/*
4 * Copyright (c) 2003 Wesley Griffin. All rights reserved.
5 * Copyright (c) 2003 Jakob Schlyter. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29#include "includes.h"
30
31#ifdef DNS
32#include <openssl/bn.h>
33#ifdef LWRES
34#include <lwres/netdb.h>
35#include <dns/result.h>
36#else /* LWRES */
37#include <netdb.h>
38#endif /* LWRES */
39
40#include "xmalloc.h"
41#include "key.h"
42#include "dns.h"
43#include "log.h"
44#include "uuencode.h"
45
46extern char *__progname;
47RCSID("$OpenBSD: dns.c,v 1.4 2003/05/14 23:29:22 jakob Exp $");
48
49#ifndef LWRES
50static const char *errset_text[] = {
51 "success", /* 0 ERRSET_SUCCESS */
52 "out of memory", /* 1 ERRSET_NOMEMORY */
53 "general failure", /* 2 ERRSET_FAIL */
54 "invalid parameter", /* 3 ERRSET_INVAL */
55 "name does not exist", /* 4 ERRSET_NONAME */
56 "data does not exist", /* 5 ERRSET_NODATA */
57};
58
59static const char *
60dns_result_totext(unsigned int error)
61{
62 switch (error) {
63 case ERRSET_SUCCESS:
64 return errset_text[ERRSET_SUCCESS];
65 case ERRSET_NOMEMORY:
66 return errset_text[ERRSET_NOMEMORY];
67 case ERRSET_FAIL:
68 return errset_text[ERRSET_FAIL];
69 case ERRSET_INVAL:
70 return errset_text[ERRSET_INVAL];
71 case ERRSET_NONAME:
72 return errset_text[ERRSET_NONAME];
73 case ERRSET_NODATA:
74 return errset_text[ERRSET_NODATA];
75 default:
76 return "unknown error";
77 }
78}
79#endif /* LWRES */
80
81
82/*
83 * Read SSHFP parameters from key buffer.
84 */
85static int
86dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
87 u_char **digest, u_int *digest_len, Key *key)
88{
89 int success = 0;
90
91 switch (key->type) {
92 case KEY_RSA:
93 *algorithm = SSHFP_KEY_RSA;
94 break;
95 case KEY_DSA:
96 *algorithm = SSHFP_KEY_DSA;
97 break;
98 default:
99 *algorithm = SSHFP_KEY_RESERVED;
100 }
101
102 if (*algorithm) {
103 *digest_type = SSHFP_HASH_SHA1;
104 *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len);
105 success = 1;
106 } else {
107 *digest_type = SSHFP_HASH_RESERVED;
108 *digest = NULL;
109 *digest_len = 0;
110 success = 0;
111 }
112
113 return success;
114}
115
116/*
117 * Read SSHFP parameters from rdata buffer.
118 */
119static int
120dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
121 u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len)
122{
123 int success = 0;
124
125 *algorithm = SSHFP_KEY_RESERVED;
126 *digest_type = SSHFP_HASH_RESERVED;
127
128 if (rdata_len >= 2) {
129 *algorithm = rdata[0];
130 *digest_type = rdata[1];
131 *digest_len = rdata_len - 2;
132
133 if (*digest_len > 0) {
134 *digest = (u_char *) xmalloc(*digest_len);
135 memcpy(*digest, rdata + 2, *digest_len);
136 } else {
137 *digest = NULL;
138 }
139
140 success = 1;
141 }
142
143 return success;
144}
145
146
147/*
148 * Verify the given hostname, address and host key using DNS.
149 * Returns 0 if key verifies or -1 if key does NOT verify
150 */
151int
152verify_host_key_dns(const char *hostname, struct sockaddr *address,
153 Key *hostkey)
154{
155 int counter;
156 int result;
157 struct rrsetinfo *fingerprints = NULL;
158 int failures = 0;
159
160 u_int8_t hostkey_algorithm;
161 u_int8_t hostkey_digest_type;
162 u_char *hostkey_digest;
163 u_int hostkey_digest_len;
164
165 u_int8_t dnskey_algorithm;
166 u_int8_t dnskey_digest_type;
167 u_char *dnskey_digest;
168 u_int dnskey_digest_len;
169
170
171 debug3("verify_hostkey_dns");
172 if (hostkey == NULL)
173 fatal("No key to look up!");
174
175 result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
176 DNS_RDATATYPE_SSHFP, 0, &fingerprints);
177 if (result) {
178 verbose("DNS lookup error: %s", dns_result_totext(result));
179 return DNS_VERIFY_ERROR;
180 }
181
182#ifdef DNSSEC
183 /* Only accept validated answers */
184 if (!fingerprints->rri_flags & RRSET_VALIDATED) {
185 error("Ignored unvalidated fingerprint from DNS.");
186 return DNS_VERIFY_ERROR;
187 }
188#endif
189
190 debug("found %d fingerprints in DNS", fingerprints->rri_nrdatas);
191
192 /* Initialize host key parameters */
193 if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
194 &hostkey_digest, &hostkey_digest_len, hostkey)) {
195 error("Error calculating host key fingerprint.");
196 return DNS_VERIFY_ERROR;
197 }
198
199 for (counter = 0 ; counter < fingerprints->rri_nrdatas ; counter++) {
200 /*
201 * Extract the key from the answer. Ignore any badly
202 * formatted fingerprints.
203 */
204 if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
205 &dnskey_digest, &dnskey_digest_len,
206 fingerprints->rri_rdatas[counter].rdi_data,
207 fingerprints->rri_rdatas[counter].rdi_length)) {
208 verbose("Error parsing fingerprint from DNS.");
209 continue;
210 }
211
212 /* Check if the current key is the same as the given key */
213 if (hostkey_algorithm == dnskey_algorithm &&
214 hostkey_digest_type == dnskey_digest_type) {
215
216 if (hostkey_digest_len == dnskey_digest_len &&
217 memcmp(hostkey_digest, dnskey_digest,
218 hostkey_digest_len) == 0) {
219
220 /* Matching algoritm and digest. */
221 freerrset(fingerprints);
222#ifdef DNSSEC
223 debug("matching host key fingerprint found in DNS");
224 return DNS_VERIFY_OK;
225#else
226 logit("Matching host key fingerprint found in DNS.");
227 return DNS_VERIFY_ERROR;
228#endif
229 } else {
230 /* Correct algorithm but bad digest */
231 debug("verify_hostkey_dns: failed");
232 failures++;
233 }
234 }
235 }
236
237 freerrset(fingerprints);
238
239 if (failures) {
240 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
241 error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
242 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
243 error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
244 error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
245 error("It is also possible that the %s host key has just been changed.",
246 key_type(hostkey));
247 error("Please contact your system administrator.");
248 return DNS_VERIFY_FAILED;
249 }
250
251 debug("fingerprints found in DNS, but none of them matched");
252
253 return DNS_VERIFY_ERROR;
254}
255
256
257/*
258 * Export the fingerprint of a key as a DNS resource record
259 */
260int
261export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
262{
263 u_int8_t rdata_pubkey_algorithm = 0;
264 u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;
265 u_char *rdata_digest;
266 u_int rdata_digest_len;
267
268 int i;
269 int success = 0;
270
271 if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
272 &rdata_digest, &rdata_digest_len, key)) {
273
274 if (generic)
275 fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname,
276 DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len,
277 rdata_pubkey_algorithm, rdata_digest_type);
278 else
279 fprintf(f, "%s IN SSHFP %d %d ", hostname,
280 rdata_pubkey_algorithm, rdata_digest_type);
281
282 for (i = 0; i < rdata_digest_len; i++)
283 fprintf(f, "%02x", rdata_digest[i]);
284 fprintf(f, "\n");
285 success = 1;
286 } else {
287 error("dns_export_rr: unsupported algorithm");
288 }
289
290 return success;
291}
292
293#endif /* DNS */
diff --git a/dns.h b/dns.h
new file mode 100644
index 000000000..ba0ea9fb4
--- /dev/null
+++ b/dns.h
@@ -0,0 +1,57 @@
1/* $OpenBSD: dns.h,v 1.3 2003/05/14 22:56:51 jakob Exp $ */
2
3/*
4 * Copyright (c) 2003 Wesley Griffin. All rights reserved.
5 * Copyright (c) 2003 Jakob Schlyter. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28
29#include "includes.h"
30
31#ifdef DNS
32#ifndef DNS_H
33#define DNS_H
34
35enum sshfp_types {
36 SSHFP_KEY_RESERVED,
37 SSHFP_KEY_RSA,
38 SSHFP_KEY_DSA
39};
40
41enum sshfp_hashes {
42 SSHFP_HASH_RESERVED,
43 SSHFP_HASH_SHA1
44};
45
46#define DNS_RDATACLASS_IN 1
47#define DNS_RDATATYPE_SSHFP 44
48
49#define DNS_VERIFY_FAILED -1
50#define DNS_VERIFY_OK 0
51#define DNS_VERIFY_ERROR 1
52
53int verify_host_key_dns(const char *, struct sockaddr *, Key *);
54int export_dns_rr(const char *, Key *, FILE *, int);
55
56#endif /* DNS_H */
57#endif /* DNS */
diff --git a/key.c b/key.c
index 060b63745..d918cfd0a 100644
--- a/key.c
+++ b/key.c
@@ -32,7 +32,7 @@
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */ 33 */
34#include "includes.h" 34#include "includes.h"
35RCSID("$OpenBSD: key.c,v 1.51 2003/02/12 09:33:04 markus Exp $"); 35RCSID("$OpenBSD: key.c,v 1.52 2003/05/14 18:16:20 jakob Exp $");
36 36
37#include <openssl/evp.h> 37#include <openssl/evp.h>
38 38
@@ -169,7 +169,7 @@ key_equal(Key *a, Key *b)
169 return 0; 169 return 0;
170} 170}
171 171
172static u_char * 172u_char*
173key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) 173key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
174{ 174{
175 const EVP_MD *md = NULL; 175 const EVP_MD *md = NULL;
diff --git a/key.h b/key.h
index 725c7a04a..a7b6afe86 100644
--- a/key.h
+++ b/key.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: key.h,v 1.20 2003/02/12 09:33:04 markus Exp $ */ 1/* $OpenBSD: key.h,v 1.21 2003/05/14 18:16:20 jakob Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -61,6 +61,7 @@ void key_free(Key *);
61Key *key_demote(Key *); 61Key *key_demote(Key *);
62int key_equal(Key *, Key *); 62int key_equal(Key *, Key *);
63char *key_fingerprint(Key *, enum fp_type, enum fp_rep); 63char *key_fingerprint(Key *, enum fp_type, enum fp_rep);
64u_char *key_fingerprint_raw(Key *, enum fp_type, u_int *);
64char *key_type(Key *); 65char *key_type(Key *);
65int key_write(Key *, FILE *); 66int key_write(Key *, FILE *);
66int key_read(Key *, char **); 67int key_read(Key *, char **);
diff --git a/readconf.c b/readconf.c
index acdf128f6..c9c463b29 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.106 2003/04/09 12:00:37 djm Exp $"); 15RCSID("$OpenBSD: readconf.c,v 1.107 2003/05/14 18:16:20 jakob Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "xmalloc.h" 18#include "xmalloc.h"
@@ -114,7 +114,7 @@ typedef enum {
114 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication, 114 oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
115 oHostKeyAlgorithms, oBindAddress, oSmartcardDevice, 115 oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
116 oClearAllForwardings, oNoHostAuthenticationForLocalhost, 116 oClearAllForwardings, oNoHostAuthenticationForLocalhost,
117 oEnableSSHKeysign, oRekeyLimit, 117 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS,
118 oDeprecated 118 oDeprecated
119} OpCodes; 119} OpCodes;
120 120
@@ -187,6 +187,7 @@ static struct {
187 { "smartcarddevice", oSmartcardDevice }, 187 { "smartcarddevice", oSmartcardDevice },
188 { "clearallforwardings", oClearAllForwardings }, 188 { "clearallforwardings", oClearAllForwardings },
189 { "enablesshkeysign", oEnableSSHKeysign }, 189 { "enablesshkeysign", oEnableSSHKeysign },
190 { "verifyhostkeydns", oVerifyHostKeyDNS },
190 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost }, 191 { "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
191 { "rekeylimit", oRekeyLimit }, 192 { "rekeylimit", oRekeyLimit },
192 { NULL, oBadOption } 193 { NULL, oBadOption }
@@ -392,6 +393,10 @@ parse_flag:
392 intptr = &options->check_host_ip; 393 intptr = &options->check_host_ip;
393 goto parse_flag; 394 goto parse_flag;
394 395
396 case oVerifyHostKeyDNS:
397 intptr = &options->verify_host_key_dns;
398 goto parse_flag;
399
395 case oStrictHostKeyChecking: 400 case oStrictHostKeyChecking:
396 intptr = &options->strict_host_key_checking; 401 intptr = &options->strict_host_key_checking;
397 arg = strdelim(&s); 402 arg = strdelim(&s);
@@ -829,6 +834,7 @@ initialize_options(Options * options)
829 options->enable_ssh_keysign = - 1; 834 options->enable_ssh_keysign = - 1;
830 options->no_host_authentication_for_localhost = - 1; 835 options->no_host_authentication_for_localhost = - 1;
831 options->rekey_limit = - 1; 836 options->rekey_limit = - 1;
837 options->verify_host_key_dns = -1;
832} 838}
833 839
834/* 840/*
@@ -947,6 +953,8 @@ fill_default_options(Options * options)
947 options->enable_ssh_keysign = 0; 953 options->enable_ssh_keysign = 0;
948 if (options->rekey_limit == -1) 954 if (options->rekey_limit == -1)
949 options->rekey_limit = 0; 955 options->rekey_limit = 0;
956 if (options->verify_host_key_dns == -1)
957 options->verify_host_key_dns = 0;
950 /* options->proxy_command should not be set by default */ 958 /* options->proxy_command should not be set by default */
951 /* options->user will be set in the main program if appropriate */ 959 /* options->user will be set in the main program if appropriate */
952 /* options->hostname will be set in the main program if appropriate */ 960 /* options->hostname will be set in the main program if appropriate */
diff --git a/readconf.h b/readconf.h
index d35472117..d141b8c00 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.47 2003/04/02 09:48:07 markus Exp $ */ 1/* $OpenBSD: readconf.h,v 1.48 2003/05/14 18:16:20 jakob Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -86,6 +86,7 @@ typedef struct {
86 char *preferred_authentications; 86 char *preferred_authentications;
87 char *bind_address; /* local socket address for connection to sshd */ 87 char *bind_address; /* local socket address for connection to sshd */
88 char *smartcard_device; /* Smartcard reader device */ 88 char *smartcard_device; /* Smartcard reader device */
89 int verify_host_key_dns; /* Verify host key using DNS */
89 90
90 int num_identity_files; /* Number of files for RSA/DSA identities. */ 91 int num_identity_files; /* Number of files for RSA/DSA identities. */
91 char *identity_files[SSH_MAX_IDENTITY_FILES]; 92 char *identity_files[SSH_MAX_IDENTITY_FILES];
diff --git a/ssh-keygen.1 b/ssh-keygen.1
index 000e8ff2a..613d71a07 100644
--- a/ssh-keygen.1
+++ b/ssh-keygen.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: ssh-keygen.1,v 1.56 2003/03/28 10:11:43 jmc Exp $ 1.\" $OpenBSD: ssh-keygen.1,v 1.57 2003/05/14 18:16:20 jakob Exp $
2.\" 2.\"
3.\" -*- nroff -*- 3.\" -*- nroff -*-
4.\" 4.\"
@@ -83,6 +83,10 @@
83.Nm ssh-keygen 83.Nm ssh-keygen
84.Fl U Ar reader 84.Fl U Ar reader
85.Op Fl f Ar input_keyfile 85.Op Fl f Ar input_keyfile
86.Nm ssh-keygen
87.Fl r Ar hostname
88.Op Fl f Ar input_keyfile
89.Op Fl g
86.Sh DESCRIPTION 90.Sh DESCRIPTION
87.Nm 91.Nm
88generates, manages and converts authentication keys for 92generates, manages and converts authentication keys for
@@ -163,6 +167,8 @@ print the key in a
163to stdout. 167to stdout.
164This option allows exporting keys for use by several commercial 168This option allows exporting keys for use by several commercial
165SSH implementations. 169SSH implementations.
170.It Fl g
171Use generic DNS resource record format.
166.It Fl f Ar filename 172.It Fl f Ar filename
167Specifies the filename of the key file. 173Specifies the filename of the key file.
168.It Fl i 174.It Fl i
@@ -218,6 +224,9 @@ Provides the (old) passphrase.
218.It Fl U Ar reader 224.It Fl U Ar reader
219Upload an existing RSA private key into the smartcard in 225Upload an existing RSA private key into the smartcard in
220.Ar reader . 226.Ar reader .
227.It Fl r Ar hostname
228Print DNS resource record with the specified
229.Ar hostname .
221.El 230.El
222.Sh FILES 231.Sh FILES
223.Bl -tag -width Ds 232.Bl -tag -width Ds
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 1d08c7cec..f3ea4f1fd 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$OpenBSD: ssh-keygen.c,v 1.104 2003/05/11 16:56:48 markus Exp $"); 15RCSID("$OpenBSD: ssh-keygen.c,v 1.105 2003/05/14 18:16:20 jakob Exp $");
16 16
17#include <openssl/evp.h> 17#include <openssl/evp.h>
18#include <openssl/pem.h> 18#include <openssl/pem.h>
@@ -70,6 +70,7 @@ char *identity_comment = NULL;
70int convert_to_ssh2 = 0; 70int convert_to_ssh2 = 0;
71int convert_from_ssh2 = 0; 71int convert_from_ssh2 = 0;
72int print_public = 0; 72int print_public = 0;
73int print_generic = 0;
73 74
74char *key_type_name = NULL; 75char *key_type_name = NULL;
75 76
@@ -620,6 +621,38 @@ do_change_passphrase(struct passwd *pw)
620 exit(0); 621 exit(0);
621} 622}
622 623
624#ifdef DNS
625/*
626 * Print the SSHFP RR.
627 */
628static void
629do_print_resource_record(struct passwd *pw, char *hostname)
630{
631 Key *public;
632 char *comment = NULL;
633 struct stat st;
634
635 if (!have_identity)
636 ask_filename(pw, "Enter file in which the key is");
637 if (stat(identity_file, &st) < 0) {
638 perror(identity_file);
639 exit(1);
640 }
641 public = key_load_public(identity_file, &comment);
642 if (public != NULL) {
643 export_dns_rr(hostname, public, stdout, print_generic);
644 key_free(public);
645 xfree(comment);
646 exit(0);
647 }
648 if (comment)
649 xfree(comment);
650
651 printf("failed to read v2 public key from %s.\n", identity_file);
652 exit(1);
653}
654#endif /* DNS */
655
623/* 656/*
624 * Change the comment of a private key file. 657 * Change the comment of a private key file.
625 */ 658 */
@@ -726,6 +759,7 @@ usage(void)
726 fprintf(stderr, " -c Change comment in private and public key files.\n"); 759 fprintf(stderr, " -c Change comment in private and public key files.\n");
727 fprintf(stderr, " -e Convert OpenSSH to IETF SECSH key file.\n"); 760 fprintf(stderr, " -e Convert OpenSSH to IETF SECSH key file.\n");
728 fprintf(stderr, " -f filename Filename of the key file.\n"); 761 fprintf(stderr, " -f filename Filename of the key file.\n");
762 fprintf(stderr, " -g Use generic DNS resource record format.\n");
729 fprintf(stderr, " -i Convert IETF SECSH to OpenSSH key file.\n"); 763 fprintf(stderr, " -i Convert IETF SECSH to OpenSSH key file.\n");
730 fprintf(stderr, " -l Show fingerprint of key file.\n"); 764 fprintf(stderr, " -l Show fingerprint of key file.\n");
731 fprintf(stderr, " -p Change passphrase of private key file.\n"); 765 fprintf(stderr, " -p Change passphrase of private key file.\n");
@@ -736,6 +770,9 @@ usage(void)
736 fprintf(stderr, " -C comment Provide new comment.\n"); 770 fprintf(stderr, " -C comment Provide new comment.\n");
737 fprintf(stderr, " -N phrase Provide new passphrase.\n"); 771 fprintf(stderr, " -N phrase Provide new passphrase.\n");
738 fprintf(stderr, " -P phrase Provide old passphrase.\n"); 772 fprintf(stderr, " -P phrase Provide old passphrase.\n");
773#ifdef DNS
774 fprintf(stderr, " -r hostname Print DNS resource record.\n");
775#endif /* DNS */
739#ifdef SMARTCARD 776#ifdef SMARTCARD
740 fprintf(stderr, " -D reader Download public key from smartcard.\n"); 777 fprintf(stderr, " -D reader Download public key from smartcard.\n");
741 fprintf(stderr, " -U reader Upload private key to smartcard.\n"); 778 fprintf(stderr, " -U reader Upload private key to smartcard.\n");
@@ -752,6 +789,7 @@ main(int ac, char **av)
752{ 789{
753 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2; 790 char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
754 char *reader_id = NULL; 791 char *reader_id = NULL;
792 char *resource_record_hostname = NULL;
755 Key *private, *public; 793 Key *private, *public;
756 struct passwd *pw; 794 struct passwd *pw;
757 struct stat st; 795 struct stat st;
@@ -778,7 +816,7 @@ main(int ac, char **av)
778 exit(1); 816 exit(1);
779 } 817 }
780 818
781 while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:U:D:P:N:C:")) != -1) { 819 while ((opt = getopt(ac, av, "degiqpclBRxXyb:f:t:U:D:P:N:C:r:")) != -1) {
782 switch (opt) { 820 switch (opt) {
783 case 'b': 821 case 'b':
784 bits = atoi(optarg); 822 bits = atoi(optarg);
@@ -803,6 +841,9 @@ main(int ac, char **av)
803 strlcpy(identity_file, optarg, sizeof(identity_file)); 841 strlcpy(identity_file, optarg, sizeof(identity_file));
804 have_identity = 1; 842 have_identity = 1;
805 break; 843 break;
844 case 'g':
845 print_generic = 1;
846 break;
806 case 'P': 847 case 'P':
807 identity_passphrase = optarg; 848 identity_passphrase = optarg;
808 break; 849 break;
@@ -843,6 +884,9 @@ main(int ac, char **av)
843 case 'U': 884 case 'U':
844 reader_id = optarg; 885 reader_id = optarg;
845 break; 886 break;
887 case 'r':
888 resource_record_hostname = optarg;
889 break;
846 case '?': 890 case '?':
847 default: 891 default:
848 usage(); 892 usage();
@@ -868,6 +912,13 @@ main(int ac, char **av)
868 do_convert_from_ssh2(pw); 912 do_convert_from_ssh2(pw);
869 if (print_public) 913 if (print_public)
870 do_print_public(pw); 914 do_print_public(pw);
915 if (resource_record_hostname != NULL) {
916#ifdef DNS
917 do_print_resource_record(pw, resource_record_hostname);
918#else /* DNS */
919 fatal("no DNS support.");
920#endif /* DNS */
921 }
871 if (reader_id != NULL) { 922 if (reader_id != NULL) {
872#ifdef SMARTCARD 923#ifdef SMARTCARD
873 if (download) 924 if (download)
diff --git a/ssh_config.5 b/ssh_config.5
index 44208b431..2f33aa3f3 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.7 2003/03/28 10:11:43 jmc Exp $ 37.\" $OpenBSD: ssh_config.5,v 1.8 2003/05/14 18:16:20 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
@@ -618,6 +618,11 @@ having to remember to give the user name on the command line.
618Specifies a file to use for the user 618Specifies a file to use for the user
619host key database instead of 619host key database instead of
620.Pa $HOME/.ssh/known_hosts . 620.Pa $HOME/.ssh/known_hosts .
621.It Cm VerifyHostKeyDNS
622Specifies whether to verify the remote key using DNS and SSHFP resource
623records.
624The default is
625.Dq no .
621.It Cm XAuthLocation 626.It Cm XAuthLocation
622Specifies the full pathname of the 627Specifies the full pathname of the
623.Xr xauth 1 628.Xr xauth 1
diff --git a/sshconnect.c b/sshconnect.c
index 33d9c727f..32bef7d07 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.139 2003/04/14 14:17:50 markus Exp $"); 16RCSID("$OpenBSD: sshconnect.c,v 1.140 2003/05/14 18:16:21 jakob Exp $");
17 17
18#include <openssl/bn.h> 18#include <openssl/bn.h>
19 19
@@ -33,6 +33,10 @@ RCSID("$OpenBSD: sshconnect.c,v 1.139 2003/04/14 14:17:50 markus Exp $");
33#include "misc.h" 33#include "misc.h"
34#include "readpass.h" 34#include "readpass.h"
35 35
36#ifdef DNS
37#include "dns.h"
38#endif
39
36char *client_version_string = NULL; 40char *client_version_string = NULL;
37char *server_version_string = NULL; 41char *server_version_string = NULL;
38 42
@@ -797,11 +801,28 @@ fail:
797 return -1; 801 return -1;
798} 802}
799 803
804/* returns 0 if key verifies or -1 if key does NOT verify */
800int 805int
801verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) 806verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
802{ 807{
803 struct stat st; 808 struct stat st;
804 809
810#ifdef DNS
811 if (options.verify_host_key_dns) {
812 switch(verify_host_key_dns(host, hostaddr, host_key)) {
813 case DNS_VERIFY_OK:
814 return 0;
815 case DNS_VERIFY_FAILED:
816 return -1;
817 case DNS_VERIFY_ERROR:
818 break;
819 default:
820 debug3("bad return value from verify_host_key_dns");
821 break;
822 }
823 }
824#endif /* DNS */
825
805 /* return ok if the key can be found in an old keyfile */ 826 /* return ok if the key can be found in an old keyfile */
806 if (stat(options.system_hostfile2, &st) == 0 || 827 if (stat(options.system_hostfile2, &st) == 0 ||
807 stat(options.user_hostfile2, &st) == 0) { 828 stat(options.user_hostfile2, &st) == 0) {