Obsolete option --no-sig-create-check.
[gnupg.git] / util / cert.c
1 /* cert.c - DNS CERT code
2  * Copyright (C) 2005, 2006, 2007 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 _WIN32
24 #include <windows.h>
25 #else
26 #include <netinet/in.h>
27 #include <arpa/nameser.h>
28 #include <arpa/inet.h>
29 #include <resolv.h>
30 #endif
31 #include <string.h>
32 #include "memory.h"
33 #endif
34 #include "iobuf.h"
35 #include "util.h"
36
37 /* Not every installation has gotten around to supporting CERTs
38    yet... */
39 #ifndef T_CERT
40 # define T_CERT 37
41 # ifdef __VMS
42 #  include "cert_vms.h"
43 # endif /* def __VMS */
44 #endif
45
46 #ifdef USE_DNS_CERT
47
48 /* Returns -1 on error, 0 for no answer, 1 for PGP provided and 2 for
49    IPGP provided. */
50 int
51 get_cert (const char *name, int want_ipgp, size_t max_size,IOBUF *iobuf,
52           unsigned char **fpr, size_t *fpr_len, char **url)
53 {
54   unsigned char *answer;
55   int r,ret=-1;
56   u16 count;
57
58   if(fpr)
59     *fpr=NULL;
60
61   if(url)
62     *url=NULL;
63
64   answer=xmalloc(max_size);
65
66   r=res_query(name,C_IN,T_CERT,answer,max_size);
67   /* Not too big, not too small, no errors and at least 1 answer. */
68   if(r>=sizeof(HEADER) && r<=max_size
69      && (((HEADER *)answer)->rcode)==NOERROR
70      && (count=ntohs(((HEADER *)answer)->ancount)))
71     {
72       int rc;
73       unsigned char *pt,*emsg;
74
75       emsg=&answer[r];
76
77       pt=&answer[sizeof(HEADER)];
78
79       /* Skip over the query */
80
81       rc=dn_skipname(pt,emsg);
82       if(rc==-1)
83         goto fail;
84
85       pt+=rc+QFIXEDSZ;
86
87       /* There are several possible response types for a CERT request.
88          We're interested in the PGP (a key) and IPGP (a URI) types.
89          Skip all others.  TODO: A key is better than a URI since
90          we've gone through all this bother to fetch it, so favor that
91          if we have both PGP and IPGP? */
92
93       while(count-->0 && pt<emsg)
94         {
95           u16 type,class,dlen,ctype;
96
97           rc=dn_skipname(pt,emsg); /* the name we just queried for */
98           if(rc==-1)
99             break;
100
101           pt+=rc;
102
103           /* Truncated message? 15 bytes takes us to the point where
104              we start looking at the ctype. */
105           if((emsg-pt)<15)
106             break;
107
108           type=*pt++ << 8;
109           type|=*pt++;
110
111           class=*pt++ << 8;
112           class|=*pt++;
113           /* We asked for IN and got something else !? */
114           if(class!=C_IN)
115             break;
116
117           /* ttl */
118           pt+=4;
119
120           /* data length */
121           dlen=*pt++ << 8;
122           dlen|=*pt++;
123
124           /* We asked for CERT and got something else - might be a
125              CNAME, so loop around again. */
126           if(type!=T_CERT)
127             {
128               pt+=dlen;
129               continue;
130             }
131
132           /* The CERT type */
133           ctype=*pt++ << 8;
134           ctype|=*pt++;
135
136           /* Skip the CERT key tag and algo which we don't need. */
137           pt+=3;
138
139           dlen-=5;
140
141           /* 15 bytes takes us to here */
142
143           if (want_ipgp && ctype != 6)
144             ; /* Skip non IPGP cert records.  */
145           else if (ctype==3 && iobuf && dlen)
146             {
147               /* PGP type */
148               *iobuf=iobuf_temp_with_content((char *)pt,dlen);
149               ret=1;
150               break;
151             }
152           else if(ctype==6 && dlen && dlen<1023 && dlen>=pt[0]+1
153                   && fpr && fpr_len && url)
154             {
155               /* IPGP type */
156               *fpr_len=pt[0];
157
158               if(*fpr_len)
159                 {
160                   *fpr=xmalloc(*fpr_len);
161                   memcpy(*fpr,&pt[1],*fpr_len);
162                 }
163               else
164                 *fpr=NULL;
165
166               if(dlen>*fpr_len+1)
167                 {
168                   *url=xmalloc(dlen-(*fpr_len+1)+1);
169                   memcpy(*url,&pt[*fpr_len+1],dlen-(*fpr_len+1));
170                   (*url)[dlen-(*fpr_len+1)]='\0';
171                 }
172               else
173                 *url=NULL;
174
175               ret=2;
176               break;
177             }
178
179           /* Neither type matches, so go around to the next answer. */
180           pt+=dlen;
181         }
182     }
183
184  fail:
185   xfree(answer);
186
187   return ret;
188 }
189
190 #else /* !USE_DNS_CERT */
191
192 int
193 get_cert (const char *name, int want_ipgp, size_t max_size,IOBUF *iobuf,
194           unsigned char **fpr, size_t *fpr_len, char **url)
195 {
196   return -1;
197 }
198
199 #endif
200
201 /* Test with simon.josefsson.org */
202
203 #ifdef TEST
204 int
205 main(int argc,char *argv[])
206 {
207   unsigned char *fpr;
208   size_t fpr_len;
209   char *url;
210   int rc;
211   IOBUF iobuf;
212
213   if(argc!=2)
214     {
215       printf("cert-test [name]\n");
216       return 1;
217     }
218
219   printf("CERT lookup on %s\n",argv[1]);
220
221   rc=get_cert (argv[1], 0, 16384, &iobuf, &fpr, &fpr_len, &url);
222   if(rc==-1)
223     printf("error\n");
224   else if(rc==0)
225     printf("no answer\n");
226   else if(rc==1)
227     {
228       printf("key found: %d bytes\n",(int)iobuf_get_temp_length(iobuf));
229       iobuf_close(iobuf);
230     }
231   else if(rc==2)
232     {
233       if(fpr)
234         {
235           size_t i;
236           printf("Fingerprint found (%d bytes): ",(int)fpr_len);
237           for(i=0;i<fpr_len;i++)
238             printf("%02X",fpr[i]);
239           printf("\n");
240         }
241       else
242         printf("No fingerprint found\n");
243
244       if(url)
245         printf("URL found: %s\n",url);
246       else
247         printf("No URL found\n");
248
249       xfree(fpr);
250       xfree(url);
251     }
252
253   return 0;
254 }
255 #endif /* TEST */