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