Add new functions to import and export keys specified by gpgme_key_t.

Allow  exporting keys to a keyserver.
This commit is contained in:
Werner Koch 2009-06-16 11:42:21 +00:00
parent 59eecf421e
commit b872605941
22 changed files with 1005 additions and 92 deletions

14
NEWS
View File

@ -1,4 +1,4 @@
Noteworthy changes in version 1.1.9 Noteworthy changes in version 1.2.0
------------------------------------------------ ------------------------------------------------
* New encryption flag GPGME_ENCRYPT_NO_ENCRYPT_TO to disable default * New encryption flag GPGME_ENCRYPT_NO_ENCRYPT_TO to disable default
@ -11,7 +11,6 @@ Noteworthy changes in version 1.1.9
* New functions gpgme_io_read and gpgme_io_write for use with * New functions gpgme_io_read and gpgme_io_write for use with
gpgme_passphrase_cb_t and gpgme_edit_cb_t functions. gpgme_passphrase_cb_t and gpgme_edit_cb_t functions.
* Interface changes relative to the 1.1.7 release: * Interface changes relative to the 1.1.7 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GPGME_KEYLIST_MODE_EPHEMERAL NEW. GPGME_KEYLIST_MODE_EPHEMERAL NEW.
@ -22,12 +21,23 @@ Noteworthy changes in version 1.1.9
gpgme_op_assuan_transact_start NEW. gpgme_op_assuan_transact_start NEW.
gpgme_op_assuan_transact NEW. gpgme_op_assuan_transact NEW.
gpgme_op_assuan_result NEW. gpgme_op_assuan_result NEW.
gpgme_op_import_keys NEW.
gpgme_op_import_keys_start NEW.
gpgme_subkey_t EXTENDED: New fields is_cardkey, card_number. gpgme_subkey_t EXTENDED: New fields is_cardkey, card_number.
GPGME_ENCRYPT_NO_ENCRYPT_TO NEW. GPGME_ENCRYPT_NO_ENCRYPT_TO NEW.
gpgme_check_version CHANGED: Is now a macro. gpgme_check_version CHANGED: Is now a macro.
gpgme_new EXTENDED: More failure codes. gpgme_new EXTENDED: More failure codes.
gpgme_io_read NEW. gpgme_io_read NEW.
gpgme_io_write NEW. gpgme_io_write NEW.
gpgme_result_ref NEW.
gpgme_result_unref NEW.
gpgme_export_mode_t NEW.
gpgme_export_ext_start EXTENDED: Arg RESERVED is now a MODE flag.
gpgme_op_export EXTENDED: Arg RESERVED is now a MODE flag.
gpgme_op_export_ext_start EXTENDED: Arg RESERVED is now a MODE flag.
gpgme_op_export_ext EXTENDED: Arg RESERVED is now a MODE flag.
gpgme_op_export_keys_start NEW.
gpgme_op_export_keys NEW.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

18
TODO
View File

@ -1,4 +1,4 @@
Hey Emacs, this is -*- outline -*- mode! Hey Emacs, this is -*- org -*- mode!
* IMPORTANT * IMPORTANT
** When using descriptor passing, we need to set the fd to blocking before ** When using descriptor passing, we need to set the fd to blocking before
@ -24,7 +24,7 @@ Hey Emacs, this is -*- outline -*- mode!
(see edit.c::command_handler). (see edit.c::command_handler).
** I/O and User Data could be made extensible. But this can be done ** I/O and User Data could be made extensible. But this can be done
without breaking the ABI hopefully. without breaking the ABI hopefully.
* All enums that should be enums need to have a maximum value to ensure ** All enums that should be enums need to have a maximum value to ensure
a certain minimum width for extensibility. a certain minimum width for extensibility.
** Compatibility interfaces that can be removed in future versions: ** Compatibility interfaces that can be removed in future versions:
*** gpgme_data_new_from_filepart *** gpgme_data_new_from_filepart
@ -68,9 +68,15 @@ Hey Emacs, this is -*- outline -*- mode!
application can then do whatever is required. There are other application can then do whatever is required. There are other
usages too. This notfication system should be independent of any usages too. This notfication system should be independent of any
contextes of course. contextes of course.
Not sure whether this is still required. GPGME_PROTOCOL_ASSUAN is
sufficient for this.
** --learn-code support ** --learn-code support
This might be integrated with import. we still need to work out how This might be integrated with import. we still need to work out how
to learn a card when gpg and gpgsm have support for smartcards. to learn a card when gpg and gpgsm have support for smartcards. In
GPA we currently invoke gpg directly.
** Might need a stat() for data objects and use it for length param to gpg. ** Might need a stat() for data objects and use it for length param to gpg.
** Implement support for photo ids. ** Implement support for photo ids.
** Allow selection of subkeys ** Allow selection of subkeys
@ -82,6 +88,7 @@ Hey Emacs, this is -*- outline -*- mode!
*** Allow to export secret keys. *** Allow to export secret keys.
Rejected because this is conceptually flawed. Secret keys on a Rejected because this is conceptually flawed. Secret keys on a
smart card can not be exported, for example. smart card can not be exported, for example.
May eventually e supproted with a keywrapping system.
*** Selecting the key ring, setting the version or comment in output. *** Selecting the key ring, setting the version or comment in output.
Rejected because the naive implementation is engine specific, the Rejected because the naive implementation is engine specific, the
configuration is part of the engine's configuration or readily configuration is part of the engine's configuration or readily
@ -110,6 +117,11 @@ Hey Emacs, this is -*- outline -*- mode!
(it's an internal error, as select_protocol checks already). (it's an internal error, as select_protocol checks already).
** When server mode is implemented properly, more care has to be taken to ** When server mode is implemented properly, more care has to be taken to
release all resources on error (for example to free assuan_cmd). release all resources on error (for example to free assuan_cmd).
** op_import_keys and op_export_keys have a limit ion the number of keys.
This is because we pass them in gpg via the command line and gpgsm
via an assuan control line. We should pipe them instead and maybe
change gpg/gpgsm to not put them in memory.
* GPG breakage: * GPG breakage:
** gpg 1.4.2 lacks error reporting if sign/encrypt with revoked key. ** gpg 1.4.2 lacks error reporting if sign/encrypt with revoked key.
** gpg 1.4.2 does crappy error reporting (namely none at all) when ** gpg 1.4.2 does crappy error reporting (namely none at all) when

View File

@ -1,3 +1,8 @@
2009-06-12 Werner Koch <wk@g10code.com>
* assuan-pipe-connect.c (_gpgme_io_spawn): Change prototype.
(pipe_connect_gpgme): Pass a flags arg.
2009-04-08 Marcus Brinkmann <marcus@g10code.de> 2009-04-08 Marcus Brinkmann <marcus@g10code.de>
* assuan.h (_gpgme_io_socket): New prototype. * assuan.h (_gpgme_io_socket): New prototype.

View File

