• Archives

  • Categories


 
WebAuth wa_keyring import/export patch Posted on 06.07.2016 by greg.kuchyt

I had a need to export individual keys from the keyrings used by our WebKDC and main WebLogin servers to ensure that our dev pool and production pool had a common key from which to pivot around. This allowed the previous keys used to still be valid but also provide the shared key to cut-over to our next-gen servers. Digging into the keyring.c library I noticed that most of the framework was already in the library and that only a couple accessory functions needed to be written for the wa_keyring binary. The patch for this is below.

From d824d427eff88c318877d64e0dfe3b2a56e4191f Mon Sep 17 00:00:00 2001
From: Greg Kuchyt <gkuchyt@uvm.edu>
Date: Tue, 7 Jun 2016 08:44:37 -0400
Subject: [PATCH] Add export/import functionality of individual keys in wa_keyring

---
 tools/wa_keyring.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/tools/wa_keyring.c b/tools/wa_keyring.c
index e78f7fb..44ad3b0 100644
--- a/tools/wa_keyring.c
+++ b/tools/wa_keyring.c
@@ -32,6 +32,7 @@ Usage: %s [-hv] -f <keyring> list\n\
 \n\
 Functions:\n\
   add <valid-after>                 # add a new random key\n\
+  export <id>                       # export key by id\n\
   gc <oldest-valid-after-to-keep>   # garbage collect old keys\n\
   list                              # list keys\n\
   remove <id>                       # remove key by id\n\
@@ -273,6 +274,60 @@ list_keyring(struct webauth_context *ctx, const char *keyring, bool verbose)
     }
 }
 
+/*
+ * Export the key at the given slot such that it can be imported into a
+ * keyring on a different server. Thus allowing keys to be synchronized
+ * across servers that have divergent key histories.
+ */
+static void
+export_key(struct webauth_context *ctx, const char *keyring, unsigned long n)
+{
+    struct webauth_keyring *ring;
+    struct webauth_keyring *newring;
+    const char *newkeyring = "export_wakeyring";
+    struct webauth_keyring_entry *entry;
+    int s;
+
+    s = webauth_keyring_read(ctx, keyring, &ring);
+    if (s != WA_ERR_NONE)
+        die_webauth(ctx, s, "cannot read keyring %s", keyring);
+
+    entry = &APR_ARRAY_IDX(ring->entries, n, struct webauth_keyring_entry);
+    newring = webauth_keyring_new(ctx, 1);
+    webauth_keyring_add(ctx, newring, entry->creation, entry->valid_after, entry->key);
+    s = webauth_keyring_write(ctx, newring, newkeyring);
+    if (s != WA_ERR_NONE)
+        die_webauth(ctx, s, "cannot write new keyring %s", newkeyring);
+}
+
+/*
+ * Import one keyring into another keyring. This allows keys from another
+ * server to be synchronized with servers that have a divergent key history.
+ */
+static void
+import_key(struct webauth_context *ctx, const char *keyring, const char *impkeyring) {
+    struct webauth_keyring *ring;
+    struct webauth_keyring *impring;
+    struct webauth_keyring_entry *impentry;
+    int s;
+    size_t i;
+
+    s = webauth_keyring_read(ctx, keyring, &ring);
+    if (s != WA_ERR_NONE)
+        die_webauth(ctx, s, "cannot read keyring %s", keyring);
+
+    s = webauth_keyring_read(ctx, impkeyring, &impring);
+    if (s != WA_ERR_NONE)
+        die_webauth(ctx, s, "cannot read keyring %s", impkeyring);
+
+    for (i = 0; i < (size_t) impring->entries->nelts; i++) {
+        impentry = &APR_ARRAY_IDX(impring->entries, i, struct webauth_keyring_entry);
+        webauth_keyring_add(ctx, ring, impentry->creation, impentry->valid_after, impentry->key);
+    }
+    s = webauth_keyring_write(ctx, ring, keyring);
+    if (s != WA_ERR_NONE)
+        die_webauth(ctx, s, "cannot write new keyring %s", keyring);
+}
 
 /*
  * Add a new key to a keyring.  Takes the path to the keyring and the offset
@@ -418,6 +473,19 @@ main(int argc, char **argv)
         if (argc > 0)
             usage(1);
         list_keyring(ctx, keyring, verbose);
+    } else if (strcmp(command, "export") == 0) {
+        if (argc != 1)
+            usage(1);
+        errno = 0;
+        id = strtoul(argv[0], &end, 10);
+        if (errno != 0 || *end != '\0')
+            die("invalid key id: %s", argv[0]);
+        export_key(ctx, keyring, id);
+    } else if (strcmp(command, "import") == 0) {
+        if (argc != 1)
+            usage(1);
+        errno = 0;
+        import_key(ctx, keyring, argv[0]);
     } else if (strcmp(command, "add") == 0) {
         if (argc != 1)
             usage(1);
-- 
1.7.1