common: Fix regression due to commit 2183683b.
[gnupg.git] / common / 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 /* Certificate types according to RFC-4398.  */
64 #define CERTTYPE_PKIX      1 /* X.509 as per PKIX. */
65 #define CERTTYPE_SPKI      2 /* SPKI certificate.  */
66 #define CERTTYPE_PGP       3 /* OpenPGP packet.  */
67 #define CERTTYPE_IPKIX     4 /* The URL of an X.509 data object. */
68 #define CERTTYPE_ISPKI     5 /* The URL of an SPKI certificate.  */
69 #define CERTTYPE_IPGP      6 /* The fingerprint and URL of an OpenPGP packet.*/
70 #define CERTTYPE_ACPKIX    7 /* Attribute Certificate.  */
71 #define CERTTYPE_IACPKIX   8 /* The URL of an Attribute Certificate.  */
72 #define CERTTYPE_URI     253 /* URI private.  */
73 #define CERTTYPE_OID     254 /* OID private.  */
74
75
76 /* Returns 0 on success or an error code.  If a PGP CERT record was
77    found, a new estream with that key will be returned at R_KEY and
78    the other return parameters are set to NULL/0.  If an IPGP CERT
79    record was found the fingerprint is stored as an allocated block at
80    R_FPR and its length at R_FPRLEN; an URL is is allocated as a
81    string and returned at R_URL.  Note that this function returns the
82    first CERT found with a supported type; it is expected that only
83    one CERT record is used. */
84 gpg_error_t
85 get_dns_cert (const char *name, estream_t *r_key,
86               unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
87 {
88 #ifdef USE_DNS_CERT
89 #ifdef USE_ADNS
90   gpg_error_t err;
91   adns_state state;
92   adns_answer *answer = NULL;
93   unsigned int ctype;
94   int count;
95
96   *r_key = NULL;
97   *r_fpr = NULL;
98   *r_fprlen = 0;
99   *r_url = NULL;
100
101   if (adns_init (&state, adns_if_noerrprint, NULL))
102     {
103       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
104       log_error ("error initializing adns: %s\n", strerror (errno));
105       return err;
106     }
107
108   if (adns_synchronous (state, name, (adns_r_unknown | my_adns_r_cert),
109                         adns_qf_quoteok_query, &answer))
110     {
111       err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
112       /* log_error ("DNS query failed: %s\n", strerror (errno)); */
113       adns_finish (state);
114       return err;
115     }
116   if (answer->status != adns_s_ok)
117     {
118       /* log_error ("DNS query returned an error: %s (%s)\n", */
119       /*            adns_strerror (answer->status), */
120       /*            adns_errabbrev (answer->status)); */
121       err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
122       goto leave;
123     }
124
125   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
126   for (count = 0; count < answer->nrrs; count++)
127     {
128       int datalen = answer->rrs.byteblock[count].len;
129       const unsigned char *data = answer->rrs.byteblock[count].data;
130
131       if (datalen < 5)
132         continue;  /* Truncated CERT record - skip.  */
133
134       ctype = buf16_to_uint (data);
135       /* (key tag and algorithm fields are not required.) */
136       data += 5;
137       datalen -= 5;
138
139       if (ctype == CERTTYPE_PGP && datalen >= 11)
140         {
141           /* CERT type is PGP.  Gpg checks for a minimum length of 11,
142              thus we do the same.  */
143           *r_key = es_fopenmem_init (0, "rwb", data, datalen);
144           if (!*r_key)
145             err = gpg_err_make (default_errsource,
146                                 gpg_err_code_from_syserror ());
147           else
148             err = 0;
149           goto leave;
150         }
151       else if (ctype == 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   *r_key = NULL;
208   *r_fpr = NULL;
209   *r_fprlen = 0;
210   *r_url = NULL;
211
212   /* Allocate a 64k buffer which is the limit for an DNS response.  */
213   answer = xtrymalloc (65536);
214   if (!answer)
215     return gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
216
217   err = gpg_err_make (default_errsource, GPG_ERR_NOT_FOUND);
218
219   r = res_query (name, C_IN, T_CERT, answer, 65536);
220   /* Not too big, not too small, no errors and at least 1 answer. */
221   if (r >= sizeof (HEADER) && r <= 65536
222       && (((HEADER *) answer)->rcode) == NOERROR
223       && (count = ntohs (((HEADER *) answer)->ancount)))
224     {
225       int rc;
226       unsigned char *pt, *emsg;
227
228       emsg = &answer[r];
229
230       pt = &answer[sizeof (HEADER)];
231
232       /* Skip over the query */
233
234       rc = dn_skipname (pt, emsg);
235       if (rc == -1)
236         {
237           err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
238           goto leave;
239         }
240       pt += rc + QFIXEDSZ;
241
242       /* There are several possible response types for a CERT request.
243          We're interested in the PGP (a key) and IPGP (a URI) types.
244          Skip all others.  TODO: A key is better than a URI since
245          we've gone through all this bother to fetch it, so favor that
246          if we have both PGP and IPGP? */
247
248       while (count-- > 0 && pt < emsg)
249         {
250           u16 type, class, dlen, ctype;
251
252           rc = dn_skipname (pt, emsg);  /* the name we just queried for */
253           if (rc == -1)
254             {
255               err = gpg_err_make (default_errsource, GPG_ERR_INV_OBJ);
256               goto leave;
257             }
258
259           pt += rc;
260
261           /* Truncated message? 15 bytes takes us to the point where
262              we start looking at the ctype. */
263           if ((emsg - pt) < 15)
264             break;
265
266           type = buf16_to_u16 (pt);
267           pt += 2;
268
269           class = buf16_to_u16 (pt);
270           pt += 2;
271
272           if (class != C_IN)
273             break;
274
275           /* ttl */
276           pt += 4;
277
278           /* data length */
279           dlen = buf16_to_u16 (pt);
280           pt += 2;
281
282           /* We asked for CERT and got something else - might be a
283              CNAME, so loop around again. */
284           if (type != T_CERT)
285             {
286               pt += dlen;
287               continue;
288             }
289
290           /* The CERT type */
291           ctype = buf16_to_u16 (pt);
292           pt += 2;
293
294           /* Skip the CERT key tag and algo which we don't need. */
295           pt += 3;
296
297           dlen -= 5;
298
299           /* 15 bytes takes us to here */
300
301           if (ctype == CERTTYPE_PGP && dlen)
302             {
303               /* PGP type */
304               *r_key = es_fopenmem_init (0, "rwb", pt, dlen);
305               if (!*r_key)
306                 err = gpg_err_make (default_errsource,
307                                     gpg_err_code_from_syserror ());
308               else
309                 err = 0;
310               goto leave;
311             }
312           else if (ctype == CERTTYPE_IPGP
313                    && dlen && dlen < 1023 && dlen >= pt[0] + 1)
314             {
315               /* IPGP type */
316               *r_fprlen = pt[0];
317               if (*r_fprlen)
318                 {
319                   *r_fpr = xtrymalloc (*r_fprlen);
320                   if (!*r_fpr)
321                     {
322                       err = gpg_err_make (default_errsource,
323                                           gpg_err_code_from_syserror ());
324                       goto leave;
325                     }
326                   memcpy (*r_fpr, &pt[1], *r_fprlen);
327                 }
328               else
329                 *r_fpr = NULL;
330
331               if (dlen > *r_fprlen + 1)
332                 {
333                   *r_url = xtrymalloc (dlen - (*r_fprlen + 1) + 1);
334                   if (!*r_fpr)
335                     {
336                       err = gpg_err_make (default_errsource,
337                                           gpg_err_code_from_syserror ());
338                       xfree (*r_fpr);
339                       *r_fpr = NULL;
340                       goto leave;
341                     }
342                   memcpy (*r_url, &pt[*r_fprlen + 1], dlen - (*r_fprlen + 1));
343                   (*r_url)[dlen - (*r_fprlen + 1)] = '\0';
344                 }
345               else
346                 *r_url = NULL;
347
348               err = 0;
349               goto leave;
350             }
351
352           /* Neither type matches, so go around to the next answer. */
353           pt += dlen;
354         }
355     }
356
357  leave:
358   xfree (answer);
359   return err;
360
361 #endif /*!USE_ADNS */
362 #else /* !USE_DNS_CERT */
363   (void)name;
364   *r_key = NULL;
365   *r_fpr = NULL;
366   *r_fprlen = 0;
367   *r_url = NULL;
368
369   return gpg_err_make (default_errsource, GPG_ERR_NOT_SUPPORTED);
370 #endif
371 }