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