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 ? */ 64extern int h_errno; 65 66static struct certinfo *getnewci __P((int, int, int, int, int, 67 unsigned char *)); 68 69static struct certinfo * 70getnewci(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 96void 97freecertinfo(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) 120int 121getcertsbyname(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 194end: 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*/ 203int 204getcertsbyname(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 335end: 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 346int 347b64encode(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 380int 381main(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