]> andersk Git - openssh.git/blob - dns.c
- (djm) [acss.c auth-krb5.c auth-options.c auth-pam.c auth-shadow.c]
[openssh.git] / dns.c
1 /* $OpenBSD: dns.c,v 1.21 2006/07/22 20:48:23 stevesk 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 #include "includes.h"
29
30 #include <sys/types.h>
31 #include <sys/socket.h>
32
33 #include <netdb.h>
34 #include <string.h>
35
36 #include "xmalloc.h"
37 #include "key.h"
38 #include "dns.h"
39 #include "log.h"
40
41 static const char *errset_text[] = {
42         "success",              /* 0 ERRSET_SUCCESS */
43         "out of memory",        /* 1 ERRSET_NOMEMORY */
44         "general failure",      /* 2 ERRSET_FAIL */
45         "invalid parameter",    /* 3 ERRSET_INVAL */
46         "name does not exist",  /* 4 ERRSET_NONAME */
47         "data does not exist",  /* 5 ERRSET_NODATA */
48 };
49
50 static const char *
51 dns_result_totext(unsigned int res)
52 {
53         switch (res) {
54         case ERRSET_SUCCESS:
55                 return errset_text[ERRSET_SUCCESS];
56         case ERRSET_NOMEMORY:
57                 return errset_text[ERRSET_NOMEMORY];
58         case ERRSET_FAIL:
59                 return errset_text[ERRSET_FAIL];
60         case ERRSET_INVAL:
61                 return errset_text[ERRSET_INVAL];
62         case ERRSET_NONAME:
63                 return errset_text[ERRSET_NONAME];
64         case ERRSET_NODATA:
65                 return errset_text[ERRSET_NODATA];
66         default:
67                 return "unknown error";
68         }
69 }
70
71 /*
72  * Read SSHFP parameters from key buffer.
73  */
74 static int
75 dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
76     u_char **digest, u_int *digest_len, const Key *key)
77 {
78         int success = 0;
79
80         switch (key->type) {
81         case KEY_RSA:
82                 *algorithm = SSHFP_KEY_RSA;
83                 break;
84         case KEY_DSA:
85                 *algorithm = SSHFP_KEY_DSA;
86                 break;
87         default:
88                 *algorithm = SSHFP_KEY_RESERVED; /* 0 */
89         }
90
91         if (*algorithm) {
92                 *digest_type = SSHFP_HASH_SHA1;
93                 *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len);
94                 if (*digest == NULL)
95                         fatal("dns_read_key: null from key_fingerprint_raw()");
96                 success = 1;
97         } else {
98                 *digest_type = SSHFP_HASH_RESERVED;
99                 *digest = NULL;
100                 *digest_len = 0;
101                 success = 0;
102         }
103
104         return success;
105 }
106
107 /*
108  * Read SSHFP parameters from rdata buffer.
109  */
110 static int
111 dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
112     u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len)
113 {
114         int success = 0;
115
116         *algorithm = SSHFP_KEY_RESERVED;
117         *digest_type = SSHFP_HASH_RESERVED;
118
119         if (rdata_len >= 2) {
120                 *algorithm = rdata[0];
121                 *digest_type = rdata[1];
122                 *digest_len = rdata_len - 2;
123
124                 if (*digest_len > 0) {
125                         *digest = (u_char *) xmalloc(*digest_len);
126                         memcpy(*digest, rdata + 2, *digest_len);
127                 } else {
128                         *digest = (u_char *)xstrdup("");
129                 }
130
131                 success = 1;
132         }
133
134         return success;
135 }
136
137 /*
138  * Check if hostname is numerical.
139  * Returns -1 if hostname is numeric, 0 otherwise
140  */
141 static int
142 is_numeric_hostname(const char *hostname)
143 {
144         struct addrinfo hints, *ai;
145
146         memset(&hints, 0, sizeof(hints));
147         hints.ai_socktype = SOCK_DGRAM;
148         hints.ai_flags = AI_NUMERICHOST;
149
150         if (getaddrinfo(hostname, "0", &hints, &ai) == 0) {
151                 freeaddrinfo(ai);
152                 return -1;
153         }
154
155         return 0;
156 }
157
158 /*
159  * Verify the given hostname, address and host key using DNS.
160  * Returns 0 if lookup succeeds, -1 otherwise
161  */
162 int
163 verify_host_key_dns(const char *hostname, struct sockaddr *address,
164     const Key *hostkey, int *flags)
165 {
166         u_int counter;
167         int result;
168         struct rrsetinfo *fingerprints = NULL;
169
170         u_int8_t hostkey_algorithm;
171         u_int8_t hostkey_digest_type;
172         u_char *hostkey_digest;
173         u_int hostkey_digest_len;
174
175         u_int8_t dnskey_algorithm;
176         u_int8_t dnskey_digest_type;
177         u_char *dnskey_digest;
178         u_int dnskey_digest_len;
179
180         *flags = 0;
181
182         debug3("verify_host_key_dns");
183         if (hostkey == NULL)
184                 fatal("No key to look up!");
185
186         if (is_numeric_hostname(hostname)) {
187                 debug("skipped DNS lookup for numerical hostname");
188                 return -1;
189         }
190
191         result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
192             DNS_RDATATYPE_SSHFP, 0, &fingerprints);
193         if (result) {
194                 verbose("DNS lookup error: %s", dns_result_totext(result));
195                 return -1;
196         }
197
198         if (fingerprints->rri_flags & RRSET_VALIDATED) {
199                 *flags |= DNS_VERIFY_SECURE;
200                 debug("found %d secure fingerprints in DNS",
201                     fingerprints->rri_nrdatas);
202         } else {
203                 debug("found %d insecure fingerprints in DNS",
204                     fingerprints->rri_nrdatas);
205         }
206
207         /* Initialize host key parameters */
208         if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
209             &hostkey_digest, &hostkey_digest_len, hostkey)) {
210                 error("Error calculating host key fingerprint.");
211                 freerrset(fingerprints);
212                 return -1;
213         }
214
215         if (fingerprints->rri_nrdatas)
216                 *flags |= DNS_VERIFY_FOUND;
217
218         for (counter = 0; counter < fingerprints->rri_nrdatas; counter++)  {
219                 /*
220                  * Extract the key from the answer. Ignore any badly
221                  * formatted fingerprints.
222                  */
223                 if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
224                     &dnskey_digest, &dnskey_digest_len,
225                     fingerprints->rri_rdatas[counter].rdi_data,
226                     fingerprints->rri_rdatas[counter].rdi_length)) {
227                         verbose("Error parsing fingerprint from DNS.");
228                         continue;
229                 }
230
231                 /* Check if the current key is the same as the given key */
232                 if (hostkey_algorithm == dnskey_algorithm &&
233                     hostkey_digest_type == dnskey_digest_type) {
234
235                         if (hostkey_digest_len == dnskey_digest_len &&
236                             memcmp(hostkey_digest, dnskey_digest,
237                             hostkey_digest_len) == 0) {
238
239                                 *flags |= DNS_VERIFY_MATCH;
240                         }
241                 }
242                 xfree(dnskey_digest);
243         }
244
245         xfree(hostkey_digest); /* from key_fingerprint_raw() */
246         freerrset(fingerprints);
247
248         if (*flags & DNS_VERIFY_FOUND)
249                 if (*flags & DNS_VERIFY_MATCH)
250                         debug("matching host key fingerprint found in DNS");
251                 else
252                         debug("mismatching host key fingerprint found in DNS");
253         else
254                 debug("no host key fingerprint found in DNS");
255
256         return 0;
257 }
258
259 /*
260  * Export the fingerprint of a key as a DNS resource record
261  */
262 int
263 export_dns_rr(const char *hostname, const Key *key, FILE *f, int generic)
264 {
265         u_int8_t rdata_pubkey_algorithm = 0;
266         u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;
267         u_char *rdata_digest;
268         u_int rdata_digest_len;
269
270         u_int i;
271         int success = 0;
272
273         if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
274             &rdata_digest, &rdata_digest_len, key)) {
275
276                 if (generic)
277                         fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname,
278                             DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len,
279                             rdata_pubkey_algorithm, rdata_digest_type);
280                 else
281                         fprintf(f, "%s IN SSHFP %d %d ", hostname,
282                             rdata_pubkey_algorithm, rdata_digest_type);
283
284                 for (i = 0; i < rdata_digest_len; i++)
285                         fprintf(f, "%02x", rdata_digest[i]);
286                 fprintf(f, "\n");
287                 xfree(rdata_digest); /* from key_fingerprint_raw() */
288                 success = 1;
289         } else {
290                 error("export_dns_rr: unsupported algorithm");
291         }
292
293         return success;
294 }
This page took 0.207474 seconds and 5 git commands to generate.