diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | Makefile.in | 8 | ||||
-rw-r--r-- | README.dns | 55 | ||||
-rw-r--r-- | dns.c | 293 | ||||
-rw-r--r-- | dns.h | 57 | ||||
-rw-r--r-- | key.c | 4 | ||||
-rw-r--r-- | key.h | 3 | ||||
-rw-r--r-- | readconf.c | 12 | ||||
-rw-r--r-- | readconf.h | 3 | ||||
-rw-r--r-- | ssh-keygen.1 | 11 | ||||
-rw-r--r-- | ssh-keygen.c | 55 | ||||
-rw-r--r-- | ssh_config.5 | 7 | ||||
-rw-r--r-- | sshconnect.c | 23 |
13 files changed, 523 insertions, 16 deletions
@@ -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 | ||
8 | 20030514 | 14 | 20030514 |
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 | ||
63 | LIBSSH_OBJS=authfd.o authfile.o bufaux.o buffer.o canohost.o channels.o \ | 63 | LIBSSH_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 | ||
72 | SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ | 72 | SSHOBJS= 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 @@ | |||
1 | How to verify host keys using OpenSSH and DNS | ||
2 | --------------------------------------------- | ||
3 | |||
4 | OpenSSH contains experimental support for verifying host keys using DNS | ||
5 | as described in draft-ietf-secsh-dns-xx.txt. The document contains | ||
6 | very brief instructions on how to test this feature. Configuring DNS | ||
7 | and DNSSEC is out of the scope of this document. | ||
8 | |||
9 | |||
10 | (1) Enable DNS fingerprint support in OpenSSH | ||
11 | |||
12 | Edit /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 | |||
19 | To create a DNS resource record (RR) containing a fingerprint of the | ||
20 | public host key, use the following command: | ||
21 | |||
22 | ssh-keygen -r hostname -f keyfile -g | ||
23 | |||
24 | where "hostname" is your fully qualified hostname and "keyfile" is the | ||
25 | file containing the public host key file. If you have multiple keys, | ||
26 | you should generate one RR for each key. | ||
27 | |||
28 | In the example above, ssh-keygen will print the fingerprint in a | ||
29 | generic DNS RR format parsable by most modern name server | ||
30 | implementations. If your nameserver has support for the SSHFP RR, as | ||
31 | defined by the draft, you can omit the -g flag and ssh-keygen will | ||
32 | print a standard RR. | ||
33 | |||
34 | To publish the fingerprint using the DNS you must add the generated RR | ||
35 | to your DNS zone file and sign your zone. | ||
36 | |||
37 | |||
38 | (3) Enable the ssh client to verify host keys using DNS | ||
39 | |||
40 | To enable the ssh client to verify host keys using DNS, you have to | ||
41 | add the following option to the ssh configuration file | ||
42 | ($HOME/.ssh/config or /etc/ssh/ssh_config): | ||
43 | |||
44 | VerifyHostKeyDNS yes | ||
45 | |||
46 | Upon connection the client will try to look up the fingerprint RR | ||
47 | using DNS. If the fingerprint received from the DNS server matches | ||
48 | the 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 $ | ||
@@ -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 | |||
46 | extern char *__progname; | ||
47 | RCSID("$OpenBSD: dns.c,v 1.4 2003/05/14 23:29:22 jakob Exp $"); | ||
48 | |||
49 | #ifndef LWRES | ||
50 | static 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 | |||
59 | static const char * | ||
60 | dns_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 | */ | ||
85 | static int | ||
86 | dns_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 | */ | ||
119 | static int | ||
120 | dns_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 | */ | ||
151 | int | ||
152 | verify_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 | */ | ||
260 | int | ||
261 | export_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 */ | ||
@@ -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 | |||
35 | enum sshfp_types { | ||
36 | SSHFP_KEY_RESERVED, | ||
37 | SSHFP_KEY_RSA, | ||
38 | SSHFP_KEY_DSA | ||
39 | }; | ||
40 | |||
41 | enum 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 | |||
53 | int verify_host_key_dns(const char *, struct sockaddr *, Key *); | ||
54 | int export_dns_rr(const char *, Key *, FILE *, int); | ||
55 | |||
56 | #endif /* DNS_H */ | ||
57 | #endif /* DNS */ | ||
@@ -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" |
35 | RCSID("$OpenBSD: key.c,v 1.51 2003/02/12 09:33:04 markus Exp $"); | 35 | RCSID("$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 | ||
172 | static u_char * | 172 | u_char* |
173 | key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length) | 173 | key_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; |
@@ -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 *); | |||
61 | Key *key_demote(Key *); | 61 | Key *key_demote(Key *); |
62 | int key_equal(Key *, Key *); | 62 | int key_equal(Key *, Key *); |
63 | char *key_fingerprint(Key *, enum fp_type, enum fp_rep); | 63 | char *key_fingerprint(Key *, enum fp_type, enum fp_rep); |
64 | u_char *key_fingerprint_raw(Key *, enum fp_type, u_int *); | ||
64 | char *key_type(Key *); | 65 | char *key_type(Key *); |
65 | int key_write(Key *, FILE *); | 66 | int key_write(Key *, FILE *); |
66 | int key_read(Key *, char **); | 67 | int 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" |
15 | RCSID("$OpenBSD: readconf.c,v 1.106 2003/04/09 12:00:37 djm Exp $"); | 15 | RCSID("$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 |
88 | generates, manages and converts authentication keys for | 92 | generates, manages and converts authentication keys for |
@@ -163,6 +167,8 @@ print the key in a | |||
163 | to stdout. | 167 | to stdout. |
164 | This option allows exporting keys for use by several commercial | 168 | This option allows exporting keys for use by several commercial |
165 | SSH implementations. | 169 | SSH implementations. |
170 | .It Fl g | ||
171 | Use generic DNS resource record format. | ||
166 | .It Fl f Ar filename | 172 | .It Fl f Ar filename |
167 | Specifies the filename of the key file. | 173 | Specifies 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 |
219 | Upload an existing RSA private key into the smartcard in | 225 | Upload an existing RSA private key into the smartcard in |
220 | .Ar reader . | 226 | .Ar reader . |
227 | .It Fl r Ar hostname | ||
228 | Print 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" |
15 | RCSID("$OpenBSD: ssh-keygen.c,v 1.104 2003/05/11 16:56:48 markus Exp $"); | 15 | RCSID("$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; | |||
70 | int convert_to_ssh2 = 0; | 70 | int convert_to_ssh2 = 0; |
71 | int convert_from_ssh2 = 0; | 71 | int convert_from_ssh2 = 0; |
72 | int print_public = 0; | 72 | int print_public = 0; |
73 | int print_generic = 0; | ||
73 | 74 | ||
74 | char *key_type_name = NULL; | 75 | char *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 | */ | ||
628 | static void | ||
629 | do_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. | |||
618 | Specifies a file to use for the user | 618 | Specifies a file to use for the user |
619 | host key database instead of | 619 | host key database instead of |
620 | .Pa $HOME/.ssh/known_hosts . | 620 | .Pa $HOME/.ssh/known_hosts . |
621 | .It Cm VerifyHostKeyDNS | ||
622 | Specifies whether to verify the remote key using DNS and SSHFP resource | ||
623 | records. | ||
624 | The default is | ||
625 | .Dq no . | ||
621 | .It Cm XAuthLocation | 626 | .It Cm XAuthLocation |
622 | Specifies the full pathname of the | 627 | Specifies 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" |
16 | RCSID("$OpenBSD: sshconnect.c,v 1.139 2003/04/14 14:17:50 markus Exp $"); | 16 | RCSID("$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 | |||
36 | char *client_version_string = NULL; | 40 | char *client_version_string = NULL; |
37 | char *server_version_string = NULL; | 41 | char *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 */ | ||
800 | int | 805 | int |
801 | verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) | 806 | verify_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) { |