Imported Upstream version 2.1.4
[platform/upstream/gpg2.git] / dirmngr / dns-cert.c
1 /* dns-cert.c - DNS CERT code (rfc-4398)
2  * Copyright (C) 2005, 2006, 2009 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * This file is free software; you can redistribute it and/or modify
7  * it under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * This file is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, see <http://www.gnu.org/licenses/>.
28  */
29
30 #include <config.h>
31 #include <sys/types.h>
32 #ifdef USE_DNS_CERT
33 # ifdef HAVE_W32_SYSTEM
34 #  ifdef HAVE_WINSOCK2_H
35 #   include <winsock2.h>
36 #  endif
37 #  include <windows.h>
38 # else
39 #  include <netinet/in.h>
40 #  include <arpa/nameser.h>
41 #  include <resolv.h>
42 # endif
43 # include <string.h>
44 #endif
45 #ifdef USE_ADNS
46 # include <adns.h>
47 #endif
48
49 #include "util.h"
50 #include "host2net.h"
51 #include "dns-cert.h"
52
53 /* Not every installation has gotten around to supporting CERTs
54    yet... */
55 #ifndef T_CERT
56 #define T_CERT 37
57 #endif
58
59 /* ADNS has no support for CERT yet. */
60 #define my_adns_r_cert 37
61
62
63
64 /* Returns 0 on success or an error code.  If a PGP CERT record was
65    found, the malloced data is returned at (R_KEY, R_KEYLEN) and
66    the other return parameters are set to NULL/0.  If an IPGP CERT
67    record was found the fingerprint is stored as an allocated block at
68    R_FPR and its length at R_FPRLEN; an URL is is allocated as a
69    string and returned at R_URL.  If WANT_CERTTYPE is 0 this function
70    returns the first CERT found with a supported type; it is expected
71    that only one CERT record is used.  If WANT_CERTTYPE is one of the
72    supported certtypes only records wih this certtype are considered
73    and the first found is returned.  (R_KEY,R_KEYLEN) are optional. */
74 gpg_error_t
75 get_dns_cert (const char *name, int want_certtype,
76               void **r_key, size_t *r_keylen,
77               unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
78 {
79 #ifdef USE_DNS_CERT
80 #ifdef USE_ADNS
81   gpg_error_t err;
82   adns_state state;
83   adns_answer *answer = NULL;
84   unsigned int ctype;
85   int count;
86
87   if (r_key)
88     *r_key = NULL;
89   if (r_keylen)
90     *r_keylen = 0;
91   *r_fpr = NULL;
92   *r_fprlen = 0;
93   *r_url = NULL;
94
95   if (adns_init (&state, adns_if_noerrprint, NULL))
96     {
97       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
98       log_error ("error initializing adns: %s\n", strerror (errno));
99       return err;
100     }
101
102   if (adns_synchronous (state, name, (adns_r_unknown | my_adns_r_cert),
103                         adns_qf_quoteok_query, &answer))
104     {
105       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
106       /* log_error ("DNS query failed: %s\n", strerror (errno)); */
107       adns_finish (state);
108       return err;
109     }
110   if (answer->status != adns_s_ok)
111     {
112       /* log_error ("DNS query returned an error: %s (%s)\n", */
113       /*            adns_strerror (answer->status), */
114       /*            adns_errabbrev (answer->status)); */
115       err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
116       goto leave;
117     }
118
119   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
120   for (count = 0; count < answer->nrrs; count++)
121     {
122       int datalen = answer->rrs.byteblock[count].len;
123       const unsigned char *data = answer->rrs.byteblock[count].data;
124
125       if (datalen < 5)
126         continue;  /* Truncated CERT record - skip.  */
127
128       ctype = buf16_to_uint (data);
129       /* (key tag and algorithm fields are not required.) */
130       data += 5;
131       datalen -= 5;
132
133       if (want_certtype && want_certtype != ctype)
134         ; /* Not of the requested certtype.  */
135       else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key && r_keylen)
136         {
137           /* CERT type is PGP.  Gpg checks for a minimum length of 11,
138              thus we do the same.  */
139           *r_key = xtrymalloc (datalen);
140           if (!*r_key)
141             err = gpg_err_make (default_errsource,
142                                 gpg_err_code_from_syserror ());
143           else
144             {
145               memcpy (*r_key, data, datalen);
146               *r_keylen = datalen;
147               err = 0;
148             }
149           goto leave;
150         }
151       else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
152                && datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
153         {
154           /* CERT type is IPGP.  We made sure that the data is
155              plausible and that the caller requested this
156              information.  */
157           *r_fprlen = data[0];
158           if (*r_fprlen)
159             {
160               *r_fpr = xtrymalloc (*r_fprlen);
161               if (!*r_fpr)
162                 {
163                   err = gpg_err_make (default_errsource,
164                                       gpg_err_code_from_syserror ());
165                   goto leave;
166                 }
167               memcpy (*r_fpr, data + 1, *r_fprlen);
168             }
169           else
170             *r_fpr = NULL;
171
172           if (datalen > *r_fprlen + 1)
173             {
174               *r_url = xtrymalloc (datalen - (*r_fprlen + 1) + 1);
175               if (!*r_url)
176                 {
177                   err = gpg_err_make (default_errsource,
178                                       gpg_err_code_from_syserror ());
179                   xfree (*r_fpr);
180                   *r_fpr = NULL;
181                   goto leave;
182                 }
183               memcpy (*r_url,
184                       data + (*r_fprlen + 1), datalen - (*r_fprlen + 1));
185               (*r_url)[datalen - (*r_fprlen + 1)] = '\0';
186             }
187           else
188             *r_url = NULL;
189
190           err = 0;
191           goto leave;
192         }
193     }
194
195  leave:
196   adns_free (answer);
197   adns_finish (state);
198   return err;
199
200 #else /*!USE_ADNS*/
201
202   gpg_error_t err;
203   unsigned char *answer;
204   int r;
205   u16 count;
206
207   if (r_key)
208     *r_key = NULL;
209   if (r_keylen)
210     *r_keylen = 0;
211   *r_fpr = NULL;
212   *r_fprlen = 0;
213   *r_url = NULL;
214
215   /* Allocate a 64k buffer which is the limit for an DNS response.  */
216   answer = xtrymalloc (65536);
217   if (!answer)
218     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
219
220   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
221
222   r = res_query (name, C_IN, T_CERT, answer, 65536);
223   /* Not too big, not too small, no errors and at least 1 answer. */
224   if (r >= sizeof (HEADER) && r <= 65536
225       && (((HEADER *) answer)->rcode) == NOERROR
226       && (count = ntohs (((HEADER *) answer)->ancount)))
227     {
228       int rc;
229       unsigned char *pt, *emsg;
230
231       emsg = &answer[r];
232
233       pt = &answer[sizeof (HEADER)];
234
235       /* Skip over the query */
236
237       rc = dn_skipname (pt, emsg);
238       if (rc == -1)
239         {
240           err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
241           goto leave;
242         }
243       pt += rc + QFIXEDSZ;
244
245       /* There are several possible response types for a CERT request.
246          We're interested in the PGP (a key) and IPGP (a URI) types.
247          Skip all others.  TODO: A key is better than a URI since
248          we've gone through all this bother to fetch it, so favor that
249          if we have both PGP and IPGP? */
250
251       while (count-- > 0 && pt < emsg)
252         {
253           u16 type, class, dlen, ctype;
254
255           rc = dn_skipname (pt, emsg);  /* the name we just queried for */
256           if (rc == -1)
257             {
258               err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
259               goto leave;
260             }
261
262           pt += rc;
263
264           /* Truncated message? 15 bytes takes us to the point where
265              we start looking at the ctype. */
266           if ((emsg - pt) < 15)
267             break;
268
269           type = buf16_to_u16 (pt);
270           pt += 2;
271
272           class = buf16_to_u16 (pt);
273           pt += 2;
274
275           if (class != C_IN)
276             break;
277
278           /* ttl */
279           pt += 4;
280
281           /* data length */
282           dlen = buf16_to_u16 (pt);
283           pt += 2;
284
285           /* We asked for CERT and got something else - might be a
286              CNAME, so loop around again. */
287           if (type != T_CERT)
288             {
289               pt += dlen;
290               continue;
291             }
292
293           /* The CERT type */
294           ctype = buf16_to_u16 (pt);
295           pt += 2;
296
297           /* Skip the CERT key tag and algo which we don't need. */
298           pt += 3;
299
300           dlen -= 5;
301
302           /* 15 bytes takes us to here */
303           if (want_certtype && want_certtype != ctype)
304             ; /* Not of the requested certtype.  */
305           else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key && r_keylen)
306             {
307               /* PGP type */
308               *r_key = xtrymalloc (dlen);
309               if (!*r_key)
310                 err = gpg_err_make (default_errsource,
311                                     gpg_err_code_from_syserror ());
312               else
313                 {
314                   memcpy (*r_key, pt, dlen);
315                   *r_keylen = dlen;
316                   err = 0;
317                 }
318               goto leave;
319             }
320           else if (ctype == DNS_CERTTYPE_IPGP
321                    && dlen && dlen < 1023 && dlen >= pt[0] + 1)
322             {
323               /* IPGP type */
324               *r_fprlen = pt[0];
325               if (*r_fprlen)
326                 {
327                   *r_fpr = xtrymalloc (*r_fprlen);
328                   if (!*r_fpr)
329                     {
330                       err = gpg_err_make (default_errsource,
331                                           gpg_err_code_from_syserror ());
332                       goto leave;
333                     }
334                   memcpy (*r_fpr, &pt[1], *r_fprlen);
335                 }
336               else
337                 *r_fpr = NULL;
338
339               if (dlen > *r_fprlen + 1)
340                 {
341                   *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
342                   if (!*r_fpr)
343                     {
344                       err = gpg_err_make (default_errsource,
345                                           gpg_err_code_from_syserror ());
346                       xfree (*r_fpr);
347                       *r_fpr = NULL;
348                       goto leave;
349                     }
350                   memcpy (*r_url, &pt[*r_fprlen + 1], dlen - (*r_fprlen + 1));
351                   (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
352                 }
353               else
354                 *r_url = NULL;
355
356               err = 0;
357               goto leave;
358             }
359
360           /* Neither type matches, so go around to the next answer. */
361           pt += dlen;
362         }
363     }
364
365  leave:
366   xfree (answer);
367   return err;
368
369 #endif /*!USE_ADNS */
370 #else /* !USE_DNS_CERT */
371   (void)name;
372   if (r_key)
373     *r_key = NULL;
374   if (r_keylen)
375     *r_keylen = NULL;
376   *r_fpr = NULL;
377   *r_fprlen = 0;
378   *r_url = NULL;
379
380   return gpg_err_make (default_errsource, GPG_ERR_NOT_SUPPORTED);
381 #endif
382 }