]> git.saurik.com Git - apple/ipsec.git/blob - ipsec-tools/racoon/getcertsbyname.c
ipsec-286.1.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 "var.h"
57 #include "netdb_dnssec.h"
58
59 /* XXX should it use ci_errno to hold errno instead of h_errno ? */
60 extern int h_errno;
61
62 static struct certinfo *getnewci (int, int, int, int, int,
63 unsigned char *);
64
65 static struct certinfo *
66 getnewci(qtype, keytag, algorithm, flags, certlen, cert)
67 int qtype, keytag, algorithm, flags, certlen;
68 unsigned char *cert;
69 {
70 struct certinfo *res;
71
72 res = malloc(sizeof(*res));
73 if (!res)
74 return NULL;
75
76 memset(res, 0, sizeof(*res));
77 res->ci_type = qtype;
78 res->ci_keytag = keytag;
79 res->ci_algorithm = algorithm;
80 res->ci_flags = flags;
81 res->ci_certlen = certlen;
82 res->ci_cert = malloc(certlen);
83 if (!res->ci_cert) {
84 free(res);
85 return NULL;
86 }
87 memcpy(res->ci_cert, cert, certlen);
88
89 return res;
90 }
91
92 void
93 freecertinfo(ci)
94 struct certinfo *ci;
95 {
96 struct certinfo *next;
97
98 do {
99 next = ci->ci_next;
100 if (ci->ci_cert)
101 free(ci->ci_cert);
102 free(ci);
103 ci = next;
104 } while (ci);
105 }
106
107 /*
108 * get CERT RR by FQDN and create certinfo structure chain.
109 */
110 #ifdef HAVE_LWRES_GETRRSETBYNAME
111 #define getrrsetbyname lwres_getrrsetbyname
112 #define freerrset lwres_freerrset
113 #define hstrerror lwres_hstrerror
114 #endif
115 #if defined(HAVE_LWRES_GETRRSETBYNAME) || defined(HAVE_GETRRSETBYNAME) //%%% BUG FIX - HAVE misspelled
116 int
117 getcertsbyname(name, res)
118 char *name;
119 struct certinfo **res;
120 {
121 int rdlength;
122 char *cp;
123 int type, keytag, algorithm;
124 struct certinfo head, *cur;
125 struct rrsetinfo *rr = NULL;
126 int i;
127 int error = -1;
128
129 /* initialize res */
130 *res = NULL;
131
132 memset(&head, 0, sizeof(head));
133 cur = &head;
134
135 error = getrrsetbyname(name, C_IN, T_CERT, 0, &rr);
136 if (error) {
137 #ifdef DNSSEC_DEBUG
138 printf("getrrsetbyname: %s\n", hstrerror(error));
139 #endif
140 h_errno = NO_RECOVERY;
141 goto end;
142 }
143
144 if (rr->rri_rdclass != C_IN
145 || rr->rri_rdtype != T_CERT
146 || rr->rri_nrdatas == 0) {
147 #ifdef DNSSEC_DEBUG
148 printf("getrrsetbyname: %s", hstrerror(error));
149 #endif
150 h_errno = NO_RECOVERY;
151 goto end;
152 }
153 #ifdef DNSSEC_DEBUG
154 if (!(rr->rri_flags & LWRDATA_VALIDATED))
155 printf("rr is not valid");
156 #endif
157
158 for (i = 0; i < rr->rri_nrdatas; i++) {
159 rdlength = rr->rri_rdatas[i].rdi_length;
160 cp = rr->rri_rdatas[i].rdi_data;
161
162 GETSHORT(type, cp); /* type */
163 rdlength -= INT16SZ;
164 GETSHORT(keytag, cp); /* key tag */
165 rdlength -= INT16SZ;
166 algorithm = *cp++; /* algorithm */
167 rdlength -= 1;
168
169 #ifdef DNSSEC_DEBUG
170 printf("type=%d keytag=%d alg=%d len=%d\n",
171 type, keytag, algorithm, rdlength);
172 #endif
173
174 /* create new certinfo */
175 cur->ci_next = getnewci(type, keytag, algorithm,
176 rr->rri_flags, rdlength, cp);
177 if (!cur->ci_next) {
178 #ifdef DNSSEC_DEBUG
179 printf("getnewci: %s", strerror(errno));
180 #endif
181 h_errno = NO_RECOVERY;
182 goto end;
183 }
184 cur = cur->ci_next;
185 }
186
187 *res = head.ci_next;
188 error = 0;
189
190 end:
191 if (rr)
192 freerrset(rr);
193 if (error && head.ci_next)
194 freecertinfo(head.ci_next);
195
196 return error;
197 }
198 #else /*!HAVE_LWRES_GETRRSETBYNAME*/
199 int
200 getcertsbyname(name, res)
201 char *name;
202 struct certinfo **res;
203 {
204 unsigned char *answer = NULL, *p;
205 int buflen, anslen, len;
206 HEADER *hp;
207 int qdcount, ancount, rdlength;
208 unsigned char *cp, *eom;
209 char hostbuf[1024]; /* XXX */
210 int qtype, qclass, keytag, algorithm;
211 struct certinfo head, *cur;
212 int error = -1;
213
214 /* initialize res */
215 *res = NULL;
216
217 memset(&head, 0, sizeof(head));
218 cur = &head;
219
220 /* get CERT RR */
221 buflen = 512;
222 do {
223
224 buflen *= 2;
225 p = realloc(answer, buflen);
226 if (!p) {
227 #ifdef DNSSEC_DEBUG
228 printf("realloc: %s", strerror(errno));
229 #endif
230 h_errno = NO_RECOVERY;
231 goto end;
232 }
233 answer = p;
234
235 anslen = res_query(name, C_IN, T_CERT, answer, buflen);
236 if (anslen == -1)
237 goto end;
238
239 } while (buflen < anslen);
240
241 #ifdef DNSSEC_DEBUG
242 printf("get a DNS packet len=%d\n", anslen);
243 #endif
244
245 /* parse CERT RR */
246 eom = answer + anslen;
247
248 hp = ALIGNED_CAST(HEADER *)answer;
249 qdcount = ntohs(hp->qdcount);
250 ancount = ntohs(hp->ancount);
251
252 /* question section */
253 if (qdcount != 1) {
254 #ifdef DNSSEC_DEBUG
255 printf("query count is not 1.\n");
256 #endif
257 h_errno = NO_RECOVERY;
258 goto end;
259 }
260 cp = (unsigned char *)(hp + 1);
261 len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf));
262 if (len < 0) {
263 #ifdef DNSSEC_DEBUG
264 printf("dn_expand failed.\n");
265 #endif
266 goto end;
267 }
268 cp += len;
269 GETSHORT(qtype, cp); /* QTYPE */
270 GETSHORT(qclass, cp); /* QCLASS */
271
272 /* answer section */
273 while (ancount-- && cp < eom) {
274 len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf));
275 if (len < 0) {
276 #ifdef DNSSEC_DEBUG
277 printf("dn_expand failed.\n");
278 #endif
279 goto end;
280 }
281 cp += len;
282 GETSHORT(qtype, cp); /* TYPE */
283 GETSHORT(qclass, cp); /* CLASS */
284 cp += INT32SZ; /* TTL */
285 GETSHORT(rdlength, cp); /* RDLENGTH */
286
287 /* CERT RR */
288 if (qtype != T_CERT) {
289 #ifdef DNSSEC_DEBUG
290 printf("not T_CERT\n");
291 #endif
292 h_errno = NO_RECOVERY;
293 goto end;
294 }
295 GETSHORT(qtype, cp); /* type */
296 rdlength -= INT16SZ;
297 GETSHORT(keytag, cp); /* key tag */
298 rdlength -= INT16SZ;
299 algorithm = *cp++; /* algorithm */
300 rdlength -= 1;
301 if (cp + rdlength > eom) {
302 #ifdef DNSSEC_DEBUG
303 printf("rdlength is too long.\n");
304 #endif
305 h_errno = NO_RECOVERY;
306 goto end;
307 }
308 #ifdef DNSSEC_DEBUG
309 printf("type=%d keytag=%d alg=%d len=%d\n",
310 qtype, keytag, algorithm, rdlength);
311 #endif
312
313 /* create new certinfo */
314 cur->ci_next = getnewci(qtype, keytag, algorithm,
315 0, rdlength, cp);
316 if (!cur->ci_next) {
317 #ifdef DNSSEC_DEBUG
318 printf("getnewci: %s", strerror(errno));
319 #endif
320 h_errno = NO_RECOVERY;
321 goto end;
322 }
323 cur = cur->ci_next;
324
325 cp += rdlength;
326 }
327
328 *res = head.ci_next;
329 error = 0;
330
331 end:
332 if (answer)
333 free(answer);
334 if (error && head.ci_next)
335 freecertinfo(head.ci_next);
336
337 return error;
338 }
339 #endif
340
341 #ifdef DNSSEC_DEBUG
342 int
343 b64encode(p, len)
344 char *p;
345 int len;
346 {
347 static const char b64t[] =
348 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
349 "abcdefghijklmnopqrstuvwxyz"
350 "0123456789+/=";
351
352 while (len > 2) {
353 printf("%c", b64t[(p[0] >> 2) & 0x3f]);
354 printf("%c", b64t[((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)]);
355 printf("%c", b64t[((p[1] << 2) & 0x3c) | ((p[2] >> 6) & 0x03)]);
356 printf("%c", b64t[p[2] & 0x3f]);
357 len -= 3;
358 p += 3;
359 }
360
361 if (len == 2) {
362 printf("%c", b64t[(p[0] >> 2) & 0x3f]);
363 printf("%c", b64t[((p[0] << 4) & 0x30)| ((p[1] >> 4) & 0x0f)]);
364 printf("%c", b64t[((p[1] << 2) & 0x3c)]);
365 printf("%c", '=');
366 } else if (len == 1) {
367 printf("%c", b64t[(p[0] >> 2) & 0x3f]);
368 printf("%c", b64t[((p[0] << 4) & 0x30)]);
369 printf("%c", '=');
370 printf("%c", '=');
371 }
372
373 return 0;
374 }
375
376 int
377 main(ac, av)
378 int ac;
379 char **av;
380 {
381 struct certinfo *res, *p;
382 int i;
383
384 if (ac < 2) {
385 printf("Usage: a.out (FQDN)\n");
386 exit(1);
387 }
388
389 i = getcertsbyname(*(av + 1), &res);
390 if (i != 0) {
391 herror("getcertsbyname");
392 exit(1);
393 }
394 printf("getcertsbyname succeeded.\n");
395
396 i = 0;
397 for (p = res; p; p = p->ci_next) {
398 printf("certinfo[%d]:\n", i);
399 printf("\tci_type=%d\n", p->ci_type);
400 printf("\tci_keytag=%d\n", p->ci_keytag);
401 printf("\tci_algorithm=%d\n", p->ci_algorithm);
402 printf("\tci_flags=%d\n", p->ci_flags);
403 printf("\tci_certlen=%d\n", p->ci_certlen);
404 printf("\tci_cert: ");
405 b64encode(p->ci_cert, p->ci_certlen);
406 printf("\n");
407 i++;
408 }
409
410 freecertinfo(res);
411
412 exit(0);
413 }
414 #endif