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