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