1/* $KAME: getcertsbyname.c,v 1.7 2001/11/16 04:12:59 sakane Exp $ */ 2 3/* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include "config.h" 33 34#include <sys/types.h> 35#include <sys/param.h> 36#include <sys/socket.h> 37 38#include <netinet/in.h> 39#include <arpa/nameser_compat.h> 40#include <resolv.h> 41#ifdef HAVE_LWRES_GETRRSETBYNAME 42#include <lwres/netdb.h> 43#include <lwres/lwres.h> 44#else 45#include <netdb.h> 46#endif 47#include <stdlib.h> 48#include <string.h> 49#include <errno.h> 50 51#ifdef DNSSEC_DEBUG 52#include <stdio.h> 53#include <strings.h> 54#endif 55 56#include "var.h" 57#include "netdb_dnssec.h" 58 59/* XXX should it use ci_errno to hold errno instead of h_errno ? */ 60extern int h_errno; 61 62static struct certinfo *getnewci (int, int, int, int, int, 63 unsigned char *); 64 65static struct certinfo * 66getnewci(qtype, keytag, algorithm, flags, certlen, cert) 67 int qtype, keytag, algorithm, flags, certlen; 68 unsigned 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 92void 93freecertinfo(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(HAVE_GETRRSETBYNAME) //%%% BUG FIX - HAVE misspelled 116int 117getcertsbyname(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 190end: 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*/ 199int 200getcertsbyname(name, res) 201 char *name; 202 struct certinfo **res; 203{ 204 unsigned char *answer = NULL, *p; 205 int buflen, anslen, len; 206 HEADER *hp; 207 int qdcount, ancount, rdlength; 208 unsigned 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 = ALIGNED_CAST(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 = (unsigned 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 331end: 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 342int 343b64encode(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 376int 377main(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