Add an export secret key feature.
authorWerner Koch <wk@gnupg.org>
Mon, 24 Aug 2015 10:41:24 +0000 (12:41 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 24 Aug 2015 10:41:24 +0000 (12:41 +0200)
* src/gpgme.h.in (GPGME_EXPORT_MODE_SECRET): New.
(GPGME_EXPORT_MODE_RAW): New.
(GPGME_EXPORT_MODE_PKCS12): New.
* src/export.c (export_start, export_ext_start): Allow new flags.
* src/engine-gpg.c (export_common): Support secret key export.
* src/engine-gpgsm.c (gpgsm_export, gpgsm_export_ext): Ditto.

* src/gpgme-tool.c (cmd_export): Add options --secret, --raw,
and --pkcs12.
* tests/run-export.c (main): Likewise.
--

Note that exporting secret X.509 keys requires GnuPG 2.1.8.

Signed-off-by: Werner Koch <wk@gnupg.org>
doc/gpgme.texi
src/engine-gpg.c
src/engine-gpgsm.c
src/export.c
src/gpgme-tool.c
src/gpgme.h.in
tests/run-export.c

index 010b914..20e1912 100644 (file)
@@ -3700,6 +3700,21 @@ keys it removes all signatures except for the latest self-signatures.
 For X.509 keys it has no effect.
 
 
+@item GPGME_EXPORT_MODE_SECRET
+Instead of exporting the public key, the secret key is exported.  This
+may not be combined with @code{GPGME_EXPORT_MODE_EXTERN}.  For X.509
+the export format is PKCS#8.
+
+@item GPGME_EXPORT_MODE_RAW
+If this flag is used with @code{GPGME_EXPORT_MODE_SECRET} for an X.509
+key the export format will be changed to PKCS#1.  This flag may not be
+used with OpenPGP.
+
+@item GPGME_EXPORT_MODE_PKCS12
+If this flag is used with @code{GPGME_EXPORT_MODE_SECRET} for an X.509
+key the export format will be changed to PKCS#12 which also includes
+the certificate.  This flag may not be used with OpenPGP.
+
 @end table
 
 
index d138592..ffae2fe 100644 (file)
@@ -1793,7 +1793,8 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
   gpgme_error_t err = 0;
 
   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
-                |GPGME_EXPORT_MODE_MINIMAL)))
+                |GPGME_EXPORT_MODE_MINIMAL
+                |GPGME_EXPORT_MODE_SECRET)))
     return gpg_error (GPG_ERR_NOT_SUPPORTED);
 
   if ((mode & GPGME_EXPORT_MODE_MINIMAL))
