* cert.c (get_cert): Disable IPGP types for now until the format questions
[gnupg.git] / util / cert.c
1 /* cert.c - DNS CERT code
2  * Copyright (C) 2005 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 2 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, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA.
20  */
21
22 #include <config.h>
23 #include <sys/types.h>
24 #ifdef USE_DNS_CERT
25 #ifdef _WIN32
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 #include "memory.h"
34 #endif
35 #include "iobuf.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 #ifdef USE_DNS_CERT
44
45 /* Returns -1 on error, 0 for no answer, 1 for PGP provided and 2 for
46    IPGP provided. */
47 int
48 get_cert(const char *name,size_t max_size,IOBUF *iobuf,char **url)
49 {
50   unsigned char *answer;
51   int r,ret=-1;
52   u16 count;
53
54   answer=xmalloc(max_size);
55
56   r=res_query(name,C_IN,T_CERT,answer,max_size);
57   /* Not too big, not too small, no errors and at least 1 answer. */
58   if(r>=sizeof(HEADER) && r<=max_size
59      && (((HEADER *)answer)->rcode)==NOERROR
60      && (count=ntohs(((HEADER *)answer)->ancount)))
61     {
62       int rc;
63       unsigned char *pt,*emsg;
64
65       emsg=&answer[r];
66
67       pt=&answer[sizeof(HEADER)];
68
69       /* Skip over the query */
70
71       rc=dn_skipname(pt,emsg);
72       if(rc==-1)
73         goto fail;
74
75       pt+=rc+QFIXEDSZ;
76
77       /* There are several possible response types for a CERT request.
78          We're interested in the PGP (a key) and IPGP (a URI) types.
79          Skip all others.  TODO: A key is better than a URI since
80          we've gone through all this bother to fetch it, so favor that
81          if we have both PGP and IPGP? */
82
83       while(count-->0 && pt<emsg)
84         {
85           u16 type,class,dlen,ctype;
86
87           rc=dn_skipname(pt,emsg); /* the name we just queried for */
88           if(rc==-1)
89             break;
90
91           pt+=rc;
92
93           /* Truncated message? */
94           if((emsg-pt)<15)
95             break;
96
97           type=*pt++ << 8;
98           type|=*pt++;
99
100           class=*pt++ << 8;
101           class|=*pt++;
102           /* We asked for IN and got something else !? */
103           if(class!=C_IN)
104             break;
105
106           /* ttl */
107           pt+=4;
108
109           /* data length */
110           dlen=*pt++ << 8;
111           dlen|=*pt++;
112
113           /* We asked for CERT and got something else - might be a
114              CNAME, so loop around again. */
115           if(type!=T_CERT)
116             {
117               pt+=dlen;
118               continue;
119             }
120
121           /* The CERT type */
122           ctype=*pt++ << 8;
123           ctype|=*pt++;
124
125           /* Skip the CERT key tag and algo which we don't need. */
126           pt+=3;
127
128           dlen-=5;
129
130           if(ctype==3 && iobuf)
131             {
132               /* PGP type */
133               *iobuf=iobuf_temp_with_content((char *)pt,dlen);
134               ret=1;
135               break;
136             }
137 #if 0
138           else if(ctype==6 && dlen<1023 && url)
139             {
140               /* Sanity check the IPGP URL type that the URL isn't too
141                  long */
142
143               *url=xmalloc(dlen+1);
144               memcpy(*url,pt,dlen);
145               (*url)[dlen]='\0';
146               ret=2;
147               break;
148             }
149 #endif
150
151           /* Neither type matches, so go around to the next answer. */
152           pt+=dlen;
153         }
154     }
155
156  fail:
157   xfree(answer);
158
159   return ret;
160 }
161
162 #else /* !USE_DNS_CERT */
163
164 int
165 get_cert(const char *name,size_t max_size,IOBUF *iobuf,char **url)
166 {
167   return -1;
168 }
169
170 #endif
171
172 /* Test with simon.josefsson.org */
173
174 #ifdef TEST
175 int
176 main(int argc,char *argv[])
177 {
178   char *url;
179   int rc;
180   IOBUF iobuf;
181
182   if(argc!=2)
183     {
184       printf("cert-test [name]\n");
185       return 1;
186     }
187
188   printf("CERT lookup on %s\n",argv[1]);
189
190   rc=get_cert(argv[1],16384,&iobuf,&url);
191   if(rc==-1)
192     printf("error\n");
193   else if(rc==0)
194     printf("no answer\n");
195   else if(rc==1)
196     {
197       printf("key found: %d bytes\n",iobuf_get_temp_length(iobuf));
198       iobuf_close(iobuf);
199     }
200   else if(rc==2)
201     {
202       printf("URL found: %s\n",url);
203       xfree(url);
204     }
205
206   return 0;
207 }
208 #endif /* TEST */