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