2006-12-21 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / common / dns-cert.c
blob8dfcb97244ce4e24a2693cd052c5650c441525e1
1 /* dns-cert.c - DNS CERT code
2 * Copyright (C) 2005, 2006 Free Software Foundation, Inc.
4 * This file is part of GNUPG.
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 2 of the License, or
9 * (at your option) any later version.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 * USA.
22 #include <config.h>
23 #include <sys/types.h>
24 #ifdef USE_DNS_CERT
25 # ifdef HAVE_W32_SYSTEM
26 # include <windows.h>
27 # else
28 # include <netinet/in.h>
29 # include <arpa/nameser.h>
30 # include <resolv.h>
31 # endif
32 #include <string.h>
33 #endif
35 #include "util.h"
36 #include "iobuf.h"
37 #include "dns-cert.h"
39 /* Not every installation has gotten around to supporting CERTs
40 yet... */
41 #ifndef T_CERT
42 #define T_CERT 37
43 #endif
46 /* Returns -1 on error, 0 for no answer, 1 for PGP provided and 2 for
47 IPGP provided. */
48 int
49 get_dns_cert (const char *name,size_t max_size,IOBUF *iobuf,
50 unsigned char **fpr,size_t *fpr_len,char **url)
52 #ifdef USE_DNS_CERT
53 unsigned char *answer;
54 int r,ret=-1;
55 u16 count;
57 if(fpr)
58 *fpr=NULL;
60 if(url)
61 *url=NULL;
63 answer=xmalloc(max_size);
65 r=res_query(name,C_IN,T_CERT,answer,max_size);
66 /* Not too big, not too small, no errors and at least 1 answer. */
67 if(r>=sizeof(HEADER) && r<=max_size
68 && (((HEADER *)answer)->rcode)==NOERROR
69 && (count=ntohs(((HEADER *)answer)->ancount)))
71 int rc;
72 unsigned char *pt,*emsg;
74 emsg=&answer[r];
76 pt=&answer[sizeof(HEADER)];
78 /* Skip over the query */
80 rc=dn_skipname(pt,emsg);
81 if(rc==-1)
82 goto fail;
84 pt+=rc+QFIXEDSZ;
86 /* There are several possible response types for a CERT request.
87 We're interested in the PGP (a key) and IPGP (a URI) types.
88 Skip all others. TODO: A key is better than a URI since
89 we've gone through all this bother to fetch it, so favor that
90 if we have both PGP and IPGP? */
92 while(count-->0 && pt<emsg)
94 u16 type,class,dlen,ctype;
96 rc=dn_skipname(pt,emsg); /* the name we just queried for */
97 if(rc==-1)
98 break;
100 pt+=rc;
102 /* Truncated message? 15 bytes takes us to the point where
103 we start looking at the ctype. */
104 if((emsg-pt)<15)
105 break;
107 type=*pt++ << 8;
108 type|=*pt++;
110 class=*pt++ << 8;
111 class|=*pt++;
112 /* We asked for IN and got something else !? */
113 if(class!=C_IN)
114 break;
116 /* ttl */
117 pt+=4;
119 /* data length */
120 dlen=*pt++ << 8;
121 dlen|=*pt++;
123 /* We asked for CERT and got something else - might be a
124 CNAME, so loop around again. */
125 if(type!=T_CERT)
127 pt+=dlen;
128 continue;
131 /* The CERT type */
132 ctype=*pt++ << 8;
133 ctype|=*pt++;
135 /* Skip the CERT key tag and algo which we don't need. */
136 pt+=3;
138 dlen-=5;
140 /* 15 bytes takes us to here */
142 if(ctype==3 && iobuf && dlen)
144 /* PGP type */
145 *iobuf=iobuf_temp_with_content((char *)pt,dlen);
146 ret=1;
147 break;
149 else if(ctype==6 && dlen && dlen<1023 && dlen>=pt[0]+1
150 && fpr && fpr_len && url)
152 /* IPGP type */
153 *fpr_len=pt[0];
155 if(*fpr_len)
157 *fpr=xmalloc(*fpr_len);
158 memcpy(*fpr,&pt[1],*fpr_len);
160 else
161 *fpr=NULL;
163 if(dlen>*fpr_len+1)
165 *url=xmalloc(dlen-(*fpr_len+1)+1);
166 memcpy(*url,&pt[*fpr_len+1],dlen-(*fpr_len+1));
167 (*url)[dlen-(*fpr_len+1)]='\0';
169 else
170 *url=NULL;
172 ret=2;
173 break;
176 /* Neither type matches, so go around to the next answer. */
177 pt+=dlen;
181 fail:
182 xfree(answer);
184 return ret;
185 #else /* !USE_DNS_CERT */
186 return -1;
187 #endif
192 /* Test with simon.josefsson.org */
194 #ifdef TEST
196 main(int argc,char *argv[])
198 unsigned char *fpr;
199 size_t fpr_len;
200 char *url;
201 int rc;
202 IOBUF iobuf;
204 if(argc!=2)
206 printf("cert-test [name]\n");
207 return 1;
210 printf("CERT lookup on %s\n",argv[1]);
212 rc=get_dns_cert (argv[1],16384,&iobuf,&fpr,&fpr_len,&url);
213 if(rc==-1)
214 printf("error\n");
215 else if(rc==0)
216 printf("no answer\n");
217 else if(rc==1)
219 printf("key found: %d bytes\n",(int)iobuf_get_temp_length(iobuf));
220 iobuf_close(iobuf);
222 else if(rc==2)
224 if(fpr)
226 size_t i;
227 printf("Fingerprint found (%d bytes): ",(int)fpr_len);
228 for(i=0;i<fpr_len;i++)
229 printf("%02X",fpr[i]);
230 printf("\n");
232 else
233 printf("No fingerprint found\n");
235 if(url)
236 printf("URL found: %s\n",url);
237 else
238 printf("No URL found\n");
240 xfree(fpr);
241 xfree(url);
244 return 0;
246 #endif /* TEST */