GPGME_No_Passphrase have been renamed to GPGME_No_UserID,
GPGME_Invalid_UserID and GPGME_Bad_Passphrase resp.
+ * The FPR argument to gpgme_op_genkey was removed. Instead, use the
+ gpgme_op_genkey_result function to retrieve a GpgmeGenKeyResult
+ pointer to a structure which contains the fingerprint. This also
+ works with gpgme_op_genkey. The structure also provides other
+ information about the generated keys.
+
* Interface changes relative to the 0.4.0 release:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GpgmeIOCb CHANGED: Return type from void to GpgmeError.
gpgme_get_protocol_name NEW
GpgmePassphraseCb CHANGED: Return error value, new argument.
gpgme_cancel REMOVED: Return error in callback directly.
-GPGME_No_Recipients CHANGED: GPGME_No_UserID
-GPGME_Invalid_Recipient CHANGED: GPGME_Invalid_UserID
-GPGME_No_Passphrase CHANGED: GPGME_Bad_Passphrase
+GPGME_No_Recipients CHANGED: Now GPGME_No_UserID.
+GPGME_Invalid_Recipient CHANGED: Now GPGME_Invalid_UserID.
+GPGME_No_Passphrase CHANGED: Now GPGME_Bad_Passphrase.
+gpgme_op_genkey CHANGED: FPR argument dropped.
+gpgme_op_genkey_result NEW
+GpgmeGenKeyResult NEW
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Noteworthy changes in version 0.4.0 (2002-12-23)
2003-04-24 Marcus Brinkmann <marcus@g10code.de>
+ * gpgme.texi (Generating Keys): Document changed gpgme_op_genkey
+ and new gpgme_op_genkey_result function. Document
+ GpgmeGenKeyResult data type.
+
* gpgme.texi (Error Values): Rename GPGME_No_Passphrase to
GPGME_Bad_Passphrase.
* gpgme.texi (Decrypt): Likewise.
@cindex key, creation
@cindex key ring, add
-@deftypefun GpgmeError gpgme_op_genkey (@w{GpgmeCtx @var{ctx}}, @w{const char *@var{parms}}, @w{GpgmeData @var{pubkey}}, @w{GpgmeData @var{seckey}}, @w{char **@var{fpr}})
+@deftypefun GpgmeError gpgme_op_genkey (@w{GpgmeCtx @var{ctx}}, @w{const char *@var{parms}}, @w{GpgmeData @var{pubkey}}, @w{GpgmeData @var{seckey}})
The function @code{gpgme_op_genkey} generates a new key pair in the
context @var{ctx} and puts it into the standard key ring if both
@var{pubkey} and @var{seckey} are @code{NULL}. In this case the
Note that not all crypto engines support this interface equally.
GnuPG does not support @var{pubkey} and @var{subkey}, they should be
both @code{NULL}, and the key pair will be added to the standard key
-ring. GpgSM does only support @var{pubkey}, the secret key will be
-stored by @command{gpg-agent}. GpgSM expects @var{pubkey} being not
+ring. GpgSM only supports @var{pubkey}, the secret key will be stored
+by @command{gpg-agent}. GpgSM expects @var{pubkey} being not
@code{NULL}.
The argument @var{parms} specifies parameters for the key in an XML
container is passed verbatim to GnuPG. Control statements are not
allowed.
-If @var{fpr} is not a null pointer, the function succeeds, and the
-crypto engine supports it, *@var{fpr} will contain a string with the
-fingerprint of the key, allocated with @code{malloc}. If both a
-primary and a sub key was generated, the fingerprint of the primary
-key will be returned. If the crypto engine does not provide the
-fingerprint, *@var{fpr} will be a null pointer.
+After the operation completed successfully, the result can be
+retrieved with @code{gpgme_op_genkey_result}.
The function returns @code{GPGME_No_Error} if the operation could be
started successfully, @code{GPGME_Invalid_Value} if @var{parms} is not
@var{seckey} is not @code{NULL}.
@end deftypefun
+@deftp {Data type} {GpgmeGenKeyResult}
+This is a pointer to a structure used to store the result of a
+@code{gpgme_op_genkey} operation. After successfully generating a
+key, you can retrieve the pointer to the result with
+@code{gpgme_op_genkey_result}. The structure contains the following
+members:
+
+@table @code
+@item unsigned int primary : 1
+This is a flag that is set to 1 if a primary key was created and to 0
+if not.
+
+@item unsigned int sub : 1
+This is a flag that is set to 1 if a subkey was created and to 0
+if not.
+
+@item char *fpr
+This is the fingerprint of the key that was created. If both a
+primary and a sub key were generated, the fingerprint of the primary
+key will be returned. If the crypto engine does not provide the
+fingerprint, @code{fpr} will be a null pointer.
+@end table
+@end deftp
+
+@deftypefun GpgmeGenKeyResult gpgme_op_genkey_result (@w{GpgmeCtx @var{ctx}})
+The function @code{gpgme_op_genkey_result} returns a
+@code{GpgmeGenKeyResult} pointer to a structure holding the result of
+a @code{gpgme_op_genkey} operation. The pointer is only valid if the
+last operation on the context was a @code{gpgme_op_genkey} or
+@code{gpgme_op_genkey_start} operation, and if this operation finished
+successfully. The returned pointer is only valid until the next
+operation is started on the context.
+@end deftypefun
@node Exporting Keys
@subsection Exporting Keys
2003-04-24 Marcus Brinkmann <marcus@g10code.de>
+ * gpgme.h (struct _gpgme_op_genkey_result): New structure.
+ (GpgmeGenKeyResult): New type.
+ (gpgme_op_genkey): Drop last argument.
+ (gpgme_op_genkey_result): New function.
+ * genkey.c: Do not include "util.h", but "gpgme.h".
+ (struct genkey_result): Replace with ...
+ (op_data_t): ... this new type.
+ (release_genkey_result): Replace with ...
+ (release_op_data): ... this new function.
+ (gpgme_op_genkey_result): New function.
+ (genkey_status_handler): Rewritten using new op_data_t type.
+ (get_key_parameter): New function.
+ (_gpgme_op_genkey_start): Renamed to
+ (genkey_start): ... this and rewritten.
+ (gpgme_op_genkey_start): Use genkey_start instead
+ _gpgme_op_genkey_start.
+ (gpgme_op_genkey): Rewritten. Remove FPR argument.
+
* context.h (struct gpgme_context_s): Remove member verbosity.
* gpgme.c (gpgme_new): Do not set member verbosity.
* engine.h (_gpgme_engine_set_verbosity): Remove prototype.
#include <stdlib.h>
#include <string.h>
-#include "util.h"
+#include "gpgme.h"
#include "context.h"
#include "ops.h"
-
-struct genkey_result
+\f
+typedef struct
{
- int created_primary : 1;
- int created_sub : 1;
- char *fpr;
-};
-typedef struct genkey_result *GenKeyResult;
+ struct _gpgme_op_genkey_result result;
+
+ /* The key parameters passed to the crypto engine. */
+ GpgmeData key_parameter;
+} *op_data_t;
+
static void
-release_genkey_result (void *hook)
+release_op_data (void *hook)
{
- GenKeyResult result = (GenKeyResult) hook;
+ op_data_t opd = (op_data_t) hook;
- if (result->fpr)
- free (result->fpr);
+ if (opd->result.fpr)
+ free (opd->result.fpr);
+ if (opd->key_parameter)
+ gpgme_data_release (opd->key_parameter);
}
+GpgmeGenKeyResult
+gpgme_op_genkey_result (GpgmeCtx ctx)
+{
+ op_data_t opd;
+ GpgmeError err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &opd, -1, NULL);
+ if (err || !opd)
+ return NULL;
+
+ return &opd->result;
+}
+
+\f
static GpgmeError
-genkey_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
+genkey_status_handler (void *priv, GpgmeStatusCode code, char *args)
{
- GenKeyResult result;
- GpgmeError err = _gpgme_progress_status_handler (ctx, code, args);
+ GpgmeCtx ctx = (GpgmeCtx) priv;
+ GpgmeError err;
+ op_data_t opd;
+
+ /* Pipe the status code through the progress status handler. */
+ err = _gpgme_progress_status_handler (ctx, code, args);
if (err)
return err;
- err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &result,
- sizeof (*result), release_genkey_result);
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &opd,
+ -1, NULL);
if (err)
return err;
if (args && *args)
{
if (*args == 'B' || *args == 'P')
- result->created_primary = 1;
+ opd->result.primary = 1;
if (*args == 'B' || *args == 'S')
- result->created_sub = 1;
+ opd->result.sub = 1;
if (args[1] == ' ')
{
- if (result->fpr)
- free (result->fpr);
- result->fpr = strdup (&args[2]);
- if (!result->fpr)
+ if (opd->result.fpr)
+ free (opd->result.fpr);
+ opd->result.fpr = strdup (&args[2]);
+ if (!opd->result.fpr)
return GPGME_Out_Of_Core;
}
}
case GPGME_STATUS_EOF:
/* FIXME: Should return some more useful error value. */
- if (!result->created_primary
- && !result->created_sub)
+ if (!opd->result.primary && !opd->result.sub)
return GPGME_General_Error;
break;
static GpgmeError
-_gpgme_op_genkey_start (GpgmeCtx ctx, int synchronous, const char *parms,
- GpgmeData pubkey, GpgmeData seckey)
+get_key_parameter (const char *parms, GpgmeData *key_parameter)
{
- int err = 0;
- const char *s, *s2, *sx;
+ const char *content;
+ const char *attrib;
+ const char *endtag;
+
+ /* Extract the key parameter from the XML structure. */
+ parms = strstr (parms, "<GnupgKeyParms ");
+ if (!parms)
+ return GPGME_Invalid_Value;
+
+ content = strchr (parms, '>');
+ if (!content)
+ return GPGME_Invalid_Value;
+ content++;
+
+ attrib = strstr (parms, "format=\"internal\"");
+ if (!attrib || attrib >= content)
+ return GPGME_Invalid_Value;
+
+ endtag = strstr (content, "</GnupgKeyParms>");
+ /* FIXME: Check that there are no control statements inside. */
+ while (*content == '\n')
+ content++;
+
+ return gpgme_data_new_from_mem (key_parameter, content,
+ endtag - content, 0);
+}
+
+static GpgmeError
+genkey_start (GpgmeCtx ctx, int synchronous, const char *parms,
+ GpgmeData pubkey, GpgmeData seckey)
+{
+ GpgmeError err;
+ op_data_t opd;
err = _gpgme_op_reset (ctx, synchronous);
if (err)
- goto leave;
-
- gpgme_data_release (ctx->help_data_1);
- ctx->help_data_1 = NULL;
-
- if ((parms = strstr (parms, "<GnupgKeyParms "))
- && (s = strchr (parms, '>'))
- && (sx = strstr (parms, "format=\"internal\""))
- && sx < s
- && (s2 = strstr (s+1, "</GnupgKeyParms>")))
- {
- /* FIXME: Check that there are no control statements inside. */
- s++; /* Skip '>'. */
- while (*s == '\n')
- s++;
- err = gpgme_data_new_from_mem (&ctx->help_data_1, s, s2-s, 1);
- }
- else
- err = GPGME_Invalid_Value;
+ return err;
+
+ err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &opd,
+ sizeof (*opd), release_op_data);
+ if (err)
+ return err;
+ err = get_key_parameter (parms, &opd->key_parameter);
if (err)
- goto leave;
+ return err;
_gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
- err = _gpgme_engine_op_genkey (ctx->engine, ctx->help_data_1, ctx->use_armor,
- pubkey, seckey);
-
- leave:
- if (err)
- {
- _gpgme_engine_release (ctx->engine);
- ctx->engine = NULL;
- }
- return err;
+ return _gpgme_engine_op_genkey (ctx->engine, opd->key_parameter,
+ ctx->use_armor, pubkey, seckey);
}
-/**
- * gpgme_op_genkey:
- * @c: the context
- * @parms: XML string with the key parameters
- * @pubkey: Returns the public key
- * @seckey: Returns the secret key
- *
- * Generate a new key and store the key in the default keyrings if
- * both @pubkey and @seckey are NULL. If @pubkey and @seckey are
- * given, the newly created key will be returned in these data
- * objects. This function just starts the gheneration and does not
- * wait for completion.
- *
- * Here is an example on how @parms should be formatted; for deatils
- * see the file doc/DETAILS from the GnuPG distribution.
- *
- * <literal>
- * <![CDATA[
- * <GnupgKeyParms format="internal">
- * Key-Type: DSA
- * Key-Length: 1024
- * Subkey-Type: ELG-E
- * Subkey-Length: 1024
- * Name-Real: Joe Tester
- * Name-Comment: with stupid passphrase
- * Name-Email: joe@foo.bar
- * Expire-Date: 0
- * Passphrase: abc
- * </GnupgKeyParms>
- * ]]>
- * </literal>
- *
- * Strings should be given in UTF-8 encoding. The format we support
- * for now is only "internal". The content of the
- * <GnupgKeyParms> container is passed verbatim to GnuPG.
- * Control statements are not allowed.
- *
- * Return value: 0 for success or an error code
- **/
+/* Generate a new keypair and add it to the keyring. PUBKEY and
+ SECKEY should be null for now. PARMS specifies what keys should be
+ generated. */
GpgmeError
gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
GpgmeData pubkey, GpgmeData seckey)
{
- return _gpgme_op_genkey_start (ctx, 0, parms, pubkey, seckey);
+ return genkey_start (ctx, 0, parms, pubkey, seckey);
}
-/**
- * gpgme_op_genkey:
- * @c: the context
- * @parms: XML string with the key parameters
- * @pubkey: Returns the public key
- * @seckey: Returns the secret key
- * @fpr: Returns the fingerprint of the key.
- *
- * Generate a new key and store the key in the default keyrings if both
- * @pubkey and @seckey are NULL. If @pubkey and @seckey are given, the newly
- * created key will be returned in these data objects.
- * See gpgme_op_genkey_start() for a description of @parms.
- *
- * Return value: 0 for success or an error code
- **/
+/* Generate a new keypair and add it to the keyring. PUBKEY and
+ SECKEY should be null for now. PARMS specifies what keys should be
+ generated. */
GpgmeError
-gpgme_op_genkey (GpgmeCtx ctx, const char *parms,
- GpgmeData pubkey, GpgmeData seckey,
- char **fpr)
+gpgme_op_genkey (GpgmeCtx ctx, const char *parms, GpgmeData pubkey,
+ GpgmeData seckey)
{
- GpgmeError err = _gpgme_op_genkey_start (ctx, 1, parms, pubkey, seckey);
+ GpgmeError err;
+
+ err = genkey_start (ctx, 1, parms, pubkey, seckey);
if (!err)
err = _gpgme_wait_one (ctx);
- if (!err && fpr)
- {
- GenKeyResult result;
-
- err = _gpgme_op_data_lookup (ctx, OPDATA_GENKEY, (void **) &result,
- -1, NULL);
- if (err)
- return err;
-
- if (result && result->fpr)
- {
- *fpr = strdup (result->fpr);
- if (!*fpr)
- return GPGME_Out_Of_Core;
- }
- else
- *fpr = NULL;
- }
return err;
}
GpgmeError gpgme_op_export (GpgmeCtx ctx, GpgmeRecipients recp,
GpgmeData keydata);
+\f
+/* Key generation. */
+struct _gpgme_op_genkey_result
+{
+ /* A primary key was generated. */
+ unsigned int primary : 1;
+
+ /* A sub key was generated. */
+ unsigned int sub : 1;
+
+ /* Internal to GPGME, do not use. */
+ unsigned int _unused : 30;
+
+ /* The fingerprint of the generated key. */
+ char *fpr;
+};
+typedef struct _gpgme_op_genkey_result *GpgmeGenKeyResult;
+
/* Generate a new keypair and add it to the keyring. PUBKEY and
SECKEY should be null for now. PARMS specifies what keys should be
- generated. On success, if *FPR is non-null, it contains a
- malloc()'ed string with the fingerprint of the generated key on
- success. */
+ generated. */
GpgmeError gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
GpgmeData pubkey, GpgmeData seckey);
GpgmeError gpgme_op_genkey (GpgmeCtx ctx, const char *parms,
- GpgmeData pubkey, GpgmeData seckey,
- char **fpr);
+ GpgmeData pubkey, GpgmeData seckey);
+/* Retrieve a pointer to the result of the genkey operation. */
+GpgmeGenKeyResult gpgme_op_genkey_result (GpgmeCtx ctx);
+
+\f
/* Delete KEY from the keyring. If ALLOW_SECRET is non-zero, secret
keys are also deleted. */
GpgmeError gpgme_op_delete_start (GpgmeCtx ctx, const GpgmeKey key,
+2003-04-24 Marcus Brinkmann <marcus@g10code.de>
+
+ * gpg/t-genkey.c: Rewritten to match new semantics.
+
2003-02-06 Marcus Brinkmann <marcus@g10code.de>
* gpg/t-decrypt.c (passphrase_cb): Fix to new prototype.
/* t-genkey.c - regression test
- * Copyright (C) 2000 Werner Koch (dd9jn)
- * Copyright (C) 2001 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 General Public License as published by
- * the Free Software Foundation; either version 2 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
+ Copyright (C) 2000 Werner Koch (dd9jn)
+ Copyright (C) 2001, 2003 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 General Public License as published by
+ the Free Software Foundation; either version 2 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GPGME; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <assert.h>
#include <gpgme.h>
-#define fail_if_err(a) do { if(a) { \
- fprintf (stderr, "%s:%d: GpgmeError %s\n", \
- __FILE__, __LINE__, gpgme_strerror(a)); \
- exit (1); } \
- } while(0)
+#define fail_if_err(err) \
+ do \
+ { \
+ if (err) \
+ { \
+ fprintf (stderr, "%s:%d: GpgmeError %s\n", \
+ __FILE__, __LINE__, gpgme_strerror (err)); \
+ exit (1); \
+ } \
+ } \
+ while (0)
+/* True if progress function printed something on the screen. */
+int progress_called;
static void
-progress ( void *self, const char *what, int type, int current, int total)
+progress (void *self, const char *what, int type, int current, int total)
{
- fprintf (stderr, "progress `%s' %d %d %d\n", what, type, current, total);
+ if (!strcmp (what, "primegen") && !current && !total
+ && (type == '.' || type == '+' || type == '!'
+ || type == '^' || type == '<' || type == '>'))
+ {
+ printf ("%c", type);
+ fflush (stdout);
+ progress_called = 1;
+ }
+ else
+ {
+ fprintf (stderr, "unknown progress `%s' %d %d %d\n", what, type,
+ current, total);
+ exit (1);
+ }
}
int
-main (int argc, char **argv )
+main (int argc, char **argv)
{
- GpgmeCtx ctx;
- GpgmeError err;
- const char *format;
- char *parms;
- int count = 0;
-
- do {
- err = gpgme_new (&ctx);
- fail_if_err (err);
+ GpgmeCtx ctx;
+ GpgmeError err;
+ const char *parms = "<GnupgKeyParms format=\"internal\">\n"
+ "Key-Type: DSA\n"
+ "Key-Length: 1024\n"
+ "Subkey-Type: ELG-E\n"
+ "Subkey-Length: 1024\n"
+ "Name-Real: Joe Tester\n"
+ "Name-Comment: (pp=abc)\n"
+ "Name-Email: joe@foo.bar\n"
+ "Expire-Date: 0\n"
+ "Passphrase: abc\n"
+ "</GnupgKeyParms>\n";
+ GpgmeGenKeyResult result;
- gpgme_set_progress_cb (ctx, progress, NULL);
+ err = gpgme_new (&ctx);
+ fail_if_err (err);
- format = "<GnupgKeyParms format=\"internal\">\n"
- "Key-Type: DSA\n"
- "Key-Length: 1024\n"
- "Subkey-Type: ELG-E\n"
- "Subkey-Length: 1024\n"
- "Name-Real: Joe Tester\n"
- "Name-Comment: (pp=abc,try=%d)\n"
- "Name-Email: joe@foo.bar\n"
- "Expire-Date: 0\n"
- "Passphrase: abc\n"
- "</GnupgKeyParms>\n";
- parms = malloc ( strlen (format) + 1 + 20 );
- if (!parms)
- exit (8);
- sprintf (parms, format, ++count );
- err = gpgme_op_genkey (ctx, parms, NULL, NULL, NULL);
- fail_if_err (err);
- free (parms);
-
- gpgme_release (ctx);
- } while ( argc > 1 && !strcmp( argv[1], "--loop" ) );
-
- return 0;
-}
+ gpgme_set_progress_cb (ctx, progress, NULL);
+
+ err = gpgme_op_genkey (ctx, parms, NULL, NULL);
+ fail_if_err (err);
+ result = gpgme_op_genkey_result (ctx);
+ if (!result)
+ {
+ fprintf (stderr, "%s:%d: gpgme_op_genkey_result returns NULL\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+ if (progress_called)
+ printf ("\n");
+ printf ("Generated key: %s (%s)\n", result->fpr ? result->fpr : "none",
+ result->primary ? (result->sub ? "primary, sub" : "primary")
+ : (result->sub ? "sub" : "none"));
+ if (strlen (result->fpr) != 40)
+ {
+ fprintf (stderr, "%s:%d: generated key has unexpected fingerprint\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+ if (!result->primary)
+ {
+ fprintf (stderr, "%s:%d: primary key was not generated\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+ if (!result->sub)
+ {
+ fprintf (stderr, "%s:%d: sub key was not generated\n",
+ __FILE__, __LINE__);
+ exit (1);
+ }
+ gpgme_release (ctx);
+ return 0;
+}