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
This commit is contained in:
Ingo Klöcker 2022-01-03 16:25:40 +01:00
parent 414bbdd53c
commit 0e19c48791
7 changed files with 51 additions and 5 deletions

3
NEWS
View File

@ -5,11 +5,14 @@ Noteworthy changes in version 1.16.1 (unreleased)
* New context flag "import-filter". [#5739] * New context flag "import-filter". [#5739]
* New export mode to export secret subkeys. [#5757]
* qt: Extend ChangeExpiryJob to change expiration of primary key * qt: Extend ChangeExpiryJob to change expiration of primary key
and of subkeys at the same time. [#4717] and of subkeys at the same time. [#4717]
* Interface changes relative to the 1.16.0 release: * 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 'key-origin'.
gpgme_set_ctx_flag EXTENDED: New flag 'import-filter'. gpgme_set_ctx_flag EXTENDED: New flag 'import-filter'.
qt: ChangeExpiryJob::Option NEW. qt: ChangeExpiryJob::Option NEW.

View File

@ -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 accepts just a single key; to force the export of a specific subkey
a fingerprint pattern with an appended exclamation mark may be used. a fingerprint pattern with an appended exclamation mark may be used.
@item GPGME_EXPORT_MODE_SECRET @item GPGME_EXPORT_MODE_SECRET
@since{1.6.0} @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 may not be combined with @code{GPGME_EXPORT_MODE_EXTERN}. For X.509
the export format is PKCS#8. 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 @item GPGME_EXPORT_MODE_RAW
@since{1.6.0} @since{1.6.0}

View File

@ -2354,7 +2354,8 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
if ((mode & ~(GPGME_EXPORT_MODE_EXTERN if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
|GPGME_EXPORT_MODE_MINIMAL |GPGME_EXPORT_MODE_MINIMAL
|GPGME_EXPORT_MODE_SSH |GPGME_EXPORT_MODE_SSH
|GPGME_EXPORT_MODE_SECRET))) |GPGME_EXPORT_MODE_SECRET
|GPGME_EXPORT_MODE_SECRET_SUBKEY)))
return gpg_error (GPG_ERR_NOT_SUPPORTED); return gpg_error (GPG_ERR_NOT_SUPPORTED);
if ((mode & GPGME_EXPORT_MODE_MINIMAL)) if ((mode & GPGME_EXPORT_MODE_MINIMAL))
@ -2379,7 +2380,9 @@ export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
} }
else 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"); err = add_arg (gpg, "--export-secret-keys");
else else
err = add_arg (gpg, "--export"); err = add_arg (gpg, "--export");

View File

@ -125,7 +125,8 @@ check_mode (gpgme_export_mode_t mode, gpgme_protocol_t protocol,
|GPGME_EXPORT_MODE_SECRET |GPGME_EXPORT_MODE_SECRET
|GPGME_EXPORT_MODE_SSH |GPGME_EXPORT_MODE_SSH
|GPGME_EXPORT_MODE_RAW |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. */ return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */
if ((mode & GPGME_EXPORT_MODE_SSH)) 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_MINIMAL
|GPGME_EXPORT_MODE_SECRET |GPGME_EXPORT_MODE_SECRET
|GPGME_EXPORT_MODE_RAW |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. */ 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. */ 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 ((mode & GPGME_EXPORT_MODE_EXTERN))
{ {
if (keydata) if (keydata)
@ -369,6 +377,11 @@ export_keys_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t keys[],
if (!keys) if (!keys)
return gpg_error (GPG_ERR_INV_VALUE); 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. */ /* Create a list of pattern from the keys. */
for (idx=nkeys=0; keys[idx]; idx++) for (idx=nkeys=0; keys[idx]; idx++)
if (keys[idx]->protocol == ctx->protocol) if (keys[idx]->protocol == ctx->protocol)

View File

@ -2688,6 +2688,8 @@ cmd_export (assuan_context_t ctx, char *line)
mode |= GPGME_EXPORT_MODE_MINIMAL; mode |= GPGME_EXPORT_MODE_MINIMAL;
if (has_option (line, "--secret")) if (has_option (line, "--secret"))
mode |= GPGME_EXPORT_MODE_SECRET; mode |= GPGME_EXPORT_MODE_SECRET;
if (has_option (line, "--secret-subkey"))
mode |= GPGME_EXPORT_MODE_SECRET_SUBKEY;
if (has_option (line, "--raw")) if (has_option (line, "--raw"))
mode |= GPGME_EXPORT_MODE_RAW; mode |= GPGME_EXPORT_MODE_RAW;
if (has_option (line, "--pkcs12")) if (has_option (line, "--pkcs12"))

View File

@ -407,6 +407,7 @@ gpgme_pinentry_mode_t;
#define GPGME_EXPORT_MODE_RAW 32 #define GPGME_EXPORT_MODE_RAW 32
#define GPGME_EXPORT_MODE_PKCS12 64 #define GPGME_EXPORT_MODE_PKCS12 64
#define GPGME_EXPORT_MODE_SSH 256 #define GPGME_EXPORT_MODE_SSH 256
#define GPGME_EXPORT_MODE_SECRET_SUBKEY 512
typedef unsigned int gpgme_export_mode_t; typedef unsigned int gpgme_export_mode_t;

View File

@ -128,6 +128,11 @@ main (int argc, char **argv)
mode |= GPGME_EXPORT_MODE_SECRET; mode |= GPGME_EXPORT_MODE_SECRET;
argc--; argv++; argc--; argv++;
} }
else if (!strcmp (*argv, "--secret-subkey"))
{
mode |= GPGME_EXPORT_MODE_SECRET_SUBKEY;
argc--; argv++;
}
else if (!strcmp (*argv, "--raw")) else if (!strcmp (*argv, "--raw"))
{ {
mode |= GPGME_EXPORT_MODE_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. */ mode = GPGME_EXPORT_MODE_SSH; /* Set only this bit for this test. */
keyarray[0] = NULL; 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); err = gpgme_op_export_ext (ctx, (const char**)argv, mode, out);
fail_if_err (err); fail_if_err (err);
} }