@ -51,7 +51,7 @@ struct spawn_fd_item_s
int _gpgme_io_pipe (int filedes[2], int inherit_idx); int _gpgme_io_pipe (int filedes[2], int inherit_idx);
int _gpgme_io_spawn (const char *path, char *const argv[], int _gpgme_io_spawn (const char *path, char *const argv[], unsigned int flags,
struct spawn_fd_item_s *fd_list, pid_t *r_pid); struct spawn_fd_item_s *fd_list, pid_t *r_pid);
#endif #endif
@ -659,7 +659,7 @@ pipe_connect_gpgme (assuan_context_t *ctx,
child_fds[nr].dup_to = -1; child_fds[nr].dup_to = -1;
/* Start the process. */ /* Start the process. */
res = _gpgme_io_spawn (name, (char *const *) argv, child_fds, NULL); res = _gpgme_io_spawn (name, (char *const *) argv, 0, child_fds, NULL);
if (res == -1) if (res == -1)
{ {
_assuan_log_printf ("CreateProcess failed: %s\n", strerror (errno)); _assuan_log_printf ("CreateProcess failed: %s\n", strerror (errno));

View File

@ -1,3 +1,8 @@
2009-06-16 Werner Koch <wk@g10code.com>
* gpgme.texi (Exporting Keys): Document gpgme_op_export_keys.
(Importing Keys): Document gpgme_op_import_keys.
2009-05-28 Marcus Brinkmann <marcus@g10code.de> 2009-05-28 Marcus Brinkmann <marcus@g10code.de>
* gpgme.texi (Library Version Check): Document selftest error. * gpgme.texi (Library Version Check): Document selftest error.

View File

@ -3318,7 +3318,25 @@ operation is started on the context.
@cindex key, export @cindex key, export
@cindex key ring, export from @cindex key ring, export from
@deftypefun gpgme_error_t gpgme_op_export (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}}) Exporting keys means the same as running @command{gpg} with the command
@option{--export}. However, a mode flag can be used to change the way
the export works. The available mode flags are described below, they
may be or-ed together.
@table @code
@item GPGME_EXPORT_MODE_EXTERN
If this bit is set, the output is send directly to the default
keyserver. This is currently only allowed for OpenPGP keys. It is good
practise to not send more than a few dozens key to a keyserver at one
time. Using this flag requires that the @var{keydata} argument of the
export function is set to @code{NULL}.
@end table
@deftypefun gpgme_error_t gpgme_op_export (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export} extracts public keys and returns The function @code{gpgme_op_export} extracts public keys and returns
them in the data buffer @var{keydata}. The output format of the key them in the data buffer @var{keydata}. The output format of the key
data returned is determined by the @acronym{ASCII} armor attribute set data returned is determined by the @acronym{ASCII} armor attribute set
@ -3329,7 +3347,7 @@ If @var{pattern} is @code{NULL}, all available keys are returned.
Otherwise, @var{pattern} contains an engine specific expression that Otherwise, @var{pattern} contains an engine specific expression that
is used to limit the list to all keys matching the pattern. is used to limit the list to all keys matching the pattern.
@var{reserved} is reserved for future use and must be @code{0}. @var{mode} is usually 0; other values are described above.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the The function returns the error code @code{GPG_ERR_NO_ERROR} if the
operation completed successfully, @code{GPG_ERR_INV_VALUE} if operation completed successfully, @code{GPG_ERR_INV_VALUE} if
@ -3337,7 +3355,7 @@ operation completed successfully, @code{GPG_ERR_INV_VALUE} if
errors that are reported by the crypto engine support routines. errors that are reported by the crypto engine support routines.
@end deftypefun @end deftypefun
@deftypefun gpgme_error_t gpgme_op_export_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}}) @deftypefun gpgme_error_t gpgme_op_export_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export_start} initiates a The function @code{gpgme_op_export_start} initiates a
@code{gpgme_op_export} operation. It can be completed by calling @code{gpgme_op_export} operation. It can be completed by calling
@code{gpgme_wait} on the context. @xref{Waiting For Completion}. @code{gpgme_wait} on the context. @xref{Waiting For Completion}.
@ -3347,7 +3365,7 @@ operation could be started successfully, and @code{GPG_ERR_INV_VALUE}
if @var{keydata} is not a valid empty data buffer. if @var{keydata} is not a valid empty data buffer.
@end deftypefun @end deftypefun
@deftypefun gpgme_error_t gpgme_op_export_ext (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}}) @deftypefun gpgme_error_t gpgme_op_export_ext (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export} extracts public keys and returns The function @code{gpgme_op_export} extracts public keys and returns
them in the data buffer @var{keydata}. The output format of the key them in the data buffer @var{keydata}. The output format of the key
data returned is determined by the @acronym{ASCII} armor attribute set data returned is determined by the @acronym{ASCII} armor attribute set
@ -3359,7 +3377,7 @@ are returned. Otherwise, @var{pattern} is a @code{NULL} terminated
array of strings that are used to limit the list to all keys matching array of strings that are used to limit the list to all keys matching
at least one of the patterns verbatim. at least one of the patterns verbatim.
@var{reserved} is reserved for future use and must be @code{0}. @var{mode} is usually 0; other values are described above.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the The function returns the error code @code{GPG_ERR_NO_ERROR} if the
operation completed successfully, @code{GPG_ERR_INV_VALUE} if operation completed successfully, @code{GPG_ERR_INV_VALUE} if
@ -3367,7 +3385,7 @@ operation completed successfully, @code{GPG_ERR_INV_VALUE} if
errors that are reported by the crypto engine support routines. errors that are reported by the crypto engine support routines.
@end deftypefun @end deftypefun
@deftypefun gpgme_error_t gpgme_op_export_ext_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{unsigned int @var{reserved}}, @w{gpgme_data_t @var{keydata}}) @deftypefun gpgme_error_t gpgme_op_export_ext_start (@w{gpgme_ctx_t @var{ctx}}, @w{const char *@var{pattern}[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export_ext_start} initiates a The function @code{gpgme_op_export_ext_start} initiates a
@code{gpgme_op_export_ext} operation. It can be completed by calling @code{gpgme_op_export_ext} operation. It can be completed by calling
@code{gpgme_wait} on the context. @xref{Waiting For Completion}. @code{gpgme_wait} on the context. @xref{Waiting For Completion}.
@ -3378,11 +3396,50 @@ if @var{keydata} is not a valid empty data buffer.
@end deftypefun @end deftypefun
@deftypefun gpgme_error_t gpgme_op_export_keys (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t keys[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export_keys} extracts public keys and returns
them in the data buffer @var{keydata}. The output format of the key
data returned is determined by the @acronym{ASCII} armor attribute set
for the context @var{ctx}, or, if that is not set, by the encoding
specified for @var{keydata}.
The keys to export are taken form the @code{NULL} terminated array
@var{keys}. Only keys of the the currently selected protocol of
@var{ctx} which do have a fingerprint set are considered for export.
Other keys specified by the @var{keys} are ignored. In particular
OpenPGP keys retrieved via an external key listing are not included.
@var{mode} is usually 0; other values are described above.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the
operation completed successfully, @code{GPG_ERR_INV_VALUE} if
@var{keydata} is not a valid empty data buffer, @code{GPG_ERR_NO_DATA}
if no useful keys are in @var{keys} and passes through any errors that
are reported by the crypto engine support routines.
@end deftypefun
@deftypefun gpgme_error_t gpgme_op_export_keys_start (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t @var{keys}[]}, @w{gpgme_export_mode_t @var{mode}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_export_keys_start} initiates a
@code{gpgme_op_export_ext} operation. It can be completed by calling
@code{gpgme_wait} on the context. @xref{Waiting For Completion}.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the
operation could be started successfully, and @code{GPG_ERR_INV_VALUE}
if @var{keydata} is not a valid empty data buffer, @code{GPG_ERR_NO_DATA}
if no useful keys are in @var{keys} and passes through any errors that
are reported by the crypto engine support routines.
@end deftypefun
@node Importing Keys @node Importing Keys
@subsection Importing Keys @subsection Importing Keys
@cindex key, import @cindex key, import
@cindex key ring, import to @cindex key ring, import to
Importing keys means the same as running @command{gpg} with the command
@option{--import}.
@deftypefun gpgme_error_t gpgme_op_import (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{keydata}}) @deftypefun gpgme_error_t gpgme_op_import (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_data_t @var{keydata}})
The function @code{gpgme_op_import} adds the keys in the data buffer The function @code{gpgme_op_import} adds the keys in the data buffer
@var{keydata} to the key ring of the crypto engine used by @var{ctx}. @var{keydata} to the key ring of the crypto engine used by @var{ctx}.
@ -3409,6 +3466,44 @@ import could be started successfully, @code{GPG_ERR_INV_VALUE} if
and @code{GPG_ERR_NO_DATA} if @var{keydata} is an empty data buffer. and @code{GPG_ERR_NO_DATA} if @var{keydata} is an empty data buffer.
@end deftypefun @end deftypefun
@deftypefun gpgme_error_t gpgme_op_import_keys (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{keys}})
The function @code{gpgme_op_import_keys} adds the keys described by the
@code{NULL} terminated array @var{keys} to the key ring of the crypto
engine used by @var{ctx}. This function is the general interface to
move a key from one crypto engine to another as long as they are
compatible. In particular it is used to actually import and make keys
permanent which have been retrieved from an external source (i.e. using
@code{GPGME_KEYLIST_MODE_EXTERN}). @footnote{Thus it is a replacement
for the usual workaround of exporting and then importing a key to make
an X.509 key permanent.}
Only keys of the the currently selected protocol of @var{ctx} are
considered for import. Other keys specified by the @var{keys} are
ignored. As of now all considered keys must have been retrieved using
the same method, that is the used key listing mode must be identical.
After the operation completed successfully, the result can be
retrieved with @code{gpgme_op_import_result}.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the
import was completed successfully, @code{GPG_ERR_INV_VALUE} if
@var{keydata} if @var{ctx} or @var{keydata} is not a valid pointer,
@code{GPG_ERR_CONFLICT} if the key listing mode does not match, and
@code{GPG_ERR_NO_DATA} if no keys are considered for export.
@end deftypefun
@deftypefun gpgme_error_t gpgme_op_import_keys_start (@w{gpgme_ctx_t @var{ctx}}, @w{gpgme_key_t *@var{keys}})
The function @code{gpgme_op_import_keys_start} initiates a
@code{gpgme_op_import_keys} operation. It can be completed by calling
@code{gpgme_wait} on the context. @xref{Waiting For Completion}.
The function returns the error code @code{GPG_ERR_NO_ERROR} if the
import was completed successfully, @code{GPG_ERR_INV_VALUE} if
@var{keydata} if @var{ctx} or @var{keydata} is not a valid pointer,
@code{GPG_ERR_CONFLICT} if the key listing mode does not match, and
@code{GPG_ERR_NO_DATA} if no keys are considered for export.
@end deftypefun
@deftp {Data type} {gpgme_import_status_t} @deftp {Data type} {gpgme_import_status_t}
This is a pointer to a structure used to store a part of the result of This is a pointer to a structure used to store a part of the result of
a @code{gpgme_op_import} operation. For each considered key one a @code{gpgme_op_import} operation. For each considered key one

