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