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