View File

@ -1,3 +1,34 @@
2009-06-16 Werner Koch <wk@g10code.com>
* gpgme.h.in (gpgme_op_export_keys_start, gpgme_op_export_keys): New.
* gpgme.def, libgpgme.vers: Add them.
* export.c (gpgme_op_export_keys_start, gpgme_op_export_keys): New.
(export_keys_start): New.
* gpgme.h.in (gpgme_export_mode_t, GPGME_EXPORT_MODE_EXTERN): New.
(gpgme_op_export_start, gpgme_op_export, gpgme_op_export_ext_start)
(gpgme_op_export_ext): Change arg RESERVED to MODE of new
compatible type.
* export.c (gpgme_export_ext_start, gpgme_op_export)
(gpgme_op_export_ext_start, gpgme_op_export_ext): Ditto.
(export_start): Ditto.
* engine.c (_gpgme_engine_op_export): Ditto.
* engine-backend.h (struct engine_ops): Ditto.
* engine-gpgsm.c (gpgsm_export, gpgsm_export_ext): Ditto.
* engine-gpg.c (gpg_export, gpg_export_ext): Ditto. Implement
mode EXTERN.
(gpg_export, gpg_export_ext): Factor common code out to ..
(export_common): .. this.
* gpgme.h.in (gpgme_op_import_keys_start, gpgme_op_import_keys): New.
* gpgme.def, libgpgme.vers: Add them.
* import.c (gpgme_op_import_keys_start, gpgme_op_import_keys): New.
(_gpgme_op_import_keys_start): New.
* engine.c (_gpgme_engine_op_import): Add arg KEYARRAY.
* engine-backend.h (struct engine_ops): Ditto.
* engine-gpgsm.c (gpgsm_import): Ditto. Not functional.
* engine-gpg.c (gpg_import): Ditto. Implement it.
2009-06-15 Marcus Brinkmann <marcus@g10code.de> 2009-06-15 Marcus Brinkmann <marcus@g10code.de>
* gpgme.h.in (gpgme_result_ref, gpgme_result_unref): Add * gpgme.h.in (gpgme_result_ref, gpgme_result_unref): Add

View File

