From 0e19c4879193ed7fa61ad5d488f237b2b5b5d1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20Kl=C3=B6cker?= Date: Mon, 3 Jan 2022 16:25:40 +0100 Subject: [PATCH] core: New export mode to export secret subkeys. * src/gpgme.h.in (GPGME_EXPORT_MODE_SECRET_SUBKEY): New. * src/export.c (check_mode): Allow new mode and check for invalid combinations. (export_keys_start): Return error if new mode flag is set. * src/engine-gpg.c (export_common): Implement. * src/gpgme-tool.c (cmd_export): New option --secret-subkey. * tests/run-export.c (main): New option --secret-subkey. -- This adds support for exporting secret subkeys (via gpg's --export-secret-subkeys) to gpgme_op_export[_ext][_start]. The flag is not supported by gpgme_op_export_keys[_start] because there is no way to specify which subkey(s) to export with these functions. GnuPG-bug-id: 5757 --- NEWS | 3 +++ doc/gpgme.texi | 11 ++++++++++- src/engine-gpg.c | 7 +++++-- src/export.c | 17 +++++++++++++++-- src/gpgme-tool.c | 2 ++ src/gpgme.h.in | 1 + tests/run-export.c | 15 +++++++++++++++ 7 files changed, 51 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index e57637d5..1395c5db 100644 --- a/NEWS +++ b/NEWS @@ -5,11 +5,14 @@ Noteworthy changes in version 1.16.1 (unreleased) * New context flag "import-filter". [#5739] + * New export mode to export secret subkeys. [#5757] + * qt: Extend ChangeExpiryJob to change expiration of primary key and of subkeys at the same time. [#4717] * Interface changes relative to the 1.16.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + GPGME_EXPORT_MODE_SECRET_SUBKEY NEW. gpgme_set_ctx_flag EXTENDED: New flag 'key-origin'. gpgme_set_ctx_flag EXTENDED: New flag 'import-filter'. qt: ChangeExpiryJob::Option NEW. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 8c821989..216d3cde 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -4893,7 +4893,6 @@ OpenPGP key is exported in the OpenSSH public key format. This accepts just a single key; to force the export of a specific subkey a fingerprint pattern with an appended exclamation mark may be used. - @item GPGME_EXPORT_MODE_SECRET @since{1.6.0} @@ -4901,6 +4900,16 @@ 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_SECRET_SUBKEY +@since{1.17.0} + +If this bit is set, then a secret subkey is exported. The subkey to +export must be specified with fingerprint pattern with an appended +exclamation mark. This is currently only allowed for OpenPGP keys. +This flag may not be combined with @code{GPGME_EXPORT_MODE_EXTERN}. +This flag is not supported by the export functions that take an array +of keys. + @item GPGME_EXPORT_MODE_RAW @since{1.6.0} diff --git a/src/engine-gpg.c b/src/engine-gpg.c index fd39ad76..f619a646 100644 --- a/src/engine-gpg.c +++ b/src/engine-gpg.c @@ -2354,7 +2354,8 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, if ((mode & ~(GPGME_EXPORT_MODE_EXTERN |GPGME_EXPORT_MODE_MINIMAL |GPGME_EXPORT_MODE_SSH - |GPGME_EXPORT_MODE_SECRET))) + |GPGME_EXPORT_MODE_SECRET + |GPGME_EXPORT_MODE_SECRET_SUBKEY))) return gpg_error (GPG_ERR_NOT_SUPPORTED); if ((mode & GPGME_EXPORT_MODE_MINIMAL)) @@ -2379,7 +2380,9 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode, } else { - if ((mode & GPGME_EXPORT_MODE_SECRET)) + if ((mode & GPGME_EXPORT_MODE_SECRET_SUBKEY)) + err = add_arg (gpg, "--export-secret-subkeys"); + else if ((mode & GPGME_EXPORT_MODE_SECRET)) err = add_arg (gpg, "--export-secret-keys"); else err = add_arg (gpg, "--export"); diff --git a/src/export.c b/src/export.c index 637badf9..c5bcca6e 100644 --- a/src/export.c +++ b/src/export.c @@ -125,7 +125,8 @@ check_mode (gpgme_export_mode_t mode, gpgme_protocol_t protocol, |GPGME_EXPORT_MODE_SECRET |GPGME_EXPORT_MODE_SSH |GPGME_EXPORT_MODE_RAW - |GPGME_EXPORT_MODE_PKCS12))) + |GPGME_EXPORT_MODE_PKCS12 + |GPGME_EXPORT_MODE_SECRET_SUBKEY))) return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */ if ((mode & GPGME_EXPORT_MODE_SSH)) @@ -134,7 +135,8 @@ check_mode (gpgme_export_mode_t mode, gpgme_protocol_t protocol, |GPGME_EXPORT_MODE_MINIMAL |GPGME_EXPORT_MODE_SECRET |GPGME_EXPORT_MODE_RAW - |GPGME_EXPORT_MODE_PKCS12))) + |GPGME_EXPORT_MODE_PKCS12 + |GPGME_EXPORT_MODE_SECRET_SUBKEY))) return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ } @@ -151,6 +153,12 @@ check_mode (gpgme_export_mode_t mode, gpgme_protocol_t protocol, return gpg_error (GPG_ERR_INV_FLAG); /* Only supported for X.509. */ } + if ((mode & GPGME_EXPORT_MODE_SECRET_SUBKEY)) + { + if ((mode & GPGME_EXPORT_MODE_EXTERN)) + return gpg_error (GPG_ERR_INV_FLAG); /* Combination not allowed. */ + } + if ((mode & GPGME_EXPORT_MODE_EXTERN)) { if (keydata) @@ -369,6 +377,11 @@ export_keys_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t keys[], if (!keys) return gpg_error (GPG_ERR_INV_VALUE); + if ((mode & GPGME_EXPORT_MODE_SECRET_SUBKEY)) + { + return gpg_error (GPG_ERR_INV_FLAG); + } + /* Create a list of pattern from the keys. */ for (idx=nkeys=0; keys[idx]; idx++) if (keys[idx]->protocol == ctx->protocol) diff --git a/src/gpgme-tool.c b/src/gpgme-tool.c index 0dbc4a9e..b05664e3 100644 --- a/src/gpgme-tool.c +++ b/src/gpgme-tool.c @@ -2688,6 +2688,8 @@ cmd_export (assuan_context_t ctx, char *line) mode |= GPGME_EXPORT_MODE_MINIMAL; if (has_option (line, "--secret")) mode |= GPGME_EXPORT_MODE_SECRET; + if (has_option (line, "--secret-subkey")) + mode |= GPGME_EXPORT_MODE_SECRET_SUBKEY; if (has_option (line, "--raw")) mode |= GPGME_EXPORT_MODE_RAW; if (has_option (line, "--pkcs12")) diff --git a/src/gpgme.h.in b/src/gpgme.h.in index 5c74afd6..8a9cd259 100644 --- a/src/gpgme.h.in +++ b/src/gpgme.h.in @@ -407,6 +407,7 @@ gpgme_pinentry_mode_t; #define GPGME_EXPORT_MODE_RAW 32 #define GPGME_EXPORT_MODE_PKCS12 64 #define GPGME_EXPORT_MODE_SSH 256 +#define GPGME_EXPORT_MODE_SECRET_SUBKEY 512 typedef unsigned int gpgme_export_mode_t; diff --git a/tests/run-export.c b/tests/run-export.c index 623c7331..f071b8c2 100644 --- a/tests/run-export.c +++ b/tests/run-export.c @@ -128,6 +128,11 @@ main (int argc, char **argv) mode |= GPGME_EXPORT_MODE_SECRET; argc--; argv++; } + else if (!strcmp (*argv, "--secret-subkey")) + { + mode |= GPGME_EXPORT_MODE_SECRET_SUBKEY; + argc--; argv++; + } else if (!strcmp (*argv, "--raw")) { mode |= GPGME_EXPORT_MODE_RAW; @@ -165,6 +170,16 @@ main (int argc, char **argv) mode = GPGME_EXPORT_MODE_SSH; /* Set only this bit for this test. */ keyarray[0] = NULL; + err = gpgme_op_export_ext (ctx, (const char**)argv, mode, out); + fail_if_err (err); + } + else if ((mode & GPGME_EXPORT_MODE_SECRET_SUBKEY)) + { + keyarray[0] = NULL; + + printf ("exporting secret subkeys!\n"); + + gpgme_set_armor (ctx, 1); err = gpgme_op_export_ext (ctx, (const char**)argv, mode, out); fail_if_err (err); }