2001-11-21 Marcus Brinkmann <marcus@g10code.de>
[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   int i;
113   const char *s, *s2, *sx;
114
115   fail_on_pending_request (ctx);
116   ctx->pending = 1;
117
118   gpgme_data_release (ctx->help_data_1);
119   ctx->help_data_1 = NULL;
120
121   _gpgme_engine_release (ctx->engine);
122   ctx->engine = NULL;
123   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
124                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
125   if (err)
126     goto leave;
127
128   /* We need a special mechanism to get the fd of a pipe here, so
129    * that we can use this for the %pubring and %secring parameters.
130    * We don't have this yet, so we implement only the adding to the
131    * standard keyrings */
132   if (pubkey || seckey)
133     {
134       err = mk_error (Not_Implemented);
135       goto leave;
136     }
137
138   if (!pubkey && !seckey)
139     ; /* okay: Add key to the keyrings */
140   else if (!pubkey || gpgme_data_get_type (pubkey) != GPGME_DATA_TYPE_NONE)
141     {
142       err = mk_error (Invalid_Value);
143       goto leave;
144     }
145   else if (!seckey || gpgme_data_get_type (seckey) != GPGME_DATA_TYPE_NONE)
146     {
147       err = mk_error (Invalid_Value);
148       goto leave;
149     }
150     
151   if (pubkey)
152     {
153       _gpgme_data_set_mode (pubkey, GPGME_DATA_MODE_IN);
154       _gpgme_data_set_mode (seckey, GPGME_DATA_MODE_IN);
155       /* FIXME: Need some more things here.  */
156     }
157
158   if ((parms = strstr (parms, "<GnupgKeyParms ")) 
159       && (s = strchr (parms, '>'))
160       && (sx = strstr (parms, "format=\"internal\""))
161       && sx < s
162       && (s2 = strstr (s+1, "</GnupgKeyParms>")))
163     {
164       /* FIXME: Check that there are no control statements inside.  */
165       err = gpgme_data_new_from_mem (&ctx->help_data_1, s+1, s2-s-1, 1);
166     }
167   else 
168     err = mk_error (Invalid_Value);
169
170   if (err)
171     goto leave;
172     
173   _gpgme_data_set_mode (ctx->help_data_1, GPGME_DATA_MODE_OUT);
174
175   _gpgme_engine_set_status_handler (ctx->engine, genkey_status_handler, ctx);
176   _gpgme_engine_set_verbosity (ctx->engine, ctx->verbosity);
177
178   err = _gpgme_engine_op_genkey (ctx->engine, ctx->help_data_1, ctx->use_armor);
179
180   if (!err)
181     err = _gpgme_engine_start (ctx->engine, ctx);
182
183  leave:
184   if (err)
185     {
186       ctx->pending = 0; 
187       _gpgme_engine_release (ctx->engine);
188       ctx->engine = NULL;
189     }
190   return err;
191 }
192
193 /**
194  * gpgme_op_genkey:
195  * @c: the context
196  * @parms: XML string with the key parameters
197  * @pubkey: Returns the public key
198  * @seckey: Returns the secret key
199  * 
200  * Generate a new key and store the key in the default keyrings if both
201  * @pubkey and @seckey are NULL.  If @pubkey and @seckey are given, the newly
202  * created key will be returned in these data objects.
203  * See gpgme_op_genkey_start() for a description of @parms.
204  * 
205  * Return value: 0 for success or an error code
206  **/
207 GpgmeError
208 gpgme_op_genkey( GpgmeCtx c, const char *parms,
209                  GpgmeData pubkey, GpgmeData seckey )
210 {
211     int rc = gpgme_op_genkey_start ( c, parms, pubkey, seckey );
212     if ( !rc ) {
213         gpgme_wait (c, 1);
214         c->pending = 0;
215     }
216     return rc;
217 }
218
219
220
221
222