gpg: Add export options "export-pka" and "export-dane".
authorWerner Koch <wk@gnupg.org>
Thu, 7 Jul 2016 15:02:58 +0000 (17:02 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 7 Jul 2016 15:35:20 +0000 (17:35 +0200)
* g10/options.h (EXPORT_PKA_FORMAT): New.
* g10/keylist.c (list_keyblock_pka): Do not use DANE flag.
* g10/export.c: Include zb32.h.
(parse_export_options): Add options "export-pka" and "export-dane".
(do_export): Do not armor if either of these option is set.
(print_pka_or_dane_records): New.
(do_export_stream): Implement new options.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/gpg.texi
g10/export.c
g10/keylist.c
g10/options.h

index 11d3a65..ae860d7 100644 (file)
@@ -2320,6 +2320,18 @@ opposite meaning. The options are:
   most recent self-signature on each user ID. This option is the same as
   running the @option{--edit-key} command "minimize" before export except
   that the local copy of the key is not modified. Defaults to no.
+
+  @item export-pka
+  Instead of outputting the key material output PKA records suitable
+  to put into DNS zone files.  An ORIGIN line is printed before each
+  record to allow diverting the records to the corresponding zone file.
+
+  @item export-dane
+  Instead of outputting the key material output OpenPGP DANE records
+  suitable to put into DNS zone files.  An ORIGIN line is printed before
+  each record to allow diverting the records to the corresponding zone
+  file.
+
 @end table
 
 @item --with-colons
index c5b7328..d31b09a 100644 (file)
@@ -35,6 +35,7 @@
 #include "i18n.h"
 #include "membuf.h"
 #include "host2net.h"
+#include "zb32.h"
 #include "recsel.h"
 #include "mbox-util.h"
 #include "init.h"
@@ -103,6 +104,10 @@ parse_export_options(char *str,unsigned int *options,int noisy)
        N_("remove unusable parts from key during export")},
       {"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL,
        N_("remove as much as possible from key during export")},
+
+      {"export-pka", EXPORT_PKA_FORMAT, NULL, NULL },
+      {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL },
+
       /* Aliases for backward compatibility */
       {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
       {"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL},
@@ -316,7 +321,7 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options,
   if (rc)
     return rc;
 
-  if ( opt.armor )
+  if ( opt.armor && !(options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)) )
     {
       afx = new_armor_context ();
       afx->what = secret? 5 : 1;
@@ -1245,9 +1250,8 @@ apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
         {
           if (!recsel_select (selector, filter_getval, node))
             {
-
-              log_debug ("keep-uid: deleting '%s'\n",
-                         node->pkt->pkt.user_id->name);
+              /* log_debug ("keep-uid: deleting '%s'\n", */
+              /*            node->pkt->pkt.user_id->name); */
               /* The UID packet and all following packets up to the
                * next UID or a subkey.  */
               delete_kbnode (node);
@@ -1258,14 +1262,101 @@ apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
                    node = node->next)
                 delete_kbnode (node->next);
            }
-          else
-            log_debug ("keep-uid: keeping '%s'\n",
-                       node->pkt->pkt.user_id->name);
+          /* else */
+          /*   log_debug ("keep-uid: keeping '%s'\n", */
+          /*              node->pkt->pkt.user_id->name); */
         }
     }
 }
 
 
+/* Print DANE or PKA records for all user IDs in KEYBLOCK to the
+ * stream FP.  The data for the record is taken from HEXDATA.  HEXFPR
+ * is the fingerprint of the primary key.  */
+static gpg_error_t
+print_pka_or_dane_records (kbnode_t keyblock, const char *hexdata,
+                           const char *hexfpr, estream_t fp,
+                           int print_pka, int print_dane)
+{
+  gpg_error_t err = 0;
+  kbnode_t kbctx, node;
+  PKT_user_id *uid;
+  char *mbox = NULL;
+  char hashbuf[32];
+  char *hash = NULL;
+  char *domain;
+  const char *s;
+  unsigned int len;
+
+  for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
+    {
+      if (node->pkt->pkttype != PKT_USER_ID)
+        continue;
+      uid = node->pkt->pkt.user_id;
+
+      if (uid->is_expired || uid->is_revoked)
+        continue;
+
+      xfree (mbox);
+      mbox = mailbox_from_userid (uid->name);
+      if (!mbox)
+        continue;
+
+      domain = strchr (mbox, '@');
+      *domain++ = 0;
+
+      if (print_pka)
+        {
+          es_fprintf (fp, "$ORIGIN _pka.%s.\n; %s\n; ", domain, hexfpr);
+          print_utf8_buffer (fp, uid->name, uid->len);
+          es_putc ('\n', fp);
+          gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
+          xfree (hash);
+          hash = zb32_encode (hashbuf, 8*20);
+          if (!hash)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          len = strlen (hexfpr)/2;
+          es_fprintf (fp, "%s TYPE37 \\# %u 0006 0000 00 %02X %s\n\n",
+                      hash, 6 + len, len, hexfpr);
+        }
+
+      if (print_dane && hexdata)
+        {
+          es_fprintf (fp, "$ORIGIN _openpgpkey.%s.\n; %s\n; ", domain, hexfpr);
+          print_utf8_buffer (fp, uid->name, uid->len);
+          es_putc ('\n', fp);
+          gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox));
+          xfree (hash);
+          hash = bin2hex (hashbuf, 28, NULL);
+          if (!hash)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          ascii_strlwr (hash);
+          len = strlen (hexdata)/2;
+          es_fprintf (fp, "%s TYPE61 \\# %u (\n", hash, len);
+          for (s = hexdata; ;)
+            {
+              es_fprintf (fp, "\t%.64s\n", s);
+              if (strlen (s) < 64)
+                break;
+              s += 64;
+            }
+          es_fputs ("\t)\n\n", fp);
+        }
+    }
+
+ leave:
+  xfree (hash);
+  xfree (mbox);
+  return err;
+}
+
+
 /* Helper for do_export_stream which writes one keyblock to OUT.  */
 static gpg_error_t
 do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
