be52056d276a4254a166524a6078304dac6944d6
[gpgme.git] / gpgme / genkey.c
1 /* genkey.c -  key generation
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GPGME is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32 static void
33 genkey_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
34 {
35     if ( code == STATUS_PROGRESS && *args ) {
36         if (ctx->progress_cb) {
37             char *p;
38             int type=0, current=0, total=0;
39             
40             if ( (p = strchr (args, ' ')) ) {
41                 *p++ = 0;
42                 if (*p) {
43                     type = *(byte*)p;
44                     if ( (p = strchr (p+1, ' ')) ) {
45                         *p++ = 0;
46                         if (*p) {
47                             current = atoi (p);
48                             if ( (p = strchr (p+1, ' ')) ) {
49                                 *p++ = 0;
50                                 total = atoi (p);
51                             }
52                         }
53                     }
54                 }
55             }           
56             if ( type != 'X' )
57                 ctx->progress_cb ( ctx->progress_cb_value, args, type,
58                                    current, total );
59         }
60         return;
61     }
62
63     DEBUG2 ("genkey_status: code=%d args=`%s'\n", code, args );
64     /* FIXME: Need to do more */
65 }
66
67
68 /**
69  * gpgme_op_genkey:
70  * @c: the context
71  * @parms: XML string with the key parameters
72  * @pubkey: Returns the public key
73  * @seckey: Returns the secret key
74  * 
75  * Generate a new key and store the key in the default keyrings if
76  * both @pubkey and @seckey are NULL.  If @pubkey and @seckey are
77  * given, the newly created key will be returned in these data
78  * objects.  This function just starts the gheneration and does not
79  * wait for completion.
80  *
81  * Here is an example on how @parms should be formatted; for deatils
82  * see the file doc/DETAILS from the GnuPG distribution.
83  *
84  * <literal>
85  * <![CDATA[
86  * <GnupgKeyParms format="internal">
87  * Key-Type: DSA
88  * Key-Length: 1024
89  * Subkey-Type: ELG-E
90  * Subkey-Length: 1024
91  * Name-Real: Joe Tester
92  * Name-Comment: with stupid passphrase
93  * Name-Email: joe@foo.bar
94  * Expire-Date: 0
95  * Passphrase: abc
96  * </GnupgKeyParms>
97  * ]]>
98  * </literal> 
99  *
100  * Strings should be given in UTF-8 encoding.  The format we support
101  * for now is only "internal".  The content of the
102  * &lt;GnupgKeyParms&gt; container is passed verbatim to GnuPG.
103  * Control statements are not allowed.
104  * 
105  * Return value: 0 for success or an error code
106  **/
107 GpgmeError
108 gpgme_op_genkey_start (GpgmeCtx ctx, const char *parms,
109                        GpgmeData pubkey, GpgmeData seckey)
110 {
111   int err = 0;
112   const char *s, *s2, *sx;
113
114   fail_on_pending_request (ctx);
115   ctx->pending = 1;
116
117   gpgme_data_release (ctx->help_data_1);
118   ctx->help_data_1 = NULL;
119
120   _gpgme_engine_release (ctx->engine);
121   ctx->engine = NULL;
122   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
123                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
124   if (err)
125     goto leave;
126
127   /* We need a special mechanism to get the fd of a pipe here, so
128    * that we can use this for the %pubring and %secring parameters.
129    * We don't have this yet, so we implement only the adding to the
130    * standard keyrings */
131   if (pubkey || seckey)
132     {
133       err = mk_error (Not_Implemented);
134       goto leave;
135     }
136
137   if (!pubkey && !seckey)
138     ; /* okay: Add key to the keyrings */
139   else if (!pubkey || gpgme_data_get_type (pubkey) != GPGME_DATA_TYPE_NONE)
140     {
141       err = mk_error (Invalid_Value);
142       goto leave;
143     }
144   else if (!seckey || gpgme_data_get_type (seckey) != GPGME_DATA_TYPE_NONE)
145     {
146       err = mk_error (Invalid_Value);
147       goto leave;
148     }
149     
150   if (pubkey)
151     {
152       _gpgme_data_set_mode (pubkey, GPGME_DATA_MODE_IN);
153       _gpgme_data_set_mode (seckey, GPGME_DATA_MODE_IN);
154       /* FIXME: Need some more things here.  */
155     }
156
157   if ((parms = strstr (parms, "<GnupgKeyParms ")) 
158       && (s = strchr (parms, '>'))
159       && (sx = strstr (parms, "format=\"internal\""))
160       && sx < s
161       && (s2 = strstr (s+1, "</GnupgKeyParms>")))
162     {
163       /* FIXME: Check that there are no control statements inside.  */
164       err = gpgme_data_new_from_mem (&ctx->help_data_1, s+1, s2-s-1, 1);
165     }
166   else 
167     err = mk_error (Invalid_Value);
168
169   if (err)
170     goto leave;
171     
172   _gpgme_data_set_mode (ctx->help_data_1, GPGME_DATA_MODE_OUT);
173
174   _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
175   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
176
177   err = _gpgme_engine_op_genkey (ctx->engine, ctx->help_data_1, ctx->use_armor);
178
179   if (!err)
180     err = _gpgme_engine_start (ctx->engine, ctx);
181
182  leave:
183   if (err)
184     {
185       ctx->pending = 0; 
186       _gpgme_engine_release (ctx->engine);
187       ctx->engine = NULL;
188     }
189   return err;
190 }
191
192 /**
193  * gpgme_op_genkey:
194  * @c: the context
195  * @parms: XML string with the key parameters
196  * @pubkey: Returns the public key
197  * @seckey: Returns the secret key
198  * 
199  * Generate a new key and store the key in the default keyrings if both
200  * @pubkey and @seckey are NULL.  If @pubkey and @seckey are given, the newly
201  * created key will be returned in these data objects.
202  * See gpgme_op_genkey_start() for a description of @parms.
203  * 
204  * Return value: 0 for success or an error code
205  **/
206 GpgmeError
207 gpgme_op_genkey (GpgmeCtx ctx, const char *parms,
208                  GpgmeData pubkey, GpgmeData seckey)
209 {
210   GpgmeError err = gpgme_op_genkey_start (ctx, parms, pubkey, seckey);
211   if (!err)
212     gpgme_wait (ctx, 1);
213   return err;
214 }
215
216
217
218
219