]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/getcertsbyname.c
ipsec-146.1.tar.gz
[apple/ipsec.git] / ipsec-tools / racoon / getcertsbyname.c
1 /* $KAME: getcertsbyname.c,v 1.7 2001/11/16 04:12:59 sakane Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include "config.h"
33
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/socket.h>
37
38 #include <netinet/in.h>
39 #include <arpa/nameser_compat.h>
40 #include <resolv.h>
41 #ifdef HAVE_LWRES_GETRRSETBYNAME
42 #include <lwres/netdb.h>
43 #include <lwres/lwres.h>
44 #else
45 #include <netdb.h>
46 #endif
47 #include <stdlib.h>
48 #include <string.h>
49 #include <errno.h>
50
51 #ifdef DNSSEC_DEBUG
52 #include <stdio.h>
53 #include <strings.h>
54 #endif
55
56 #include "netdb_dnssec.h"
57
58 /* XXX should it use ci_errno to hold errno instead of h_errno ? */
59 extern int h_errno;
60
61 static struct certinfo *getnewci __P((int, int, int, int, int,
62 unsigned char *));
63
64 static struct certinfo *
65 getnewci(qtype, keytag, algorithm, flags, certlen, cert)
66 int qtype, keytag, algorithm, flags, certlen;
67 unsigned char *cert;
68 {
69 struct certinfo *res;
70
71 res = malloc(sizeof(*res));
72 if (!res)
73 return NULL;
74
75 memset(res, 0, sizeof(*res));
76 res->ci_type = qtype;
77 res->ci_keytag = keytag;
78 res->ci_algorithm = algorithm;
79 res->ci_flags = flags;
80 res->ci_certlen = certlen;
81 res->ci_cert = malloc(certlen);
82 if (!res->ci_cert) {
83 free(res);
84 return NULL;
85 }
86 memcpy(res->ci_cert, cert, certlen);
87
88 return res;
89 }
90
91 void
92 freecertinfo(ci)
93 struct certinfo *ci;
94 {
95 struct certinfo *next;
96
97 do {
98 next = ci->ci_next;
99 if (ci->ci_cert)
100 free(ci->ci_cert);
101 free(ci);
102 ci = next;
103 } while (ci);
104 }
105
106 /*
107 * get CERT RR by FQDN and create certinfo structure chain.
108 */
109 #ifdef HAVE_LWRES_GETRRSETBYNAME
110 #define getrrsetbyname lwres_getrrsetbyname
111 #define freerrset lwres_freerrset
112 #define hstrerror lwres_hstrerror
113 #endif
114 #if defined(HAVE_LWRES_GETRRSETBYNAME) || defined(HAVE_GETRRSETBYNAME) //%%% BUG FIX - HAVE misspelled
115 int
116 getcertsbyname(name, res)
117 char *name;
118 struct certinfo **res;
119 {
120 int rdlength;
121 char *cp;
122 int type, keytag, algorithm;
123 struct certinfo head, *cur;
124 struct rrsetinfo *rr = NULL;
125 int i;
126 int error = -1;
127
128 /* initialize res */
129 *res = NULL;
130
131 memset(&head, 0, sizeof(head));
132 cur = &head;
133
134 error = getrrsetbyname(name, C_IN, T_CERT, 0, &rr);
135 if (error) {
136 #ifdef DNSSEC_DEBUG
137 printf("getrrsetbyname: %s\n", hstrerror(error));
138 #endif
139 h_errno = NO_RECOVERY;
140 goto end;
141 }
142
143 if (rr->rri_rdclass != C_IN
144 || rr->rri_rdtype != T_CERT
145 || rr->rri_nrdatas == 0) {
146 #ifdef DNSSEC_DEBUG
147 printf("getrrsetbyname: %s", hstrerror(error));
148 #endif
149 h_errno = NO_RECOVERY;
150 goto end;
151 }
152 #ifdef DNSSEC_DEBUG
153 if (!(rr->rri_flags & LWRDATA_VALIDATED))
154 printf("rr is not valid");
155 #endif
156
157 for (i = 0; i < rr->rri_nrdatas; i++) {
158 rdlength = rr->rri_rdatas[i].rdi_length;
159 cp = rr->rri_rdatas[i].rdi_data;
160
161 GETSHORT(type, cp); /* type */
162 rdlength -= INT16SZ;
163 GETSHORT(keytag, cp); /* key tag */
164 rdlength -= INT16SZ;
165 algorithm = *cp++; /* algorithm */
166 rdlength -= 1;
167
168 #ifdef DNSSEC_DEBUG
169 printf("type=%d keytag=%d alg=%d len=%d\n",
170 type, keytag, algorithm, rdlength);
171 #endif
172
173 /* create new certinfo */
174 cur->ci_next = getnewci(type, keytag, algorithm,
175 rr->rri_flags, rdlength, cp);
176 if (!cur->ci_next) {
177 #ifdef DNSSEC_DEBUG
178 printf("getnewci: %s", strerror(errno));
179 #endif
180 h_errno = NO_RECOVERY;
181 goto end;
182 }
183 cur = cur->ci_next;
184 }
185
186 *res = head.ci_next;
187 error = 0;
188
189 end:
190 if (rr)
191 freerrset(rr);
192 if (error && head.ci_next)
193 freecertinfo(head.ci_next);
194
195 return error;
196 }
197 #else /*!HAVE_LWRES_GETRRSETBYNAME*/
198 int
199 getcertsbyname(name, res)
200 char *name;
201 struct certinfo **res;
202 {
203 unsigned char *answer = NULL, *p;
204 int buflen, anslen, len;
205 HEADER *hp;
206 int qdcount, ancount, rdlength;
207 unsigned char *cp, *eom;
208 char hostbuf[1024]; /* XXX */
209 int qtype, qclass, keytag, algorithm;
210 struct certinfo head, *cur;
211 int error = -1;
212
213 /* initialize res */
214 *res = NULL;
215
216 memset(&head, 0, sizeof(head));
217 cur = &head;
218
219 /* get CERT RR */
220 buflen = 512;
221 do {
222
223 buflen *= 2;
224 p = realloc(answer, buflen);
225 if (!p) {
226 #ifdef DNSSEC_DEBUG
227 printf("realloc: %s", strerror(errno));
228 #endif
229 h_errno = NO_RECOVERY;
230 goto end;
231 }
232 answer = p;
233
234 anslen = res_query(name, C_IN, T_CERT, answer, buflen);
235 if (anslen == -1)
236 goto end;
237
238 } while (buflen < anslen);
239
240 #ifdef DNSSEC_DEBUG
241 printf("get a DNS packet len=%d\n", anslen);
242 #endif
243
244 /* parse CERT RR */
245 eom = answer + anslen;
246
247 hp = (HEADER *)answer;
248 qdcount = ntohs(hp->qdcount);
249 ancount = ntohs(hp->ancount);
250
251 /* question section */
252 if (qdcount != 1) {
253 #ifdef DNSSEC_DEBUG
254 printf("query count is not 1.\n");
255 #endif
256 h_errno = NO_RECOVERY;
257 goto end;
258 }
259 cp = (unsigned char *)(hp + 1);
260 len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf));
261 if (len < 0) {
262 #ifdef DNSSEC_DEBUG
263 printf("dn_expand failed.\n");
264 #endif
265 goto end;
266 }
267 cp += len;
268 GETSHORT(qtype, cp); /* QTYPE */
269 GETSHORT(qclass, cp); /* QCLASS */
270
271 /* answer section */
272 while (ancount-- && cp < eom) {
273 len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf));
274 if (len < 0) {
275 #ifdef DNSSEC_DEBUG
276 printf("dn_expand failed.\n");
277 #endif
278 goto end;
279 }
280 cp += len;
281 GETSHORT(qtype, cp); /* TYPE */
282 GETSHORT(qclass, cp); /* CLASS */
283 cp += INT32SZ; /* TTL */
284 GETSHORT(rdlength, cp); /* RDLENGTH */
285
286 /* CERT RR */
287 if (qtype != T_CERT) {
288 #ifdef DNSSEC_DEBUG
289 printf("not T_CERT\n");
290 #endif
291 h_errno = NO_RECOVERY;
292 goto end;
293 }
294 GETSHORT(qtype, cp); /* type */
295 rdlength -= INT16SZ;
296 GETSHORT(keytag, cp); /* key tag */
297 rdlength -= INT16SZ;
298 algorithm = *cp++; /* algorithm */
299 rdlength -= 1;
300 if (cp + rdlength > eom) {
301 #ifdef DNSSEC_DEBUG
302 printf("rdlength is too long.\n");
303 #endif
304 h_errno = NO_RECOVERY;
305 goto end;
306 }
307 #ifdef DNSSEC_DEBUG
308 printf("type=%d keytag=%d alg=%d len=%d\n",
309 qtype, keytag, algorithm, rdlength);
310 #endif
311
312 /* create new certinfo */
313 cur->ci_next = getnewci(qtype, keytag, algorithm,
314 0, rdlength, cp);
315 if (!cur->ci_next) {
316 #ifdef DNSSEC_DEBUG
317 printf("getnewci: %s", strerror(errno));
318 #endif
319 h_errno = NO_RECOVERY;
320 goto end;
321 }
322 cur = cur->ci_next;
323
324 cp += rdlength;
325 }
326
327 *res = head.ci_next;
328 error = 0;
329
330 end:
331 if (answer)
332 free(answer);
333 if (error && head.ci_next)
334 freecertinfo(head.ci_next);
335
336 return error;
337 }
338 #endif
339
340 #ifdef DNSSEC_DEBUG
341 int
342 b64encode(p, len)
343 char *p;
344 int len;
345 {
346 static const char b64t[] =
347 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
348 "abcdefghijklmnopqrstuvwxyz"
349 "0123456789+/=";
350
351 while (len > 2) {
352 printf("%c", b64t[(p[0] >> 2) & 0x3f]);
353 printf("%c", b64t[((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)]);
354 printf("%c", b64t[((p[1] << 2) & 0x3c) | ((p[2] >> 6) & 0x03)]);
355 printf("%c", b64t[p[2] & 0x3f]);
356 len -= 3;
357 p += 3;
358 }
359
360 if (len == 2) {
361 printf("%c", b64t[(p[0] >> 2) & 0x3f]);
362 printf("%c", b64t[((p[0] << 4) & 0x30)| ((p[1] >> 4) & 0x0f)]);
363 printf("%c", b64t[((p[1] << 2) & 0x3c)]);
364 printf("%c", '=');
365 } else if (len == 1) {
366 printf("%c", b64t[(p[0] >> 2) & 0x3f]);
367 printf("%c", b64t[((p[0] << 4) & 0x30)]);
368 printf("%c", '=');
369 printf("%c", '=');
370 }
371
372 return 0;
373 }
374
375 int
376 main(ac, av)
377 int ac;
378 char **av;
379 {
380 struct certinfo *res, *p;
381 int i;
382
383 if (ac < 2) {
384 printf("Usage: a.out (FQDN)\n");
385 exit(1);
386 }
387
388 i = getcertsbyname(*(av + 1), &res);
389 if (i != 0) {
390 herror("getcertsbyname");
391 exit(1);
392 }
393 printf("getcertsbyname succeeded.\n");
394
395 i = 0;
396 for (p = res; p; p = p->ci_next) {
397 printf("certinfo[%d]:\n", i);
398 printf("\tci_type=%d\n", p->ci_type);
399 printf("\tci_keytag=%d\n", p->ci_keytag);
400 printf("\tci_algorithm=%d\n", p->ci_algorithm);
401 printf("\tci_flags=%d\n", p->ci_flags);
402 printf("\tci_certlen=%d\n", p->ci_certlen);
403 printf("\tci_cert: ");
404 b64encode(p->ci_cert, p->ci_certlen);
405 printf("\n");
406 i++;
407 }
408
409 freecertinfo(res);
410
411 exit(0);
412 }
413 #endif