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