diff options
Diffstat (limited to 'ipsec-tools/src/racoon/getcertsbyname.c')
-rw-r--r-- | ipsec-tools/src/racoon/getcertsbyname.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/ipsec-tools/src/racoon/getcertsbyname.c b/ipsec-tools/src/racoon/getcertsbyname.c new file mode 100644 index 00000000..1ce7c62e --- /dev/null +++ b/ipsec-tools/src/racoon/getcertsbyname.c @@ -0,0 +1,418 @@ +/* $NetBSD: getcertsbyname.c,v 1.4 2006/09/09 16:22:09 manu Exp $ */ + +/* $KAME: getcertsbyname.c,v 1.7 2001/11/16 04:12:59 sakane Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "config.h" + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <arpa/nameser.h> +#if (defined(__APPLE__) && defined(__MACH__)) +# include <nameser8_compat.h> +#endif +#include <resolv.h> +#ifdef HAVE_LWRES_GETRRSETBYNAME +#include <lwres/netdb.h> +#include <lwres/lwres.h> +#else +#include <netdb.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#ifdef DNSSEC_DEBUG +#include <stdio.h> +#include <strings.h> +#endif + +#include "netdb_dnssec.h" + +/* XXX should it use ci_errno to hold errno instead of h_errno ? */ +extern int h_errno; + +static struct certinfo *getnewci __P((int, int, int, int, int, + unsigned char *)); + +static struct certinfo * +getnewci(qtype, keytag, algorithm, flags, certlen, cert) + int qtype, keytag, algorithm, flags, certlen; + unsigned char *cert; +{ + struct certinfo *res; + + res = malloc(sizeof(*res)); + if (!res) + return NULL; + + memset(res, 0, sizeof(*res)); + res->ci_type = qtype; + res->ci_keytag = keytag; + res->ci_algorithm = algorithm; + res->ci_flags = flags; + res->ci_certlen = certlen; + res->ci_cert = malloc(certlen); + if (!res->ci_cert) { + free(res); + return NULL; + } + memcpy(res->ci_cert, cert, certlen); + + return res; +} + +void +freecertinfo(ci) + struct certinfo *ci; +{ + struct certinfo *next; + + do { + next = ci->ci_next; + if (ci->ci_cert) + free(ci->ci_cert); + free(ci); + ci = next; + } while (ci); +} + +/* + * get CERT RR by FQDN and create certinfo structure chain. + */ +#ifdef HAVE_LWRES_GETRRSETBYNAME +#define getrrsetbyname lwres_getrrsetbyname +#define freerrset lwres_freerrset +#define hstrerror lwres_hstrerror +#endif +#if defined(HAVE_LWRES_GETRRSETBYNAME) || defined(AHVE_GETRRSETBYNAME) +int +getcertsbyname(name, res) + char *name; + struct certinfo **res; +{ + int rdlength; + char *cp; + int type, keytag, algorithm; + struct certinfo head, *cur; + struct rrsetinfo *rr = NULL; + int i; + int error = -1; + + /* initialize res */ + *res = NULL; + + memset(&head, 0, sizeof(head)); + cur = &head; + + error = getrrsetbyname(name, C_IN, T_CERT, 0, &rr); + if (error) { +#ifdef DNSSEC_DEBUG + printf("getrrsetbyname: %s\n", hstrerror(error)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + + if (rr->rri_rdclass != C_IN + || rr->rri_rdtype != T_CERT + || rr->rri_nrdatas == 0) { +#ifdef DNSSEC_DEBUG + printf("getrrsetbyname: %s", hstrerror(error)); +#endif + h_errno = NO_RECOVERY; + goto end; + } +#ifdef DNSSEC_DEBUG + if (!(rr->rri_flags & LWRDATA_VALIDATED)) + printf("rr is not valid"); +#endif + + for (i = 0; i < rr->rri_nrdatas; i++) { + rdlength = rr->rri_rdatas[i].rdi_length; + cp = rr->rri_rdatas[i].rdi_data; + + GETSHORT(type, cp); /* type */ + rdlength -= INT16SZ; + GETSHORT(keytag, cp); /* key tag */ + rdlength -= INT16SZ; + algorithm = *cp++; /* algorithm */ + rdlength -= 1; + +#ifdef DNSSEC_DEBUG + printf("type=%d keytag=%d alg=%d len=%d\n", + type, keytag, algorithm, rdlength); +#endif + + /* create new certinfo */ + cur->ci_next = getnewci(type, keytag, algorithm, + rr->rri_flags, rdlength, cp); + if (!cur->ci_next) { +#ifdef DNSSEC_DEBUG + printf("getnewci: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cur = cur->ci_next; + } + + *res = head.ci_next; + error = 0; + +end: + if (rr) + freerrset(rr); + if (error && head.ci_next) + freecertinfo(head.ci_next); + + return error; +} +#else /*!HAVE_LWRES_GETRRSETBYNAME*/ +int +getcertsbyname(name, res) + char *name; + struct certinfo **res; +{ + unsigned char *answer = NULL, *p; + int buflen, anslen, len; + HEADER *hp; + int qdcount, ancount, rdlength; + unsigned char *cp, *eom; + char hostbuf[1024]; /* XXX */ + int qtype, qclass, keytag, algorithm; + struct certinfo head, *cur; + int error = -1; + + /* initialize res */ + *res = NULL; + + memset(&head, 0, sizeof(head)); + cur = &head; + + /* get CERT RR */ + buflen = 512; + do { + + buflen *= 2; + p = realloc(answer, buflen); + if (!p) { +#ifdef DNSSEC_DEBUG + printf("realloc: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + answer = p; + + anslen = res_query(name, C_IN, T_CERT, answer, buflen); + if (anslen == -1) + goto end; + + } while (buflen < anslen); + +#ifdef DNSSEC_DEBUG + printf("get a DNS packet len=%d\n", anslen); +#endif + + /* parse CERT RR */ + eom = answer + anslen; + + hp = (HEADER *)answer; + qdcount = ntohs(hp->qdcount); + ancount = ntohs(hp->ancount); + + /* question section */ + if (qdcount != 1) { +#ifdef DNSSEC_DEBUG + printf("query count is not 1.\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cp = (unsigned char *)(hp + 1); + len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf)); + if (len < 0) { +#ifdef DNSSEC_DEBUG + printf("dn_expand failed.\n"); +#endif + goto end; + } + cp += len; + GETSHORT(qtype, cp); /* QTYPE */ + GETSHORT(qclass, cp); /* QCLASS */ + + /* answer section */ + while (ancount-- && cp < eom) { + len = dn_expand(answer, eom, cp, hostbuf, sizeof(hostbuf)); + if (len < 0) { +#ifdef DNSSEC_DEBUG + printf("dn_expand failed.\n"); +#endif + goto end; + } + cp += len; + GETSHORT(qtype, cp); /* TYPE */ + GETSHORT(qclass, cp); /* CLASS */ + cp += INT32SZ; /* TTL */ + GETSHORT(rdlength, cp); /* RDLENGTH */ + + /* CERT RR */ + if (qtype != T_CERT) { +#ifdef DNSSEC_DEBUG + printf("not T_CERT\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } + GETSHORT(qtype, cp); /* type */ + rdlength -= INT16SZ; + GETSHORT(keytag, cp); /* key tag */ + rdlength -= INT16SZ; + algorithm = *cp++; /* algorithm */ + rdlength -= 1; + if (cp + rdlength > eom) { +#ifdef DNSSEC_DEBUG + printf("rdlength is too long.\n"); +#endif + h_errno = NO_RECOVERY; + goto end; + } +#ifdef DNSSEC_DEBUG + printf("type=%d keytag=%d alg=%d len=%d\n", + qtype, keytag, algorithm, rdlength); +#endif + + /* create new certinfo */ + cur->ci_next = getnewci(qtype, keytag, algorithm, + 0, rdlength, cp); + if (!cur->ci_next) { +#ifdef DNSSEC_DEBUG + printf("getnewci: %s", strerror(errno)); +#endif + h_errno = NO_RECOVERY; + goto end; + } + cur = cur->ci_next; + + cp += rdlength; + } + + *res = head.ci_next; + error = 0; + +end: + if (answer) + free(answer); + if (error && head.ci_next) + freecertinfo(head.ci_next); + + return error; +} +#endif + +#ifdef DNSSEC_DEBUG +int +b64encode(p, len) + char *p; + int len; +{ + static const char b64t[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/="; + + while (len > 2) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30) | ((p[1] >> 4) & 0x0f)]); + printf("%c", b64t[((p[1] << 2) & 0x3c) | ((p[2] >> 6) & 0x03)]); + printf("%c", b64t[p[2] & 0x3f]); + len -= 3; + p += 3; + } + + if (len == 2) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30)| ((p[1] >> 4) & 0x0f)]); + printf("%c", b64t[((p[1] << 2) & 0x3c)]); + printf("%c", '='); + } else if (len == 1) { + printf("%c", b64t[(p[0] >> 2) & 0x3f]); + printf("%c", b64t[((p[0] << 4) & 0x30)]); + printf("%c", '='); + printf("%c", '='); + } + + return 0; +} + +int +main(ac, av) + int ac; + char **av; +{ + struct certinfo *res, *p; + int i; + + if (ac < 2) { + printf("Usage: a.out (FQDN)\n"); + exit(1); + } + + i = getcertsbyname(*(av + 1), &res); + if (i != 0) { + herror("getcertsbyname"); + exit(1); + } + printf("getcertsbyname succeeded.\n"); + + i = 0; + for (p = res; p; p = p->ci_next) { + printf("certinfo[%d]:\n", i); + printf("\tci_type=%d\n", p->ci_type); + printf("\tci_keytag=%d\n", p->ci_keytag); + printf("\tci_algorithm=%d\n", p->ci_algorithm); + printf("\tci_flags=%d\n", p->ci_flags); + printf("\tci_certlen=%d\n", p->ci_certlen); + printf("\tci_cert: "); + b64encode(p->ci_cert, p->ci_certlen); + printf("\n"); + i++; + } + + freecertinfo(res); + + exit(0); +} +#endif |