@ -77,14 +77,15 @@ struct engine_ops
gpgme_data_t plain, gpgme_data_t ciph, gpgme_data_t plain, gpgme_data_t ciph,
int use_armor, gpgme_ctx_t ctx /* FIXME */); int use_armor, gpgme_ctx_t ctx /* FIXME */);
gpgme_error_t (*export) (void *engine, const char *pattern, gpgme_error_t (*export) (void *engine, const char *pattern,
unsigned int reserved, gpgme_data_t keydata, gpgme_export_mode_t mode, gpgme_data_t keydata,
int use_armor); int use_armor);
gpgme_error_t (*export_ext) (void *engine, const char *pattern[], gpgme_error_t (*export_ext) (void *engine, const char *pattern[],
unsigned int reserved, gpgme_data_t keydata, gpgme_export_mode_t mode, gpgme_data_t keydata,
int use_armor); int use_armor);
gpgme_error_t (*genkey) (void *engine, gpgme_data_t help_data, int use_armor, gpgme_error_t (*genkey) (void *engine, gpgme_data_t help_data, int use_armor,
gpgme_data_t pubkey, gpgme_data_t seckey); gpgme_data_t pubkey, gpgme_data_t seckey);
gpgme_error_t (*import) (void *engine, gpgme_data_t keydata); gpgme_error_t (*import) (void *engine, gpgme_data_t keydata,
gpgme_key_t *keyarray);
gpgme_error_t (*keylist) (void *engine, const char *pattern, gpgme_error_t (*keylist) (void *engine, const char *pattern,
int secret_only, gpgme_keylist_mode_t mode); int secret_only, gpgme_keylist_mode_t mode);
gpgme_error_t (*keylist_ext) (void *engine, const char *pattern[], gpgme_error_t (*keylist_ext) (void *engine, const char *pattern[],

View File

@ -678,7 +678,7 @@ command_handler (void *opaque, int fd)
/* The Fnc will be called to get a value for one of the commands with /* The Fnc will be called to get a value for one of the commands with
a key KEY. If the Code pssed to FNC is 0, the function may release a key KEY. If the Code passed to FNC is 0, the function may release
resources associated with the returned value from another call. To resources associated with the returned value from another call. To
match such a second call to a first call, the returned value from match such a second call to a first call, the returned value from
the first call is passed as keyword. */ the first call is passed as keyword. */
@ -1704,22 +1704,41 @@ gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
static gpgme_error_t static gpgme_error_t
gpg_export (void *engine, const char *pattern, unsigned int reserved, export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor)
{
gpgme_error_t err;
if ((mode & ~GPGME_EXPORT_MODE_EXTERN))
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if ((mode & GPGME_EXPORT_MODE_EXTERN))
{
err = add_arg (gpg, "--send-keys");
}
else
{
err = add_arg (gpg, "--export");
if (!err && use_armor)
err = add_arg (gpg, "--armor");
if (!err)
err = add_data (gpg, keydata, 1, 1);
}
if (!err)
err = add_arg (gpg, "--");
return err;
}
static gpgme_error_t
gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor) gpgme_data_t keydata, int use_armor)
{ {
engine_gpg_t gpg = engine; engine_gpg_t gpg = engine;
gpgme_error_t err; gpgme_error_t err;
if (reserved) err = export_common (gpg, mode, keydata, use_armor);
return gpg_error (GPG_ERR_INV_VALUE);
err = add_arg (gpg, "--export");
if (!err && use_armor)
err = add_arg (gpg, "--armor");
if (!err)
err = add_data (gpg, keydata, 1, 1);
if (!err)
err = add_arg (gpg, "--");
if (!err && pattern && *pattern) if (!err && pattern && *pattern)
err = add_arg (gpg, pattern); err = add_arg (gpg, pattern);
@ -1732,22 +1751,13 @@ gpg_export (void *engine, const char *pattern, unsigned int reserved,
static gpgme_error_t static gpgme_error_t
gpg_export_ext (void *engine, const char *pattern[], unsigned int reserved, gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor) gpgme_data_t keydata, int use_armor)
{ {
engine_gpg_t gpg = engine; engine_gpg_t gpg = engine;
gpgme_error_t err; gpgme_error_t err;
if (reserved) err = export_common (gpg, mode, keydata, use_armor);
return gpg_error (GPG_ERR_INV_VALUE);
err = add_arg (gpg, "--export");
if (!err && use_armor)
err = add_arg (gpg, "--armor");
if (!err)
err = add_data (gpg, keydata, 1, 1);
if (!err)
err = add_arg (gpg, "--");
if (pattern) if (pattern)
{ {
@ -1795,16 +1805,40 @@ gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
static gpgme_error_t static gpgme_error_t
gpg_import (void *engine, gpgme_data_t keydata) gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
{ {
engine_gpg_t gpg = engine; engine_gpg_t gpg = engine;
gpgme_error_t err; gpgme_error_t err;
int idx;
err = add_arg (gpg, "--import"); if (keydata && keyarray)
if (!err) gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
err = add_arg (gpg, "--");
if (!err) if (keyarray)
err = add_data (gpg, keydata, -1, 0); {
err = add_arg (gpg, "--recv-keys");
if (!err)
err = add_arg (gpg, "--");
for (idx=0; !err && keyarray[idx]; idx++)
{
if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
;
else if (!keyarray[idx]->subkeys)
;
else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
else if (*keyarray[idx]->subkeys->keyid)
err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
}
}
else
{
err = add_arg (gpg, "--import");
if (!err)
err = add_arg (gpg, "--");
if (!err)
err = add_data (gpg, keydata, -1, 0);
}
if (!err) if (!err)
err = start (gpg); err = start (gpg);

View File

@ -1379,15 +1379,18 @@ gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
static gpgme_error_t static gpgme_error_t
gpgsm_export (void *engine, const char *pattern, unsigned int reserved, gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor) gpgme_data_t keydata, int use_armor)
{ {
engine_gpgsm_t gpgsm = engine; engine_gpgsm_t gpgsm = engine;
gpgme_error_t err = 0; gpgme_error_t err = 0;
char *cmd; char *cmd;
if (!gpgsm || reserved) if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
if (mode)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (!pattern) if (!pattern)
pattern = ""; pattern = "";
@ -1414,7 +1417,7 @@ gpgsm_export (void *engine, const char *pattern, unsigned int reserved,
static gpgme_error_t static gpgme_error_t
gpgsm_export_ext (void *engine, const char *pattern[], unsigned int reserved, gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor) gpgme_data_t keydata, int use_armor)
{ {
engine_gpgsm_t gpgsm = engine; engine_gpgsm_t gpgsm = engine;
@ -1424,9 +1427,12 @@ gpgsm_export_ext (void *engine, const char *pattern[], unsigned int reserved,
int length = 7 + 1; int length = 7 + 1;
char *linep; char *linep;
if (!gpgsm || reserved) if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
if (mode)
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (pattern && *pattern) if (pattern && *pattern)
{ {
const char **pat = pattern; const char **pat = pattern;
@ -1534,7 +1540,7 @@ gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
static gpgme_error_t static gpgme_error_t
gpgsm_import (void *engine, gpgme_data_t keydata) gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
{ {
engine_gpgsm_t gpgsm = engine; engine_gpgsm_t gpgsm = engine;
gpgme_error_t err; gpgme_error_t err;
@ -1542,13 +1548,23 @@ gpgsm_import (void *engine, gpgme_data_t keydata)
if (!gpgsm) if (!gpgsm)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
gpgsm->input_cb.data = keydata; if (keydata && keyarray)
err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data)); gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed. */
if (err)
return err; if (keyarray)
gpgsm_clear_fd (gpgsm, OUTPUT_FD); {
gpgsm_clear_fd (gpgsm, MESSAGE_FD); return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
gpgsm->inline_data = NULL; }
else
{
gpgsm->input_cb.data = keydata;
err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
if (err)
return err;
gpgsm_clear_fd (gpgsm, OUTPUT_FD);
gpgsm_clear_fd (gpgsm, MESSAGE_FD);
gpgsm->inline_data = NULL;
}
err = start (gpgsm, "IMPORT"); err = start (gpgsm, "IMPORT");
return err; return err;

View File

@ -620,7 +620,7 @@ _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
gpgme_error_t gpgme_error_t
_gpgme_engine_op_export (engine_t engine, const char *pattern, _gpgme_engine_op_export (engine_t engine, const char *pattern,
unsigned int reserved, gpgme_data_t keydata, gpgme_export_mode_t mode, gpgme_data_t keydata,
int use_armor) int use_armor)
{ {
if (!engine) if (!engine)
@ -629,7 +629,7 @@ _gpgme_engine_op_export (engine_t engine, const char *pattern,
if (!engine->ops->export) if (!engine->ops->export)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED); return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return (*engine->ops->export) (engine->engine, pattern, reserved, return (*engine->ops->export) (engine->engine, pattern, mode,
keydata, use_armor); keydata, use_armor);
} }
@ -667,7 +667,8 @@ _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
gpgme_error_t gpgme_error_t
_gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata) _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
gpgme_key_t *keyarray)
{ {
if (!engine) if (!engine)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
@ -675,7 +676,7 @@ _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata)
if (!engine->ops->import) if (!engine->ops->import)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED); return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
return (*engine->ops->import) (engine->engine, keydata); return (*engine->ops->import) (engine->engine, keydata, keyarray);
} }

View File

@ -93,11 +93,11 @@ gpgme_error_t _gpgme_engine_op_encrypt_sign (engine_t engine,
int use_armor, int use_armor,
gpgme_ctx_t ctx /* FIXME */); gpgme_ctx_t ctx /* FIXME */);
gpgme_error_t _gpgme_engine_op_export (engine_t engine, const char *pattern, gpgme_error_t _gpgme_engine_op_export (engine_t engine, const char *pattern,
unsigned int reserved, gpgme_export_mode_t mode,
gpgme_data_t keydata, int use_armor); gpgme_data_t keydata, int use_armor);
gpgme_error_t _gpgme_engine_op_export_ext (engine_t engine, gpgme_error_t _gpgme_engine_op_export_ext (engine_t engine,
const char *pattern[], const char *pattern[],
unsigned int reserved, gpgme_export_mode_t mode,
gpgme_data_t keydata, gpgme_data_t keydata,
int use_armor); int use_armor);
gpgme_error_t _gpgme_engine_op_genkey (engine_t engine, gpgme_error_t _gpgme_engine_op_genkey (engine_t engine,
@ -105,7 +105,8 @@ gpgme_error_t _gpgme_engine_op_genkey (engine_t engine,
int use_armor, gpgme_data_t pubkey, int use_armor, gpgme_data_t pubkey,
gpgme_data_t seckey); gpgme_data_t seckey);
gpgme_error_t _gpgme_engine_op_import (engine_t engine, gpgme_error_t _gpgme_engine_op_import (engine_t engine,
gpgme_data_t keydata); gpgme_data_t keydata,
gpgme_key_t *keyarray);
gpgme_error_t _gpgme_engine_op_keylist (engine_t engine, gpgme_error_t _gpgme_engine_op_keylist (engine_t engine,
const char *pattern, const char *pattern,
int secret_only, int secret_only,

View File

@ -22,6 +22,8 @@
#if HAVE_CONFIG_H #if HAVE_CONFIG_H
#include <config.h> #include <config.h>
#endif #endif
#include <stdlib.h>
#include <string.h>
#include "gpgme.h" #include "gpgme.h"
#include "context.h" #include "context.h"
@ -37,12 +39,24 @@ export_status_handler (void *priv, gpgme_status_code_t code, char *args)
static gpgme_error_t static gpgme_error_t
export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern, export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern,
unsigned int reserved, gpgme_data_t keydata) gpgme_export_mode_t mode, gpgme_data_t keydata)
{ {
gpgme_error_t err; gpgme_error_t err;
if (!keydata) if ((mode & ~(GPGME_EXPORT_MODE_EXTERN)))
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */
if ((mode & GPGME_EXPORT_MODE_EXTERN))
{
if (keydata)
return gpg_error (GPG_ERR_INV_VALUE);
}
else
{
if (!keydata)
return gpg_error (GPG_ERR_INV_VALUE);
}
err = _gpgme_op_reset (ctx, synchronous); err = _gpgme_op_reset (ctx, synchronous);
if (err) if (err)
@ -50,26 +64,26 @@ export_start (gpgme_ctx_t ctx, int synchronous, const char *pattern,
_gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx); _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
return _gpgme_engine_op_export (ctx->engine, pattern, reserved, keydata, return _gpgme_engine_op_export (ctx->engine, pattern, mode, keydata,
ctx->use_armor); ctx->use_armor);
} }
/* Export the keys listed in RECP into KEYDATA. */ /* Export the keys listed in PATTERN into KEYDATA. */
gpgme_error_t gpgme_error_t
gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern,
unsigned int reserved, gpgme_data_t keydata) gpgme_export_mode_t mode, gpgme_data_t keydata)
{ {
return export_start (ctx, 0, pattern, reserved, keydata); return export_start (ctx, 0, pattern, mode, keydata);
} }
/* Export the keys listed in RECP into KEYDATA. */ /* Export the keys listed in PATTERN into KEYDATA. */
gpgme_error_t gpgme_error_t
gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, unsigned int reserved, gpgme_op_export (gpgme_ctx_t ctx, const char *pattern,
gpgme_data_t keydata) gpgme_export_mode_t mode, gpgme_data_t keydata)
{ {
gpgme_error_t err = export_start (ctx, 1, pattern, reserved, keydata); gpgme_error_t err = export_start (ctx, 1, pattern, mode, keydata);
if (!err) if (!err)
err = _gpgme_wait_one (ctx); err = _gpgme_wait_one (ctx);
return err; return err;
@ -78,12 +92,23 @@ gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, unsigned int reserved,
static gpgme_error_t static gpgme_error_t
export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[], export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
unsigned int reserved, gpgme_data_t keydata) gpgme_export_mode_t mode, gpgme_data_t keydata)
{ {
gpgme_error_t err; gpgme_error_t err;
if (!keydata) if ((mode & ~(GPGME_EXPORT_MODE_EXTERN)))
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE); /* Invalid flags in MODE. */
if ((mode & GPGME_EXPORT_MODE_EXTERN))
{
if (keydata)
return gpg_error (GPG_ERR_INV_VALUE);
}
else
{
if (!keydata)
return gpg_error (GPG_ERR_INV_VALUE);
}
err = _gpgme_op_reset (ctx, synchronous); err = _gpgme_op_reset (ctx, synchronous);
if (err) if (err)
@ -91,27 +116,108 @@ export_ext_start (gpgme_ctx_t ctx, int synchronous, const char *pattern[],
_gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx); _gpgme_engine_set_status_handler (ctx->engine, export_status_handler, ctx);
return _gpgme_engine_op_export_ext (ctx->engine, pattern, reserved, keydata, return _gpgme_engine_op_export_ext (ctx->engine, pattern, mode, keydata,
ctx->use_armor); ctx->use_armor);
} }
/* Export the keys listed in RECP into KEYDATA. */ /* Export the keys listed in PATTERN into KEYDATA. */
gpgme_error_t gpgme_error_t
gpgme_op_export_ext_start (gpgme_ctx_t ctx, const char *pattern[], gpgme_op_export_ext_start (gpgme_ctx_t ctx, const char *pattern[],
unsigned int reserved, gpgme_data_t keydata) gpgme_export_mode_t mode, gpgme_data_t keydata)
{ {
return export_ext_start (ctx, 0, pattern, reserved, keydata); return export_ext_start (ctx, 0, pattern, mode, keydata);
} }
/* Export the keys listed in RECP into KEYDATA. */ /* Export the keys listed in PATTERN into KEYDATA. */
gpgme_error_t gpgme_error_t
gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[], gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
unsigned int reserved, gpgme_data_t keydata) gpgme_export_mode_t mode, gpgme_data_t keydata)
{ {
gpgme_error_t err = export_ext_start (ctx, 1, pattern, reserved, keydata); gpgme_error_t err = export_ext_start (ctx, 1, pattern, mode, keydata);
if (!err) if (!err)
err = _gpgme_wait_one (ctx); err = _gpgme_wait_one (ctx);
return err; return err;
} }
static gpgme_error_t
export_keys_start (gpgme_ctx_t ctx, int synchronous, gpgme_key_t keys[],
gpgme_export_mode_t mode, gpgme_data_t keydata)
{
gpgme_error_t err;
int nkeys, idx;
char **pattern;
if (!keys)
return gpg_error (GPG_ERR_INV_VALUE);
/* Create a list of pattern from the keys. */
for (idx=nkeys=0; keys[idx]; idx++)
if (keys[idx]->protocol == ctx->protocol)
nkeys++;
if (!nkeys)
return gpg_error (GPG_ERR_NO_DATA);
pattern = calloc (nkeys+1, sizeof *pattern);
if (!pattern)
return gpg_error_from_syserror ();
for (idx=nkeys=0; keys[idx]; idx++)
if (keys[idx]->protocol == ctx->protocol
&& keys[idx]->subkeys
&& keys[idx]->subkeys->fpr
&& *keys[idx]->subkeys->fpr)
{
pattern[nkeys] = strdup (keys[idx]->subkeys->fpr);
if (!pattern[nkeys])
{
err = gpg_error_from_syserror ();
goto leave;
}
nkeys++;
}
/* Pass on to the regular function. */
err = export_ext_start (ctx, synchronous, (const char**)pattern,
mode, keydata);
leave:
for (idx=0; pattern[idx]; idx++)
free (pattern[idx]);
free (pattern);
return err;
}
/* Export the keys from the array KEYS into KEYDATA. Only keys of the
current protocol are exported and only those which have a
fingerprint set; that is keys received with some external search
methods are silently skipped. */
gpgme_error_t
gpgme_op_export_keys_start (gpgme_ctx_t ctx,
gpgme_key_t keys[],
gpgme_export_mode_t mode,
gpgme_data_t keydata)
{
return export_keys_start (ctx, 0, keys, mode, keydata);
}
gpgme_error_t
gpgme_op_export_keys (gpgme_ctx_t ctx,
gpgme_key_t keys[],
gpgme_export_mode_t mode,
gpgme_data_t keydata)
{
gpgme_error_t err = export_keys_start (ctx, 1, keys, mode, keydata);
if (!err)
err = _gpgme_wait_one (ctx);
return err;
}

View File

@ -180,5 +180,10 @@ EXPORTS
gpgme_release_ref @138 gpgme_release_ref @138
gpgme_release_unref @139 gpgme_release_unref @139
gpgme_op_import_keys @140
gpgme_op_import_keys_start @141
gpgme_op_export_keys @142
gpgme_op_export_keys_start @143
; END ; END

View File

@ -328,6 +328,12 @@ gpgme_protocol_t;
typedef unsigned int gpgme_keylist_mode_t; typedef unsigned int gpgme_keylist_mode_t;
/* The available export mode flags. */
#define GPGME_EXPORT_MODE_EXTERN 2
typedef unsigned int gpgme_export_mode_t;
/* Flags for the audit log functions. */ /* Flags for the audit log functions. */
#define GPGME_AUDITLOG_HTML 1 #define GPGME_AUDITLOG_HTML 1
@ -1497,22 +1503,39 @@ gpgme_error_t gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata);
gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, gpgme_error_t gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata,
int *nr) _GPGME_DEPRECATED; int *nr) _GPGME_DEPRECATED;
/* Import the keys from the array KEYS into the keyring. */
gpgme_error_t gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t keys[]);
gpgme_error_t gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t keys[]);
/* Export the keys found by PATTERN into KEYDATA. */ /* Export the keys found by PATTERN into KEYDATA. */
gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern, gpgme_error_t gpgme_op_export_start (gpgme_ctx_t ctx, const char *pattern,
unsigned int reserved, gpgme_export_mode_t mode,
gpgme_data_t keydata); gpgme_data_t keydata);
gpgme_error_t gpgme_op_export (gpgme_ctx_t ctx, const char *pattern, gpgme_error_t gpgme_op_export (gpgme_ctx_t ctx, const char *pattern,
unsigned int reserved, gpgme_data_t keydata); gpgme_export_mode_t mode,
gpgme_data_t keydata);
gpgme_error_t gpgme_op_export_ext_start (gpgme_ctx_t ctx, gpgme_error_t gpgme_op_export_ext_start (gpgme_ctx_t ctx,
const char *pattern[], const char *pattern[],
unsigned int reserved, gpgme_export_mode_t mode,
gpgme_data_t keydata); gpgme_data_t keydata);
gpgme_error_t gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[], gpgme_error_t gpgme_op_export_ext (gpgme_ctx_t ctx, const char *pattern[],
unsigned int reserved, gpgme_export_mode_t mode,
gpgme_data_t keydata); gpgme_data_t keydata);
/* Export the keys from the array KEYS into KEYDATA. */
gpgme_error_t gpgme_op_export_keys_start (gpgme_ctx_t ctx,
gpgme_key_t keys[],
gpgme_export_mode_t mode,
gpgme_data_t keydata);
gpgme_error_t gpgme_op_export_keys (gpgme_ctx_t ctx,
gpgme_key_t keys[],
gpgme_export_mode_t mode,
gpgme_data_t keydata);
/* Key generation. */ /* Key generation. */
struct _gpgme_op_genkey_result struct _gpgme_op_genkey_result