@@ -1807,7 +1808,10 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
     }
   else
     {
-      err = add_arg (gpg, "--export");
+      if ((mode & GPGME_EXPORT_MODE_SECRET))
+        err = add_arg (gpg, "--export-secret-keys");
+      else
+        err = add_arg (gpg, "--export");
       if (!err && use_armor)
         err = add_arg (gpg, "--armor");
       if (!err)
index 3771157..24d3b2a 100644 (file)
@@ -1289,17 +1289,23 @@ gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
   if (!gpgsm)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  if (mode)
-    return gpg_error (GPG_ERR_NOT_SUPPORTED);
-
   if (!pattern)
     pattern = "";
 
-  cmd = malloc (7 + strlen (pattern) + 1);
+  cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
   if (!cmd)
     return gpg_error_from_syserror ();
+
   strcpy (cmd, "EXPORT ");
-  strcpy (&cmd[7], pattern);
+  if ((mode & GPGME_EXPORT_MODE_SECRET))
+    {
+      strcat (cmd, "--secret ");
+      if ((mode & GPGME_EXPORT_MODE_RAW))
+        strcat (cmd, "--raw ");
+      else if ((mode & GPGME_EXPORT_MODE_PKCS12))
+        strcat (cmd, "--pkcs12 ");
+    }
+  strcat (cmd, pattern);
 
   gpgsm->output_cb.data = keydata;
   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
@@ -1323,16 +1329,13 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
   engine_gpgsm_t gpgsm = engine;
   gpgme_error_t err = 0;
   char *line;
-  /* Length is "EXPORT " + p + '\0'.  */
-  int length = 7 + 1;
+  /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'.  */
+  int length = 7 + 9 + 9 + 1;
   char *linep;
 
   if (!gpgsm)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  if (mode)
-    return gpg_error (GPG_ERR_NOT_SUPPORTED);
-
   if (pattern && *pattern)
     {
       const char **pat = pattern;
@@ -1357,7 +1360,15 @@ gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
     return gpg_error_from_syserror ();
 
   strcpy (line, "EXPORT ");
-  linep = &line[7];
+  if ((mode & GPGME_EXPORT_MODE_SECRET))
+    {
+      strcat (line, "--secret ");
+      if ((mode & GPGME_EXPORT_MODE_RAW))
+        strcat (line, "--raw ");
+      else if ((mode & GPGME_EXPORT_MODE_PKCS12))
+        strcat (line, "--pkcs12 ");
+    }
+  linep = &line[strlen (line)];
 
   if (pattern && *pattern)
     {
index 8930aa6..a29fbde 100644 (file)
@@ -120,9 +120,24 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern,
   op_data_t opd;
 
   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
-                |GPGME_EXPORT_MODE_MINIMAL)))
+                |GPGME_EXPORT_MODE_MINIMAL
+                |GPGME_EXPORT_MODE_SECRET
+                |GPGME_EXPORT_MODE_RAW
+                |GPGME_EXPORT_MODE_PKCS12)))
     return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE.  */
 
+  if ((mode & GPGME_EXPORT_MODE_SECRET))
+    {
+      if ((mode & GPGME_EXPORT_MODE_EXTERN))
+        return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
+      if ((mode & GPGME_EXPORT_MODE_RAW)
+          && (mode & GPGME_EXPORT_MODE_PKCS12))
+        return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
+
+      if (ctx->protocol != GPGME_PROTOCOL_CMS
+          && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12)))
+        return gpg_error (GPG_ERR_INV_FLAG);  /* Only supported for X.509.  */
+    }
 
   if ((mode & GPGME_EXPORT_MODE_EXTERN))
     {
@@ -199,9 +214,25 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
   op_data_t opd;
 
   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
-                |GPGME_EXPORT_MODE_MINIMAL)))
+                |GPGME_EXPORT_MODE_MINIMAL
+                |GPGME_EXPORT_MODE_SECRET
+                |GPGME_EXPORT_MODE_RAW
+                |GPGME_EXPORT_MODE_PKCS12)))
     return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE.  */
 
