Index: creddy/creddy.c
===================================================================
--- creddy/creddy.c	(revision abd7c251aeeda06b2bd96c350cfd6ed57fd6b477)
+++ creddy/creddy.c	(revision abd7c251aeeda06b2bd96c350cfd6ed57fd6b477)
@@ -0,0 +1,169 @@
+#include <assert.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <library.h>
+
+#include "creddy.h"
+
+#define OPT_CN              1
+#define OPT_VALIDITY        2
+
+int main(int argc, char **argv) {
+    int ret;
+    options_t options = { 0, };
+
+    options.validity = 1080;
+
+    struct option getopts[] = {
+        { "help",       0, &options.help, 1 },
+        { "generate",   0, &options.mode, MODE_GENERATE },
+        { "verify",     0, &options.mode, MODE_VERIFY },
+        { "keyid",      0, &options.mode, MODE_KEYID },
+        { "attribute",  0, &options.mode, MODE_ATTRIBUTE },
+        { "roles",      0, &options.mode, MODE_ROLES },
+
+        // generate options
+        { "cn",         1, 0, OPT_CN },
+        { "validity",   1, 0, OPT_VALIDITY },
+
+        { NULL },
+    };
+
+    for ( ; ; ) {
+        int c = getopt_long(argc, argv, "", getopts, NULL);
+        if (c < 0)
+            break;
+
+        switch (c) {
+            // set the option from the value in the getopts struct
+            case 0:
+                continue;
+
+            // generate options
+            case OPT_CN:
+                options.cn = xstrdup(optarg);
+                break;
+            case OPT_VALIDITY:
+                options.validity = atoi(optarg);
+                break;
+
+            case '?':
+                break;
+
+            default:
+                printf("wat\n");
+                return 45;
+        }
+    }
+
+    if (options.help || optind < argc) {
+        if (optind > 0 && optind < argc)
+            printf("I don't understand %s\n", argv[optind]);
+        usage(&options);
+    }
+
+    // init libstrongswan
+    atexit(library_deinit);
+    ret = library_init(NULL);
+    if (!ret)
+        exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+    ret = lib->plugins->load(
+        lib->plugins,
+        NULL,
+        lib->settings->get_str(lib->settings, "", PLUGINS)
+    );
+    if (!ret)
+        exit(SS_RC_LIBSTRONGSWAN_INTEGRITY);
+
+    switch (options.mode) {
+        case MODE_GENERATE:
+            generate_main(&options);
+            break;
+
+        default:
+            usage(&options);
+    }
+
+    return 0;
+}
+
+void usage(options_t *opts) {
+    if (opts->mode == MODE_GENERATE)
+        printf(
+            "Usage: creddy --generate --cn <name> [ --validity <day> ]\n"
+            "    cert will be in ${name}_ID.der, private key in ${name}_private.der\n"
+            "    default validity: 1080 days\n"
+        );
+
+    else if (opts->mode == MODE_VERIFY)
+        printf(
+            "Usage: identity --verify --cert <cert> [ --attrcert <cert> ]\n"
+            "    if attrcert is provided, verify that it was issued by cert\n"
+        );
+
+    else if (opts->mode == MODE_KEYID)
+        printf(
+            "Usage: identity --keyid --cert <cert>\n"
+        );
+
+    else if (opts->mode == MODE_ATTRIBUTE)
+        printf(
+            "Usage: identity --attribute \\\n"
+            "                --issuer <cert> --key <key> --role <role> \\\n"
+            "                --subject <cert> [ --subject-role <role> ] \\\n"
+            "                [ --validity <days> ] --out <file>\n"
+            "    default validity: 365 days\n"
+        );
+
+    else if (opts->mode == MODE_ROLES)
+        printf(
+            "Usage: identity --roles --cert <cert>\n"
+        );
+
+    else
+        printf(
+            "Usage: creddy [--<mode>] [--help]\n"
+            "    --generate:  generate X.509 identity cert and private key\n"
+            "    --verify:    check validity of X.509 ID or attribute cert\n"
+            "    --keyid:     get fingerprint from X.509 ID cert\n"
+            "    --attribute: generate an X.509 attribute cert\n"
+            "    --roles:     list roles from an X.509 attribute cert\n"
+        );
+
+
+    exit(1);
+}
+
+void *xmalloc(size_t len) {
+    void *ret = malloc(len);
+    if (ret == NULL)
+        err(1, "couldn't malloc %d bytes\n", len);
+    return ret;
+}
+
+char *xstrdup(char *string) {
+    char *dup = strdup(string);
+    if (dup == NULL)
+        err(1, "Can't dup %s", string);
+    return dup;
+}
+
+int clean_name(char *string) {
+    int i;
+
+    assert(string != NULL);
+
+    // must start with a letter
+    if (!isalpha(string[0]))
+        return 0;
+
+    // rest must be alphanumeric
+    for (i = 1; string[i] != '\0'; ++i)
+        if (!isalnum(string[i]))
+            return 0;
+
+    return 1;
+}