View File

@ -238,7 +238,7 @@ _gpgme_op_import_start (gpgme_ctx_t ctx, int synchronous, gpgme_data_t keydata)
_gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx); _gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
return _gpgme_engine_op_import (ctx->engine, keydata); return _gpgme_engine_op_import (ctx->engine, keydata, NULL);
} }
@ -260,6 +260,84 @@ gpgme_op_import (gpgme_ctx_t ctx, gpgme_data_t keydata)
} }
static gpgme_error_t
_gpgme_op_import_keys_start (gpgme_ctx_t ctx, int synchronous,
gpgme_key_t *keys)
{
gpgme_error_t err;
void *hook;
op_data_t opd;
int idx, firstidx, nkeys;
err = _gpgme_op_reset (ctx, synchronous);
if (err)
return err;
err = _gpgme_op_data_lookup (ctx, OPDATA_IMPORT, &hook,
sizeof (*opd), release_op_data);
opd = hook;
if (err)
return err;
opd->lastp = &opd->result.imports;
if (!keys)
return gpg_error (GPG_ERR_NO_DATA);
for (idx=nkeys=0, firstidx=-1; keys[idx]; idx++)
{
/* We only consider keys of the current protocol. */
if (keys[idx]->protocol != ctx->protocol)
continue;
if (firstidx == -1)
firstidx = idx;
/* If a key has been found using a different key listing mode,
we bail out. This makes the processing easier. Fixme: To
allow a mix of keys we would need to sort them by key listing
mode and start two import operations one after the other. */
if (keys[idx]->keylist_mode != keys[firstidx]->keylist_mode)
return gpg_error (GPG_ERR_CONFLICT);
nkeys++;
}
if (!nkeys)
return gpg_error (GPG_ERR_NO_DATA);
_gpgme_engine_set_status_handler (ctx->engine, import_status_handler, ctx);
return _gpgme_engine_op_import (ctx->engine, NULL, keys);
}
/* Asynchronous version of gpgme_op_import_key. */
gpgme_error_t
gpgme_op_import_keys_start (gpgme_ctx_t ctx, gpgme_key_t *keys)
{
return _gpgme_op_import_keys_start (ctx, 0, keys);
}
/* Import the keys from the array KEYS into the keyring. This
function allows to move a key from one engine to another as long as
they are compatible. In particular it is used to actually import
keys retrieved from an external source (i.e. using
GPGME_KEYLIST_MODE_EXTERN). It replaces the old workaround of
exporting and then importing a key as used to make an X.509 key
permanent. This function automagically does the right thing.
KEYS is a NULL terminated array of gpgme key objects. The result
is the usual import result structure. Only keys matching the
current protocol are imported; other keys are ignored. */
gpgme_error_t
gpgme_op_import_keys (gpgme_ctx_t ctx, gpgme_key_t *keys)
{
gpgme_error_t err = _gpgme_op_import_keys_start (ctx, 1, keys);
if (!err)
err = _gpgme_wait_one (ctx);
return err;
}
/* Deprecated interface. */
gpgme_error_t gpgme_error_t
gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr) gpgme_op_import_ext (gpgme_ctx_t ctx, gpgme_data_t keydata, int *nr)
{ {

View File

@ -59,6 +59,11 @@ GPGME_1.1 {
gpgme_result_ref; gpgme_result_ref;
gpgme_result_unref; gpgme_result_unref;
gpgme_op_import_keys;
gpgme_op_import_keys_start;
gpgme_op_export_keys;
gpgme_op_export_keys_start;
}; };

View File

@ -1,3 +1,7 @@
2009-06-16 Werner Koch <wk@g10code.com>
* gpg/pgp-export.c, gpg/pgp-keylist.c: New.
2009-06-09 Werner Koch <wk@g10code.com> 2009-06-09 Werner Koch <wk@g10code.com>
* gpg/Makefile.am (./pubring.gpg): Ignore errors in case of * gpg/Makefile.am (./pubring.gpg): Ignore errors in case of
@ -16,7 +20,8 @@
* gpg/mkdemodirs: Renamed to ... * gpg/mkdemodirs: Renamed to ...
* gpg/mkdemodirs.in: ... here. * gpg/mkdemodirs.in: ... here.
* gpg/mkdemodirs.in (GPG): Derive value from @GPG@ instead of hard-coding "gpg". * gpg/mkdemodirs.in (GPG): Derive value from @GPG@ instead of
hard-coding "gpg".
2009-02-24 Werner Koch <wk@g10code.com> 2009-02-24 Werner Koch <wk@g10code.com>

View File

@ -50,7 +50,8 @@ LDADD = ../../src/libgpgme.la
t_thread1_LDADD = ../../src/libgpgme-pthread.la t_thread1_LDADD = ../../src/libgpgme-pthread.la
# We don't run t-genkey in the test suite, because it takes too long # We don't run t-genkey in the test suite, because it takes too long
noinst_PROGRAMS = $(TESTS) t-genkey # The other programs are used for debugging.
noinst_PROGRAMS = $(TESTS) t-genkey pgp-keylist pgp-export
mkdemodirs: mkdemodirs.in Makefile mkdemodirs: mkdemodirs.in Makefile
sed -e 's,[@]GPG[@],$(GPG),g' < $(srcdir)/mkdemodirs.in > mkdemodirs sed -e 's,[@]GPG[@],$(GPG),g' < $(srcdir)/mkdemodirs.in > mkdemodirs

168
tests/gpg/pgp-export.c Normal file
View File

@ -0,0 +1,168 @@
/* pgp-export.c - Helper to run an export command
Copyright (C) 2008, 2009 g10 Code GmbH
This file is part of GPGME.
GPGME is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
GPGME is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* We need to include config.h so that we know whether we are building
with large file system (LFS) support. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gpgme.h>
#define PGM "pgp-export"
#include "t-support.h"
static int verbose;
static const char *
nonnull (const char *s)
{
return s? s :"[none]";
}
static int
show_usage (int ex)
{
fputs ("usage: " PGM " [options] USERIDS\n\n"
"Options:\n"
" --verbose run in verbose mode\n"
" --extern send keys to the keyserver (TAKE CARE!)\n"
, stderr);
exit (ex);
}
int
main (int argc, char **argv)
{
int last_argc = -1;
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_key_t key;
gpgme_keylist_result_t result;
gpgme_key_t keyarray[100];
int keyidx = 0;
gpgme_data_t out;
gpgme_export_mode_t mode = 0;
if (argc)
{ argc--; argv++; }
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--"))
{
argc--; argv++;
break;
}
else if (!strcmp (*argv, "--help"))
show_usage (0);
else if (!strcmp (*argv, "--verbose"))
{
verbose = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--extern"))
{
mode |= GPGME_KEYLIST_MODE_EXTERN;
argc--; argv++;
}
else if (!strncmp (*argv, "--", 2))
show_usage (1);
}
if (!argc)
show_usage (1);
init_gpgme (GPGME_PROTOCOL_OpenPGP);
err = gpgme_new (&ctx);
fail_if_err (err);
gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
/* Lookup the keys. */
err = gpgme_op_keylist_ext_start (ctx, (const char**)argv, 0, 0);
fail_if_err (err);
while (!(err = gpgme_op_keylist_next (ctx, &key)))
{
printf ("keyid: %s (fpr: %s)\n",
key->subkeys?nonnull (key->subkeys->keyid):"?",
key->subkeys?nonnull (key->subkeys->fpr):"?");
if (keyidx < DIM (keyarray)-1)
keyarray[keyidx++] = key;
else
{
fprintf (stderr, PGM": too many keys"
"- skipping this key\n");
gpgme_key_unref (key);
}
}
if (gpg_err_code (err) != GPG_ERR_EOF)
fail_if_err (err);
err = gpgme_op_keylist_end (ctx);
fail_if_err (err);
keyarray[keyidx] = NULL;
result = gpgme_op_keylist_result (ctx);
if (result->truncated)
{
fprintf (stderr, PGM ": key listing unexpectedly truncated\n");
exit (1);
}
/* Now for the actual export. */
if ((mode & GPGME_KEYLIST_MODE_EXTERN))
printf ("sending keys to keyserver\n");
err = gpgme_data_new (&out);
fail_if_err (err);
gpgme_set_armor (ctx, 1);
err = gpgme_op_export_keys (ctx, keyarray, mode,
(mode & GPGME_KEYLIST_MODE_EXTERN)? NULL:out);
fail_if_err (err);
fflush (NULL);
if (!(mode & GPGME_KEYLIST_MODE_EXTERN))
{
fputs ("Begin Result:\n", stdout);
print_data (out);
fputs ("End Result.\n", stdout);
}
/* Cleanup. */
gpgme_data_release (out);
for (keyidx=0; keyarray[keyidx]; keyidx++)
gpgme_key_unref (keyarray[keyidx]);
gpgme_release (ctx);
return 0;
}

