Home | History | Annotate | Download | only in racoon
      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 *
     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
     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
    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
    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
    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
    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