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