{"id":1046,"date":"2016-06-07T17:52:46","date_gmt":"2016-06-07T17:52:46","guid":{"rendered":"http:\/\/www.gregkuchyt.net\/?p=1046"},"modified":"2017-05-23T17:56:32","modified_gmt":"2017-05-23T17:56:32","slug":"webauth-wa_keyring-importexport-patch","status":"publish","type":"post","link":"http:\/\/www.gregkuchyt.net\/?p=1046","title":{"rendered":"WebAuth wa_keyring import\/export patch"},"content":{"rendered":"<p>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\u00a0to 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.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">From d824d427eff88c318877d64e0dfe3b2a56e4191f Mon Sep 17 00:00:00 2001\r\nFrom: Greg Kuchyt &lt;gkuchyt@uvm.edu&gt;\r\nDate: Tue, 7 Jun 2016 08:44:37 -0400\r\nSubject: &#x5B;PATCH] Add export\/import functionality of individual keys in wa_keyring\r\n\r\n---\r\n tools\/wa_keyring.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++\r\n 1 files changed, 68 insertions(+), 0 deletions(-)\r\n\r\ndiff --git a\/tools\/wa_keyring.c b\/tools\/wa_keyring.c\r\nindex e78f7fb..44ad3b0 100644\r\n--- a\/tools\/wa_keyring.c\r\n+++ b\/tools\/wa_keyring.c\r\n@@ -32,6 +32,7 @@ Usage: %s &#x5B;-hv] -f &lt;keyring&gt; list\\n\\\r\n \\n\\\r\n Functions:\\n\\\r\n   add &lt;valid-after&gt;                 # add a new random key\\n\\\r\n+  export &lt;id&gt;                       # export key by id\\n\\\r\n   gc &lt;oldest-valid-after-to-keep&gt;   # garbage collect old keys\\n\\\r\n   list                              # list keys\\n\\\r\n   remove &lt;id&gt;                       # remove key by id\\n\\\r\n@@ -273,6 +274,60 @@ list_keyring(struct webauth_context *ctx, const char *keyring, bool verbose)\r\n     }\r\n }\r\n \r\n+\/*\r\n+ * Export the key at the given slot such that it can be imported into a\r\n+ * keyring on a different server. Thus allowing keys to be synchronized\r\n+ * across servers that have divergent key histories.\r\n+ *\/\r\n+static void\r\n+export_key(struct webauth_context *ctx, const char *keyring, unsigned long n)\r\n+{\r\n+    struct webauth_keyring *ring;\r\n+    struct webauth_keyring *newring;\r\n+    const char *newkeyring = &quot;export_wakeyring&quot;;\r\n+    struct webauth_keyring_entry *entry;\r\n+    int s;\r\n+\r\n+    s = webauth_keyring_read(ctx, keyring, &amp;ring);\r\n+    if (s != WA_ERR_NONE)\r\n+        die_webauth(ctx, s, &quot;cannot read keyring %s&quot;, keyring);\r\n+\r\n+    entry = &amp;APR_ARRAY_IDX(ring-&gt;entries, n, struct webauth_keyring_entry);\r\n+    newring = webauth_keyring_new(ctx, 1);\r\n+    webauth_keyring_add(ctx, newring, entry-&gt;creation, entry-&gt;valid_after, entry-&gt;key);\r\n+    s = webauth_keyring_write(ctx, newring, newkeyring);\r\n+    if (s != WA_ERR_NONE)\r\n+        die_webauth(ctx, s, &quot;cannot write new keyring %s&quot;, newkeyring);\r\n+}\r\n+\r\n+\/*\r\n+ * Import one keyring into another keyring. This allows keys from another\r\n+ * server to be synchronized with servers that have a divergent key history.\r\n+ *\/\r\n+static void\r\n+import_key(struct webauth_context *ctx, const char *keyring, const char *impkeyring) {\r\n+    struct webauth_keyring *ring;\r\n+    struct webauth_keyring *impring;\r\n+    struct webauth_keyring_entry *impentry;\r\n+    int s;\r\n+    size_t i;\r\n+\r\n+    s = webauth_keyring_read(ctx, keyring, &amp;ring);\r\n+    if (s != WA_ERR_NONE)\r\n+        die_webauth(ctx, s, &quot;cannot read keyring %s&quot;, keyring);\r\n+\r\n+    s = webauth_keyring_read(ctx, impkeyring, &amp;impring);\r\n+    if (s != WA_ERR_NONE)\r\n+        die_webauth(ctx, s, &quot;cannot read keyring %s&quot;, impkeyring);\r\n+\r\n+    for (i = 0; i &lt; (size_t) impring-&gt;entries-&gt;nelts; i++) {\r\n+        impentry = &amp;APR_ARRAY_IDX(impring-&gt;entries, i, struct webauth_keyring_entry);\r\n+        webauth_keyring_add(ctx, ring, impentry-&gt;creation, impentry-&gt;valid_after, impentry-&gt;key);\r\n+    }\r\n+    s = webauth_keyring_write(ctx, ring, keyring);\r\n+    if (s != WA_ERR_NONE)\r\n+        die_webauth(ctx, s, &quot;cannot write new keyring %s&quot;, keyring);\r\n+}\r\n \r\n \/*\r\n  * Add a new key to a keyring.  Takes the path to the keyring and the offset\r\n@@ -418,6 +473,19 @@ main(int argc, char **argv)\r\n         if (argc &gt; 0)\r\n             usage(1);\r\n         list_keyring(ctx, keyring, verbose);\r\n+    } else if (strcmp(command, &quot;export&quot;) == 0) {\r\n+        if (argc != 1)\r\n+            usage(1);\r\n+        errno = 0;\r\n+        id = strtoul(argv&#x5B;0], &amp;end, 10);\r\n+        if (errno != 0 || *end != '&#92;&#48;')\r\n+            die(&quot;invalid key id: %s&quot;, argv&#x5B;0]);\r\n+        export_key(ctx, keyring, id);\r\n+    } else if (strcmp(command, &quot;import&quot;) == 0) {\r\n+        if (argc != 1)\r\n+            usage(1);\r\n+        errno = 0;\r\n+        import_key(ctx, keyring, argv&#x5B;0]);\r\n     } else if (strcmp(command, &quot;add&quot;) == 0) {\r\n         if (argc != 1)\r\n             usage(1);\r\n-- \r\n1.7.1\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>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\u00a0to cut-over to [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":true,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[9],"tags":[],"class_list":["post-1046","post","type-post","status-publish","format-standard","hentry","category-work"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p4mwGD-gS","_links":{"self":[{"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/posts\/1046","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1046"}],"version-history":[{"count":6,"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/posts\/1046\/revisions"}],"predecessor-version":[{"id":1084,"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/posts\/1046\/revisions\/1084"}],"wp:attachment":[{"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1046"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1046"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.gregkuchyt.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1046"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}