summaryrefslogtreecommitdiffstats
path: root/ipsec-tools/src/racoon/getcertsbyname.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipsec-tools/src/racoon/getcertsbyname.c')
-rw-r--r--ipsec-tools/src/racoon/getcertsbyname.c418
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