@@ -1572,6 +1663,7 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   strlist_t sl;
   gcry_cipher_hd_t cipherhd = NULL;
   struct export_stats_s dummystats;
+  iobuf_t out_help = NULL;
 
   if (!stats)
     stats = &dummystats;
@@ -1581,10 +1673,14 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
   if (!kdbhd)
     return gpg_error_from_syserror ();
 
-  /* For the DANE format override the options.  */
-  if ((options & EXPORT_DANE_FORMAT))
-    options = (EXPORT_DANE_FORMAT | EXPORT_MINIMAL | EXPORT_CLEAN);
-
+  /* For the PKA and DANE format open a helper iobuf and for DANE
+   * enforce some options.  */
+  if ((options & (EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT)))
+    {
+      out_help = iobuf_temp ();
+      if ((options & EXPORT_DANE_FORMAT))
+        options |= EXPORT_MINIMAL | EXPORT_CLEAN;
+    }
 
   if (!users)
     {
@@ -1731,8 +1827,9 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
         }
 
       /* And write it. */
-      err = do_export_one_keyblock (ctrl, keyblock, keyid, out, secret,
-                                    options, stats, any,
+      err = do_export_one_keyblock (ctrl, keyblock, keyid,
+                                    out_help? out_help : out,
+                                    secret, options, stats, any,
                                     desc, ndesc, descindex, cipherhd);
       if (err)
         break;
@@ -1742,11 +1839,65 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
           *keyblock_out = keyblock;
           break;
         }
+
+      if (out_help)
+        {
+          /* We want to write PKA or DANE records.  OUT_HELP has the
+           * keyblock and we print a record for each uid to OUT. */
+          char *hexdata;
+          const void *data;
+          void *vp;
+          size_t datalen;
+          estream_t fp;
+
+          iobuf_flush_temp (out_help);
+          data = iobuf_get_temp_buffer (out_help);
+          datalen = iobuf_get_temp_length (out_help);
+          hexdata = bin2hex (data, datalen, NULL);
+          if (!hexdata)
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          iobuf_close (out_help);
+          out_help = iobuf_temp ();
+          ascii_strlwr (hexdata);
+          fp = es_fopenmem (0, "rw,samethread");
+          if (!fp)
+            {
+              err = gpg_error_from_syserror ();
+              xfree (hexdata);
+              goto leave;
+            }
+
+          {
+            char *hexfpr = hexfingerprint (pk, NULL, 0);
+            err = print_pka_or_dane_records (keyblock, hexdata, hexfpr, fp,
+                                             (options & EXPORT_PKA_FORMAT),
+                                             (options & EXPORT_DANE_FORMAT));
+            xfree (hexfpr);
+          }
+          xfree (hexdata);
+          if (err)
+            {
+              es_fclose (fp);
+              goto leave;
+            }
+          es_fputc (0, fp);
+          if (es_fclose_snatch (fp, &vp, NULL))
+            {
+              err = gpg_error_from_syserror ();
+              goto leave;
+            }
+          iobuf_writestr (out, vp);
+        }
+
     }
   if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
     err = 0;
 
  leave:
+  iobuf_cancel (out_help);
   gcry_cipher_close (cipherhd);
   xfree(desc);
   keydb_release (kdbhd);
index e595fe3..b8f97f5 100644 (file)
@@ -921,7 +921,7 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
       /* We do not have an export function which allows to pass a
          keyblock, thus we need to search the key again.  */
       err = export_pubkey_buffer (ctrl, hexfpr,
-                                  EXPORT_DANE_FORMAT, NULL,
+                                  (EXPORT_MINIMAL | EXPORT_CLEAN), NULL,
                                   &dummy_keyblock, &data, &datalen);
       release_kbnode (dummy_keyblock);
       if (!err)
index fc333cd..2b3cabd 100644 (file)
@@ -348,7 +348,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
 #define EXPORT_RESET_SUBKEY_PASSWD       (1<<3)
 #define EXPORT_MINIMAL                   (1<<4)
 #define EXPORT_CLEAN                     (1<<5)
-#define EXPORT_DANE_FORMAT               (1<<6)
+#define EXPORT_PKA_FORMAT                (1<<6)
+#define EXPORT_DANE_FORMAT               (1<<7)
 
 #define LIST_SHOW_PHOTOS                 (1<<0)
 #define LIST_SHOW_POLICY_URLS            (1<<1)