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