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