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