aboutsummaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2008-06-30 20:40:49 +0000
committerRob Austein <sra@hactrn.net>2008-06-30 20:40:49 +0000
commit4cc10eb88e2eaa1f2859734d607b8aa20257c5b3 (patch)
treee20652add143ced10b6bae53500757eb08bbe281 /utils
parentce57914c7d8db0bbf0f80f43a3745907e57cc3d8 (diff)
Add hashdir utility
svn path=/utils/Makefile; revision=1965
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile2
-rw-r--r--utils/hashdir/Makefile28
-rw-r--r--utils/hashdir/hashdir.c210
3 files changed, 239 insertions, 1 deletions
diff --git a/utils/Makefile b/utils/Makefile
index 7965cd30..450ffcb3 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -1,6 +1,6 @@
# $Id$
-SUBDIRS = uri manifest cert_hash roa
+SUBDIRS = uri manifest cert_hash roa hashdir
all clean test:
@for i in ${SUBDIRS}; do echo "Making $@ in $$i"; (cd $$i && ${MAKE} $@); done
diff --git a/utils/hashdir/Makefile b/utils/hashdir/Makefile
new file mode 100644
index 00000000..2031f136
--- /dev/null
+++ b/utils/hashdir/Makefile
@@ -0,0 +1,28 @@
+# $Id$
+
+OPENSSL_DIR = ../../openssl/openssl
+
+CFLAGS = -g -I${OPENSSL_DIR}/include
+
+# -H -Wl,-t
+
+BIN = hashdir
+OBJ = hashdir.o
+LIB = ${OPENSSL_DIR}/libcrypto.a
+
+all: ${BIN}
+
+clean::
+ rm -f ${BIN} ${OBJ}
+
+${BIN}: ${OBJ} ${LIB} Makefile
+ ${CC} -g -o $@ ${OBJ} ${LIB}
+
+INPUT = ../../rcynic/rcynic-data/authenticated
+OUTPUT = test.out
+
+test: ${BIN}
+ if test -d ${INPUT}; then rm -rf ${OUTPUT} && mkdir ${OUTPUT} && ./hashdir ${INPUT} ${OUTPUT}; else :; fi
+
+clean::
+ rm -rf ${OUTPUT}
diff --git a/utils/hashdir/hashdir.c b/utils/hashdir/hashdir.c
new file mode 100644
index 00000000..55f0395f
--- /dev/null
+++ b/utils/hashdir/hashdir.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2006--2008 American Registry for Internet Numbers ("ARIN")
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*
+ * Read a directory tree of DER certificates and CRLs and copy
+ * them into a PEM format directory with names in the hash format
+ * that OpenSSL's lookup routines expect.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <limits.h>
+
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+
+#ifndef FILENAME_MAX
+#define FILENAME_MAX 1024
+#endif
+
+static int verbose = 1;
+
+/*
+ * Error handling.
+ */
+
+#define _lose(_msg_, _file_) \
+ do { \
+ fprintf(stderr, "%s: %s\n", _msg_, _file_); \
+ } while (0)
+
+#define lose(_msg_, _file_) \
+ do { \
+ _lose(_msg_, _file_); \
+ goto done; \
+ } while (0)
+
+#define lose_errno(_msg_, _file_) \
+ do { \
+ _lose(_msg_, _file_); \
+ perror(NULL); \
+ goto done; \
+ } while (0)
+
+#define lose_openssl(_msg_, _file_) \
+ do { \
+ _lose(_msg_, _file_); \
+ ERR_print_errors_fp(stderr); \
+ goto done; \
+ } while (0)
+
+/*
+ * Check str for a trailing suffix.
+ */
+static int has_suffix(const char *str, const char *suffix)
+{
+ size_t len_str, len_suffix;
+ assert(str != NULL && suffix != NULL);
+ len_str = strlen(str);
+ len_suffix = strlen(suffix);
+ return len_str >= len_suffix && !strcmp(str + len_str - len_suffix, suffix);
+}
+
+/*
+ * Handle one object.
+ */
+static void file_handler(const char *filename, const char *targetdir)
+{
+ char path[FILENAME_MAX];
+ unsigned long hash;
+ const char *fmt;
+ X509_CRL *crl = NULL;
+ X509 *x509 = NULL;
+ BIO *b = NULL;
+ int i, is_crl;
+
+ if (has_suffix(filename, ".cer"))
+ is_crl = 0;
+ else if (has_suffix(filename, ".crl"))
+ is_crl = 1;
+ else
+ return; /* Ignore if neither certificate nor CRL */
+
+ if (verbose)
+ printf("Reading %s\n", filename);
+
+ if (!(b = BIO_new_file(filename, "rb")))
+ lose_openssl("Couldn't open input file", filename);
+
+ if (is_crl
+ ? !(crl = d2i_X509_CRL_bio(b, NULL))
+ : !(x509 = d2i_X509_bio(b, NULL)))
+ lose_openssl("Couldn't read DER object", filename);
+
+ BIO_free(b);
+ b = NULL;
+
+ if (!x509 && !crl)
+ return;
+
+ if (is_crl) {
+ hash = X509_NAME_hash(X509_CRL_get_issuer(crl));
+ fmt = "%s/%lx.r%d";
+ } else {
+ hash = X509_subject_name_hash(x509);
+ fmt = "%s/%lx.%d";
+ }
+
+ for (i = 0; i < INT_MAX; i++)
+ if (snprintf(path, sizeof(path), fmt, targetdir, hash, i) == sizeof(path))
+ lose("Path too long", filename);
+ else if (access(path, F_OK))
+ break;
+ if (i == INT_MAX)
+ lose("No pathname available", filename);
+
+ if (verbose)
+ printf("Writing %s\n", path);
+
+ if (!(b = BIO_new_file(path, "w")))
+ lose_openssl("Couldn't open output file", path);
+
+ if (is_crl
+ ? !PEM_write_bio_X509_CRL(b, crl)
+ : !PEM_write_bio_X509(b, x509))
+ lose_openssl("Couldn't write PEM object", path);
+
+ done:
+ X509_free(x509);
+ X509_CRL_free(crl);
+ BIO_free(b);
+}
+
+/*
+ * Walk a directory tree
+ */
+static int handle_directory(const char *name, const char *targetdir)
+{
+ char path[FILENAME_MAX];
+ struct dirent *d;
+ size_t len;
+ DIR *dir;
+ int ret = 0, need_slash;
+
+ assert(name);
+ len = strlen(name);
+ assert(len > 0 && len < sizeof(path));
+ need_slash = name[len - 1] != '/';
+
+ if ((dir = opendir(name)) == NULL)
+ lose_errno("Couldn't open directory", name);
+
+ while ((d = readdir(dir)) != NULL) {
+ if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
+ continue;
+ if (len + strlen(d->d_name) + need_slash >= sizeof(path))
+ lose("Constructed path name too long", d->d_name);
+ strcpy(path, name);
+ if (need_slash)
+ strcat(path, "/");
+ strcat(path, d->d_name);
+ switch (d->d_type) {
+ case DT_DIR:
+ if (!handle_directory(path, targetdir))
+ lose("Directory walk failed", path);
+ continue;
+ default:
+ file_handler(path, targetdir);
+ continue;
+ }
+ }
+
+ ret = 1;
+
+ done:
+ if (dir)
+ closedir(dir);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s input-directory output-directory\n");
+ return 1;
+ }
+
+ return !handle_directory(argv[1], argv[2]);
+}