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