+  if ((mode & GPGME_EXPORT_MODE_SECRET))
+    {
+      if ((mode & GPGME_EXPORT_MODE_EXTERN))
+        return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
+      if ((mode & GPGME_EXPORT_MODE_RAW)
+          && (mode & GPGME_EXPORT_MODE_PKCS12))
+        return gpg_error (GPG_ERR_INV_FLAG);  /* Combination not allowed. */
+
+      if (ctx->protocol != GPGME_PROTOCOL_CMS
+          && (mode & (GPGME_EXPORT_MODE_RAW|GPGME_EXPORT_MODE_PKCS12)))
+        return gpg_error (GPG_ERR_INV_FLAG);  /* Only supported for X.509.  */
+    }
+
   if ((mode & GPGME_EXPORT_MODE_EXTERN))
     {
       if (keydata)
index 94d1124..e5e5707 100644 (file)
@@ -3054,7 +3054,7 @@ cmd_import (assuan_context_t ctx, char *line)
 
 
 static const char hlp_export[] =
-  "EXPORT [--extern] [--minimal] [<pattern>]\n"
+  "EXPORT [--extern] [--minimal] [--secret [--pkcs12] [--raw]] [<pattern>]\n"
   "\n"
   "Export the keys described by PATTERN.  Write the\n"
   "the output to the object set by the last OUTPUT command.";
@@ -3082,6 +3082,12 @@ cmd_export (assuan_context_t ctx, char *line)
     mode |= GPGME_EXPORT_MODE_EXTERN;
   if (has_option (line, "--minimal"))
     mode |= GPGME_EXPORT_MODE_MINIMAL;
+  if (has_option (line, "--secret"))
+    mode |= GPGME_EXPORT_MODE_SECRET;
+  if (has_option (line, "--raw"))
+    mode |= GPGME_EXPORT_MODE_RAW;
+  if (has_option (line, "--pkcs12"))
+    mode |= GPGME_EXPORT_MODE_PKCS12;
 
   line = skip_options (line);
 
index 8255e63..7605570 100644 (file)
@@ -392,6 +392,9 @@ gpgme_pinentry_mode_t;
 /* The available export mode flags.  */
 #define GPGME_EXPORT_MODE_EXTERN                2
 #define GPGME_EXPORT_MODE_MINIMAL               4
+#define GPGME_EXPORT_MODE_SECRET               16
+#define GPGME_EXPORT_MODE_RAW                  32
+#define GPGME_EXPORT_MODE_PKCS12               64
 
 typedef unsigned int gpgme_export_mode_t;
 
index 4333208..b133f13 100644 (file)
@@ -43,7 +43,12 @@ show_usage (int ex)
   fputs ("usage: " PGM " [options] USERIDS\n\n"
          "Options:\n"
          "  --verbose        run in verbose mode\n"
+         "  --openpgp        use OpenPGP protocol (default)\n"
+         "  --cms            use X.509 protocol\n"
          "  --extern         send keys to the keyserver (TAKE CARE!)\n"
+         "  --secret         export secret keys instead of public keys\n"
+         "  --raw            use PKCS#1 as secret key format\n"
+         "  --pkcs12         use PKCS#12 as secret key format\n"
          , stderr);
   exit (ex);
 }
@@ -59,6 +64,7 @@ main (int argc, char **argv)
   gpgme_key_t keyarray[100];
   int keyidx = 0;
   gpgme_data_t out;
+  gpgme_protocol_t protocol = GPGME_PROTOCOL_OpenPGP;
   gpgme_export_mode_t mode = 0;
 
   if (argc)
@@ -79,9 +85,34 @@ main (int argc, char **argv)
           verbose = 1;
           argc--; argv++;
         }
+      else if (!strcmp (*argv, "--openpgp"))
+        {
+          protocol = GPGME_PROTOCOL_OpenPGP;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--cms"))
+        {
+          protocol = GPGME_PROTOCOL_CMS;
+          argc--; argv++;
+        }
       else if (!strcmp (*argv, "--extern"))
         {
-          mode |= GPGME_KEYLIST_MODE_EXTERN;
+          mode |= GPGME_EXPORT_MODE_EXTERN;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--secret"))
+        {
+          mode |= GPGME_EXPORT_MODE_SECRET;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--raw"))
+        {
+          mode |= GPGME_EXPORT_MODE_RAW;
+          argc--; argv++;
+        }
+      else if (!strcmp (*argv, "--pkcs12"))
+        {
+          mode |= GPGME_EXPORT_MODE_PKCS12;
           argc--; argv++;
         }
       else if (!strncmp (*argv, "--", 2))
@@ -92,11 +123,11 @@ main (int argc, char **argv)
   if (!argc)
     show_usage (1);
 
-  init_gpgme (GPGME_PROTOCOL_OpenPGP);
+  init_gpgme (protocol);
 
   err = gpgme_new (&ctx);
   fail_if_err (err);
-  gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
+  gpgme_set_protocol (ctx, protocol);
 
   /* Lookup the keys.  */
   err = gpgme_op_keylist_ext_start (ctx, (const char**)argv, 0, 0);
@@ -131,8 +162,10 @@ main (int argc, char **argv)
     }
 
   /* Now for the actual export.  */
-  if ((mode & GPGME_KEYLIST_MODE_EXTERN))
+  if ((mode & GPGME_EXPORT_MODE_EXTERN))
     printf ("sending keys to keyserver\n");
+  if ((mode & GPGME_EXPORT_MODE_SECRET))
+    printf ("exporting secret keys!\n");
 
   err = gpgme_data_new (&out);
   fail_if_err (err);