From fe0bf509f528dbdc50c7182f81057c6a4e15e4bd Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Sat, 5 Apr 2014 22:42:12 +0000 Subject: Source tree reorg, phase 1. Almost everything moved, no file contents changed. svn path=/branches/tk685/; revision=5757 --- rp/utils/hashdir.c | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 rp/utils/hashdir.c (limited to 'rp/utils/hashdir.c') diff --git a/rp/utils/hashdir.c b/rp/utils/hashdir.c new file mode 100644 index 00000000..1b5b0f46 --- /dev/null +++ b/rp/utils/hashdir.c @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2014 Dragon Research Labs ("DRL") + * Portions 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 notices and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DRL AND ARIN DISCLAIM ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DRL OR + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 *cer = 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)) + : !(cer = d2i_X509_bio(b, NULL))) + lose_openssl("Couldn't read DER object", filename); + + BIO_free(b); + b = NULL; + + if (is_crl) { + hash = X509_NAME_hash(X509_CRL_get_issuer(crl)); + fmt = "%s/%08lx.r%d"; + } else { + hash = X509_subject_name_hash(cer); + fmt = "%s/%08lx.%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, cer)) + lose_openssl("Couldn't write PEM object", path); + + done: + X509_free(cer); + 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; +} + +static void usage (const char *jane, const int code) +{ + fprintf(code ? stderr : stdout, "usage: %s input-directory output-directory\n", jane); + exit(code); +} + +int main(int argc, char *argv[]) +{ + if (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))) + usage(argv[0], 0); + + if (argc != 3) + usage(argv[0], 1); + + return !handle_directory(argv[1], argv[2]); +} -- cgit v1.2.3