284
tests/gpg/pgp-keylist.c Normal file
View File

@ -0,0 +1,284 @@
/* pgp-keylist.c - Helper to show a key listing.
Copyright (C) 2008, 2009 g10 Code GmbH
This file is part of GPGME.
GPGME is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
GPGME is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
/* We need to include config.h so that we know whether we are building
with large file system (LFS) support. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gpgme.h>
#define PGM "pgp-keylist"
#include "t-support.h"
static int verbose;
static const char *
nonnull (const char *s)
{
return s? s :"[none]";
}
static void
print_import_result (gpgme_import_result_t r)
{
gpgme_import_status_t st;
printf ("key import results:\n"
" considered: %d\n"
" no user id: %d\n"
" imported: %d\n"
" imported_rsa: %d\n"
" unchanged: %d\n"
" new user ids: %d\n"
" new subkeys: %d\n"
" new signatures: %d\n"
" new revocations: %d\n"
" secret read: %d\n"
" secret imported: %d\n"
" secret unchanged: %d\n"
" skipped new keys: %d\n"
" not imported: %d\n",
r->considered,
r->no_user_id,
r->imported,
r->imported_rsa,
r->unchanged,
r->new_user_ids,
r->new_sub_keys,
r->new_signatures,
r->new_revocations,
r->secret_read,
r->secret_imported,
r->secret_unchanged,
r->skipped_new_keys,
r->not_imported);
for (st=r->imports; st; st = st->next)
{
printf (" fpr: %s err: %d (%s) status:", nonnull (st->fpr),
st->result, gpg_strerror (st->result));
if (st->status & GPGME_IMPORT_NEW)
fputs (" new", stdout);
if (st->status & GPGME_IMPORT_UID)
fputs (" uid", stdout);
if (st->status & GPGME_IMPORT_SIG)
fputs (" sig", stdout);
if (st->status & GPGME_IMPORT_SUBKEY)
fputs (" subkey", stdout);
if (st->status & GPGME_IMPORT_SECRET)
fputs (" secret", stdout);
putchar ('\n');
}
}
static int
show_usage (int ex)
{
fputs ("usage: " PGM " [options] [USERID]\n\n"
"Options:\n"
" --verbose run in verbose mode\n"
" --local use GPGME_KEYLIST_MODE_LOCAL\n"
" --extern use GPGME_KEYLIST_MODE_EXTERN\n"
" --sigs use GPGME_KEYLIST_MODE_SIGS\n"
" --sig-notations use GPGME_KEYLIST_MODE_SIG_NOTATIONS\n"
" --ephemeral use GPGME_KEYLIST_MODE_EPHEMERAL\n"
" --validate use GPGME_KEYLIST_MODE_VALIDATE\n"
" --import import all keys\n"
, stderr);
exit (ex);
}
int
main (int argc, char **argv)
{
int last_argc = -1;
gpgme_error_t err;
gpgme_ctx_t ctx;
gpgme_keylist_mode_t mode = 0;
gpgme_key_t key;
gpgme_keylist_result_t result;
int import = 0;
gpgme_key_t keyarray[100];
int keyidx = 0;
if (argc)
{ argc--; argv++; }
while (argc && last_argc != argc )
{
last_argc = argc;
if (!strcmp (*argv, "--"))
{
argc--; argv++;
break;
}
else if (!strcmp (*argv, "--help"))
show_usage (0);
else if (!strcmp (*argv, "--verbose"))
{
verbose = 1;
argc--; argv++;
}
else if (!strcmp (*argv, "--local"))
{
mode |= GPGME_KEYLIST_MODE_LOCAL;
argc--; argv++;
}
else if (!strcmp (*argv, "--extern"))
{
mode |= GPGME_KEYLIST_MODE_EXTERN;
argc--; argv++;
}
else if (!strcmp (*argv, "--sigs"))
{
mode |= GPGME_KEYLIST_MODE_SIGS;
argc--; argv++;
}
else if (!strcmp (*argv, "--sig-notations"))
{
mode |= GPGME_KEYLIST_MODE_SIG_NOTATIONS;
argc--; argv++;
}
else if (!strcmp (*argv, "--ephemeral"))
{
mode |= GPGME_KEYLIST_MODE_EPHEMERAL;
argc--; argv++;
}
else if (!strcmp (*argv, "--validate"))
{
mode |= GPGME_KEYLIST_MODE_VALIDATE;
argc--; argv++;
}
else if (!strcmp (*argv, "--import"))
{
import = 1;
argc--; argv++;
}
else if (!strncmp (*argv, "--", 2))
show_usage (1);
}
if (argc > 1)
show_usage (1);
init_gpgme (GPGME_PROTOCOL_OpenPGP);
err = gpgme_new (&ctx);
fail_if_err (err);
gpgme_set_protocol (ctx, GPGME_PROTOCOL_OpenPGP);
gpgme_set_keylist_mode (ctx, mode);
err = gpgme_op_keylist_start (ctx, argc? argv[0]:NULL, 0);
fail_if_err (err);
while (!(err = gpgme_op_keylist_next (ctx, &key)))
{
gpgme_user_id_t uid;
int nuids;
printf ("keyid : %s\n", key->subkeys?nonnull (key->subkeys->keyid):"?");
printf ("fpr : %s\n", key->subkeys?nonnull (key->subkeys->fpr):"?");
printf ("caps : %s%s%s%s\n",
key->can_encrypt? "e":"",
key->can_sign? "s":"",
key->can_certify? "c":"",
key->can_authenticate? "a":"");
printf ("flags :%s%s%s%s%s%s\n",
key->secret? " secret":"",
key->revoked? " revoked":"",
key->expired? " expired":"",
key->disabled? " disabled":"",
key->invalid? " invalid":"",
key->is_qualified? " qualifid":"");
for (nuids=0, uid=key->uids; uid; uid = uid->next, nuids++)
{
printf ("userid %d: %s\n", nuids, nonnull(uid->uid));
printf ("valid %d: %s\n", nuids,
uid->validity == GPGME_VALIDITY_UNKNOWN? "unknown":
uid->validity == GPGME_VALIDITY_UNDEFINED? "undefined":
uid->validity == GPGME_VALIDITY_NEVER? "never":
uid->validity == GPGME_VALIDITY_MARGINAL? "marginal":
uid->validity == GPGME_VALIDITY_FULL? "full":
uid->validity == GPGME_VALIDITY_ULTIMATE? "ultimate": "[?]");
}
putchar ('\n');
if (import)
{
if (keyidx < DIM (keyarray)-1)
keyarray[keyidx++] = key;
else
{
fprintf (stderr, PGM": too many keys in import mode"
"- skipping this key\n");
gpgme_key_unref (key);
}
}
else
gpgme_key_unref (key);
}
if (gpg_err_code (err) != GPG_ERR_EOF)
fail_if_err (err);
err = gpgme_op_keylist_end (ctx);
fail_if_err (err);
keyarray[keyidx] = NULL;
result = gpgme_op_keylist_result (ctx);
if (result->truncated)
{
fprintf (stderr, PGM ": key listing unexpectedly truncated\n");
exit (1);
}
if (import)
{
gpgme_import_result_t impres;
err = gpgme_op_import_keys (ctx, keyarray);
fail_if_err (err);
impres = gpgme_op_import_result (ctx);
if (!impres)
{
fprintf (stderr, PGM ": no import result returned\n");
exit (1);
}
print_import_result (impres);
}
for (keyidx=0; keyarray[keyidx]; keyidx++)
gpgme_key_unref (keyarray[keyidx]);
gpgme_release (ctx);
return 0;
}

View File

@ -42,6 +42,7 @@ main (int argc, char **argv)
gpgme_error_t err; gpgme_error_t err;
gpgme_data_t out; gpgme_data_t out;
const char *pattern[] = { "Alpha", "Bob", NULL }; const char *pattern[] = { "Alpha", "Bob", NULL };
gpgme_key_t keyarray[3];
init_gpgme (GPGME_PROTOCOL_OpenPGP); init_gpgme (GPGME_PROTOCOL_OpenPGP);
@ -61,6 +62,32 @@ main (int argc, char **argv)
fputs ("End Result.\n", stdout); fputs ("End Result.\n", stdout);
gpgme_data_release (out); gpgme_data_release (out);
/* Again. Now using a key array. */
err = gpgme_data_new (&out);
fail_if_err (err);
err = gpgme_get_key (ctx, "0x68697734" /* Alpha */, keyarray+0, 0);
fail_if_err (err);
err = gpgme_get_key (ctx, "0xA9E3B0B2" /* Bob */, keyarray+1, 0);
fail_if_err (err);
keyarray[2] = NULL;
gpgme_set_armor (ctx, 1);
err = gpgme_op_export_keys (ctx, keyarray, 0, out);
fail_if_err (err);
gpgme_key_unref (keyarray[0]);
gpgme_key_unref (keyarray[1]);
fflush (NULL);
fputs ("Begin Result:\n", stdout);
print_data (out);
fputs ("End Result.\n", stdout);
gpgme_data_release (out);
gpgme_release (ctx); gpgme_release (ctx);
return 0; return 0;