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